Bulma

介紹與教學

跟 Bootstrap 的差異與比較:https://bulma.io/alternative-to-bootstrap/

Django 生態圈已經有人寫 app 了 – django-bulma,支援 template 以及 form ,包的挺完整的。

AWS SES SMTP

前兩周碰到 GMAIL 很 GY 的問題,想說要不要去申請 MailGun ,後來想說,要另外申請服務挺麻煩(畢竟不是自家用),AWS 應該有這類服務吧。去 Google 以後,才發現自己之前有用過,只是全都忘光光了,這次要紀錄下來。這次的紀錄重點:

  1. 簡介
  2. 需要什麼?
  3. 如何移出 Sandbox?

AWS SES 是 AWS 的大規模電子郵件解決方案,可以用來寄發大量的電子郵件。他除了有提供 SMTP 設定之外,也可以直接使用程式來寄送。用 SMTP 設定方便的地方在於各個語言都有 SMTP 的函式庫可以用,所以設定填一填就可以寄了,不用額外再加函式庫。

要申請這個服務,要預先準備好網域,因為他是以網域為基礎。首先要新增網域,在進行新增網域的步驟時,步驟的說明會詳列出你該怎麼做來進行後續的驗證。這部份蠻簡單的,就只是去新增一個網域記錄,然後把 AWS 要求你填的資訊放進去就可以了。

在新增網域並進行驗證以後,就可以使用 SES SMTP 或是用程式去寄了。只是這時候是在 Sandbox 裡,有限制在的,不能寄太多信,寄件者跟收件者也都有限制。AWS Management console 也會提醒你,現在還在 Sandbox,如果需要提升額度或是可以寄送到外面,必須要提出申請 (有連結可以按),這邊就是照網頁說明去提出申請即可。提出申請時,AWS 會要求你回答幾個問題。這幾個問題主要是要確保 AWS 自身的立場,也就是當有人回報信件被濫用或退信時(抱怨),該怎麼去處理。

AWS 建議的作法就是要求你使用 AWS SNS ,當有退信或是抱怨時,讓 AWS 可以透過 AWS SNS 去通知你。AWS SNS 可以用郵件通知或是用 HTTP/HTTPS 去通知你的網站進行自動處理等等的。我後來是簡單的設定 AWS SNS,用郵件來通知我,等以後再來改成讓網站自動處理。

參考資料(來自AWS 文件):

NgRx

因為 NgRx 是用 Redux 的概念,所以先看 Redux

看完大致可以理解,就是 design pattern 裡講的 state pattern。大部份 Redux 例子都是搭配 React,看的還是霧煞煞,所以找 NgRx 搭配 Angular 的例子來看。

我覺得這三篇的例子蠻清楚的,很容易可以了解現有的 angular 碰到 ngrx 時,要怎麼結合。

原本 angular 的一個頁面是 component html 跟 component code ,現在加上 ngrx 以後,會使用 store 儲存狀態,寫 reducer 來處理狀態。當有事件觸發時,就使用 store.dispatch 去發送 action,reducer 在收到以後,會依據 action 來處理狀態,然後回傳狀態。這時候頁面會因為 binding ,而反映出新的狀態結果。

這三篇雖然清楚,但已經舊了,我在試驗時,就碰到兩個問題:

  1. 找不到 StoreModule.provideStore() 這個方法,這個已經改為 StoreModule.forRoot()
  2. Observable 找不到,要解決這個問題,除了得裝 rxjs 之外,還要裝 rxjs-compat 讓 rxjs 向前相容。

文章有提到 Redux DevTools 這個工具,可以從 Firefox addons/Chrome store NgRx 安裝,安裝以後,專案程式那邊也需要調整。調整的部份可以參考 @ngrx/store-devtools ,安裝好,修改 app.module.ts 之後,就可以使用了。使用的方式是先開啟專案的網址,然後再開 developer tools,這時會看到有個 Redux 分頁,試著觸發一些事件看看,這邊就會出現發送的 action 以及改變前後的狀態了。

CSRF is dead?

前幾天在 Hacker news 上看到 Scott Helme 寫的這篇 CSRF is (really) dead ,一直沒看。這兩天開始看,一開始 Scott Helme 先提,你應該先看這篇 Cross-Site Request Forgery is dead! ,再回頭來看。


我先看了第一段,心裡納悶這樣怎麼會有什麼危險呢?後來找了另外兩篇中文來看 (加快理解):

我蠻推第一篇 Huli 寫的文章,寫的很清楚。簡單的說,就是利用 cookie ,當別的網頁裡有嵌入對其他網頁的存取時,會因為 cookie 的關係而有存取權,如果網站沒有做適當的檢查,那麼使用者的資料就有可能遭到竊取或被錯誤的存取。這也是為什麼後來幾乎每套 web framework 都會有 CSRF token 的處理。

回頭來講,Scott Helme 會說 CSRF 死的原因很簡單,就是有了 SameSite cookie,在 2019 年6月以後幾乎各家都支援 SameSite cookie 了 – Can I use samesite cookie? 所以現在只要在 Set-Cookie 時,後面多加 SameSite=Strict 或 SameSite=Lax 就可以避免 CSRF 的風險了。

等到真正普及可能還要一到兩年的時間吧。

AWS S3/Glacier select

前幾天看 S3/Glacier FAQ 時,看到有 SELECT 這個功能,是去年推出的。S3/Glacier select  這功能是這樣子,你可以把 CSV/JSON/Apache Parquet 這幾種格式的檔案放到 S3/Glacier 上,然後就可以使用類似 SQL 的敘述來查詢檔案內容。

所以我們可以把不常使用的資料從資料庫移轉到 S3/Glacier 上,需要時,再使用 S3 SELECT 來查詢。這樣資料庫不需要一直擴充容量,放到 S3/Glacier 可以降低資料庫儲存的成本。

使用範例:

不過,網路上能找到的範例多半都是使用 CSV,那使用 JSON 又是如何呢?我試了以後,發現這個 JSON 格式不是我在 Python 用 json.dump() 傾印出來就搞定的。資料是陣列時,要針對每個元素去 dump,不可以是 [{}, {},…] 這樣,必須是 {} {} {} 這樣子,AWS API 才不會報錯 (參考:stackoverflow – amazon s3 – s3-select querying data on field name)。

import json

with open('output.json', 'wt') as fout:
  for obj in objs:
    json.dump(obj, fout, indent=2, ensure_ascii=True)
# 輸出結果
"""
{
  "id": 13930241}{
  "id": 13930240}
"""

vim – 查按鍵定義

Embed from Getty Images

雖說常用 vim,但是我幾乎是沒什麼在定義按鍵,都是沿用 plugin 的定義,所以用了一堆 plugin 之後,難免會遇到衝突的情況。

那麼要怎麼查按鍵的定義呢?除了可以用 grep/ag 來找 vimrc/plugin 裡的定義之外,也可以在執行 vim 以後,用 :verbose map 來查

" 我的 leader key 是 \
" 以下就是查 \gg 會執行的指令
:verbose map <leader>gg

步驟:

  1. 先按冒號 ‘:’ ,游標會移到下方,進入 last line mode
  2. 在下方輸入 verbose map <leader>gg
  3. 輸入完按 Enter,就會看到 vim 印出按鍵的定義與上次定義的位置
  4. 再按一次 Enter,就會關閉回到 Normal mode

印出的結果 (會因為你的按鍵定義而異)

n  \gg         * :EXGSearchCWordW
        上次設定: ~/exvim/vimfiles/bundle/ex-utility/autoload/ex/keymap.vim line 37

算IOPS

上個月公司 AWS 帳單來時,看到 EBS 使用率提高,所以費用增加不少

剛剛去算了一下目前的 IOPS ,然後套到 aws 計算機去算。

先用 AWS CloudWatch 去指定要看的 EBS volume 、指標(VolumeReadOps/VolumeWriteOps)以及日期區間,把統計方式改為總和,然後用最高點的數值套這公式: (VolumeReadOps + VolumeWriteOps) / 區間的秒數,算出目前用的 IOPS 是 106 左右。

計算方式是參考這兩個連結:

然後到 AWS 計算機網頁,目前 EBS volume type 是 magnetic(standard),storage  250 G,IOPS 填入 106,算出金額約 39.79,接著將 Volume type 改為 gp2,金額變成 26.40。

所以選擇適當的 EBS volume type 是有助於省錢的。

jemalloc

jemalloc (github) 是效能聽說很好的 malloc library。

之前是在 為線上環境而最佳化的 Ruby:Fullstaq Ruby 看到的,看到的當下是想說,會不會也有人來編譯用 jemalloc 的 Python 版本,不過很遺憾的是沒有。後來找了 jemalloc 的資料以後,發現要替換其實不難。Ubuntu 14.04 是已經有包 libjemalloc 了,但版本較舊,是 3.5.1 版。

後來還是選擇自行編譯,然後使用 LD_PRELOAD 環境變數來替換 python 的 malloc library。

那要怎麼檢查 python 是不是真的有使用到呢?這可以使用 lsof 來檢查。(How to see the currently loaded shared objects in Linux?)

lsof /usr/local/lib/libjemalloc.so.2

同款的還有 tcmalloc (Google 出的),有空也來測試看看。

P.S. ptmalloc 是 glibc 的 malloc。

Linux 裡也能用 MacOSX

之前是知道 VirtualBox 可以執行 MacOSX,但我一直沒試過。前幾天,在 Twitter 上看到這個專案:https://github.com/foxlet/macOS-Simple-KVM/ ,說可以用 Linux 的 KVM 來執行 MacOSX。

今天來試試看,基本上不用做太多修改,就可以順利開機起來。
這邊紀錄一下幾件遇到的情況:

  1. 不需要額外設定 Bridged network:原本以為網路需要用 Bridged,結果照著網站上的說明去設定,反而網路有問題,這會導致安裝程序無法進行。
  2. Disk utility:到安裝程式時,先選 Disk utility 去初始化之前用 qemu-img 所建立的磁碟,後續才選 Reinstall 那個項目。
  3. 安裝以後的重開機:安裝以後重開機,不要再選到安裝,要注意看一下,選到從 SystemDisk 開機那個項目 (從右邊數過來第二個)
  4. virt-manager:可以安裝 virt-manager ,會有個類似 virtualbox 的管理工具 (就只是類似,不代表一模一樣)。這邊有幾件事情要做:
    1. 安裝:sudo apt-get install virt-manager
    2. 加入 kvm 群組:sudo usermod -a -G libvirt,kvm <your_username> ,做完這步要重新開機,virt-manager 才能順利連接 QEMU/KVM。
    3. virt-manager 是在系統工具裡,中文名字是虛擬機管理員。
    4. 使用 ./make.sh –add 將機器組態匯入以後,如果有遇到不能開機的情況,可以參考這個 pull request,使用這個指令 qemu-system-x86_64 –machine help | grep q35 | cut -d” ” -f1 | egrep -oe “.*-[0-9.]+” | sort -rV | head -1 取得 machine type,修改 template.xml 以後,再用 sudo virsh define ./template.xml 去更新機器組態。
    5. 要用虛擬機管理員自行新增硬碟。

安裝以後的設定:

  1. 輸入法:不使用 CapsLock 切換輸入法,改用 ctrl-space 來切換的話,第一步是在系統偏好設定 > 鍵盤 > 輸入方式那邊,將「使用大寫鎖定鍵來切換…」的那個勾選給取消掉。然後到系統偏好設定 > 鍵盤 > 快捷鍵那邊,在左邊找到輸入方式,將右邊的兩個項目給勾選起來,這樣就可以用 ctrl+space 來切換輸入法了,長按住 ctrl,再按 space 則是切換輸入法。
  2. homebrew:就是安裝常看到的 brew 指令。

MySQL 到底有沒有 case sensitive ?

公司的程式有人回報說,在搜尋電子郵件時,沒有區分大小寫 (case insensitive),我心裡想,雖然電子郵件並沒有嚴格區分大小寫,但我應該沒有特別做這件事,照理說,是要有區分大小寫才是,於是我開始看程式碼去找是不是 Django 等框架/函式庫自動加上了。

不過我找了好一陣子都沒找到,看來應該不是程式的問題。既然不是程式問題,那就可能是資料庫問題了,我在開發環境的 SQLite 裡用 SELECT SQL 查詢,有區分大小寫;生產環境是用 MySQL,我改在 MySQL shell 用 SELECT SQL 來查詢。結果,真的是資料庫設定問題,上網搜尋,才確定真的是 MySQL 問題:

簡單的說,是 collation 問題,所以解決方法也算是簡單,一個方法是改變 collation,看是要資料庫整個改,還是個別 table/column 去改;一個方法則是改 column data type。

MySQL 手冊對 collation 的說明是這樣的 (連結),只要後綴是 _cs 的或是 _bin 的,都是 case-sensitive 的。改 collation ,可以先使用 SHOW COLLATION WHERE COLLATION LIKE “%_cs” 來找,但 utf8 是沒有後綴名為 _cs 的 collation,只能使用 utf8_bin 。找到合適的 collation 後,要改指定 column data type ,可以使用 ALTER TABLE documents__document CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;

以 Django 來說,當然最好是一開始在建立資料庫時,就指定好 charset 跟 collation,之後的作法就是自己寫 Migration 執行自訂的 SQL 來變更指定欄位的 data type 了。