2010年12月22日 星期三

Scale out, HA, backup

Scale out、high availability、backup 三者是不同的事, 之前對這幾個詞很陌生, 備忘一下它們的差別。
  • Replication 可以同時 scale out 讀取的操作和當作讀取的 HA, 但不是 backup。舉例來說, 不小心刪錯資料, slave 上的資料也一起飛了。所以 backup 要另外做。
  • Replication 無法保證寫入的 HA, 因為 master 和 slave 之間會因延遲同步而少資料。
  • 針對寫入操作的 HA, DRBD 看起來是最穩且易於實作的 方案。但 DRBD 沒有附帶 scale out, 備份機就是待機狀態。
  • MMM 可用作寫入的 HA, 備份機可充當讀取的 replication。
  • Sharding (partition) 用來 scale out 寫入的操作, 沒包含 HA。
結論是 backup 要分開規劃, scale out 和 HA 也要分開規劃。寫入量不大的話, 可以先用 replication 擋著。反之, 要用 sharding 來 scale out, 用 DRBD 或 MMM 做 HA。

順便記一下 backup 的心得:
  • Backup 分為 raw backup 和 logical backup, 各有利弊。若 file system 有支援 snapshot, 在 slave 上做 raw backup, 不管是執行時間還是占用的空間, 都挺划算的。切記要搭配 crash-safe 的方案, 如 MySQL + InnoDB。
  • 針對 InnoDB 做 logical backup 的話, 用 XtraBackup 較快。
  • 一定要測 restore, 我半信半疑的測了一下, 馬上發現少備份使用者帳號的 DB ......
大概有個概念了, 接下來先做 replication 和 backup, 將 DB 操作包在自己寫的 lib 裡, 待需要 scale out 時比較好套。之後有更深的需求再來細讀吧。

參考資料

2010年12月16日 星期四

varchar 與 text 的效能差異, 以及 order by 的運算方式

今天和同事 S 說明 MEMORY engine 512 bytes 限制時, 被問到用 varchar 超過 512 bytes 的話, 和 text 有何差別。想了一會兒才想到使用 text 會讓 mysql 用比較慢的方式排序, 在這裡小記一下。

在官網 7.3.1.11. ORDER BY Optimization 裡寫得很清楚, 使用 order by 或 group by 時, MySQL 可能會用到 filesort (可用 explain 看 extra 欄位確認)。filesort 有兩種版本:
  • original filesort: 取出符合條件的 rows, 只留 order by 裡的欄位和 row position。排好後再回頭一個個依 row position 取回需要的欄位。換句話說, 會從硬碟讀兩次同樣的資料。
  • modified filesort: 取出符合條件的 rows, 將需要的欄位和 order by 裡的欄位一起排。只會從硬碟讀一次資料。
    舉例來說, 若是 select a from table order by b:
    • original filesort: 先用 b 排序, 再依排好的結果取出各 row 的 a, 所以會有一堆 random access。
    • modified filesort: 排序 (b, a ), 排好後就是最後結果。
      mysql 會盡量用 modified filesort, 以減少重覆讀硬碟 (更何況第二次還是 random access。) 但發生以下其中一個情況, mysql 會選用 original filesort:
      • 用到 text 或 blob 時。
      • 單筆資料 (即上面範例的 (b, a)) 超過 max_length_for_sort_data, 單位為 bytes。
      除了避免使用第一種的 filesort, 說明文件最後有提供幾個最佳化的作法, 可以調一些參數。

      2010-12-16 更新

      original filesort 不見得會比 modified filesort 慢, 今天就踏到雷, 調大 max_length_for_sort_data 讓 mysql 使用 modified filesort 反而慢兩倍多, 原因如文件上所言, 單一 row 變大, buffer 能放 row 的數量變少, 增加排序的次數 (show status like 'Sort_merge_passes')。用 profiling 看則發現 Sorting result 的執行時間變長。

      由於我用來排序的欄位就超過 512 bytes, 一定得將暫存 table 寫到硬碟。順便試了用 ram disk 上的 tmpdir, 結果的確省了一半多的時間, 原以為會會瞬殺的說。

      另外 How fast can you sort data with MySQL ? 和 Impact of the sort buffer size in MySQL 指出 sort_buffer_size 不是愈大愈好, 使用時記得測看看。結論是, 無論如何, benchmark 和 profiling 都是必要的。



      2010年12月11日 星期六

      javascript non-blocking download 的原理

      試了 head.js 的測試頁, 覺得很有意思, 為啥用 head.js 可以快這麼多, 就去看了 head.js 的原始碼, 看起來是 scriptTag 這個函式負責載入檔案。但是我不明白為何這樣可以加快載入速度, 畢竟瀏覽器的連線數量沒變, 為何用同樣的瀏覽器 (我用 Chrome 試的), 速度卻差這麼多。

      在網路上查了一陣子, 看到 jnlin 寫的《Head JS : The only script in your HEAD》, 得知關鍵在於瀏覽器如何處理 tag <script>, 接著就查到這篇: 《What is a non-blocking script?》, 才明白前因後果。

      摘要如下:
      • 只有一個 thread 在執行 javascript。這意味著 UI rendering 和其它 js 操作都是同一個 thread 負責的。 
      • 載入 script tag 時, 瀏覽器怕 script 裡有 js code 會改變 UI, 所以會等 script 載入完並執行完才繼續 rendering。
      • 相對來說, 下載 javascript 檔比執行 javascript 慢得多。若寫程式的人知道這段 script 不會影響之後的 rendering, 有機會將下載的時間切開, 省去下載時間。
      • 做法有兩種: 第一種是動態地增加 script tag, 於是在讀入網頁時, rendering 不會被 script tag 卡住。第二種是用 HTML5 的語法 async, 目前只有 Firefox 3.6 有支援。
      結論是 javascript 是單 thread, 無法平行化執行, 但可以平行下載檔案 (視最大連線數)。並且有機制讓下載檔案不會擋住網頁 rendering, 但程式設計師得自己處理 javascript 相依性 (執行順序)。head.js 提供了不錯的介面解決這問題, 不過也有些小細節要程式設計師自行處理。head.js 的相關說明見附錄, 我有興趣的是為啥它可以加快網頁載入速度 (實際上只有 rendering 完主頁的速度, 不是整體時間)。
      head.js 的說明:
      另外這裡有各家瀏覽器支援網路連線的情況, 滑鼠移到各分欄上會有說明, 可以得知一些細節。HTTP 1.1 規定同一網域最多兩個連線, 結果只有 IE6 遵守, 還被記為缺點......。

      2010年12月10日 星期五

      刪除大量檔案的方法

      當一個目錄內有上百萬、千萬個檔案時, rm -rf 會慢到很糟糕的地步, 而且砍檔案時會吃掉一堆 IO, 做其它事只要一開檔、關檔, 就會頓一下。

      上網查了各種說法, 要驗證何者的說法最合理, 需要讀 rm 的原始碼和 benchmark, 所以就不提了。有人提到一次 rm 多個檔案會比每個檔案都執行一次 rm 快, 減少 fork 和 execute 的時間, 這到是很合理。不確定在要刪除目錄的情況下, rm -rf DIR 和批次砍掉 DIR 下的檔案, 何者較快。

      後來發現以前寫的 《/bin/rm: argument list too long 的解法和原因》 滿有用的, 我可以用 find + xargs 只砍部份檔案, 分多次砍完。這個作法的另一好處是, 可以在沒人用的時候放著讓它砍部份檔案 (像是先砍 a*, 再砍 b*, ...), 方便分階段處理, 只要每次砍檔案的時間不長, 不會和人使用的時間重疊到, 就沒問題了。

      2010年12月9日 星期四

      自動防護惡意 ssh / apache2 連線的方法

      備忘一下, 有空再來試。

      通用軟體
      • ban2fail
      apache2
      • mod_evasive
      • mod_security (Debian / Ubuntu 似乎因 license 的原因, 沒有內建 package)
      ssh
      • sshguard
      • denyhost
      Btw, 一但找到一個相關的軟體名稱後, 用它到 stackoverflow.com 裡搜, 就會找到不少相關軟體。利用比較性質的文章來找相關套件, 似乎是還不錯的作法。

      2010年12月5日 星期日

      atime, noatime 和 relatime

      摘要讀這篇 Difference between noatime and relatime mount options 的心得:

      • atime: 會記錄最後讀取時間, 換句話說, 即使只讀資料, 也會寫入硬碟。
      • noatime: 別記錄讀取時間, 會造成部份程式失常。比方說郵件閱讀軟體得比對最後讀取和更改時間, 若前者比後者小, 表示還有信件未讀。
      • relatime: 只有當最後讀取時間比最後更改時間早的時候, 才記錄最後讀取時間。這解決郵件軟體的需求。
      結論: 用 relatime 安全又可提昇效能。不過我看 Ubuntu 8.04 灌好的時候就已設 relatime 了, 所以沒啥要改的。

      2010年12月2日 星期四

      更改 mysql conf 的注意事項

      mysql 的設定檔有太多讀入的位置, google 一下 "mysql default config path" 會看到一堆文章, 由此可見這問題多令人困擾。

      《High Performance MySQL 2e》提供一個不錯的找法:
      $ /usr/sbin/mysqld --verbose --help | grep -A 1 'Default options'
      
      我在 Ubuntu 8.04 上的輸出結果如下:
      Default options are read from the following files in the given order:
      /etc/mysql/my.cnf ~/.my.cnf /usr/etc/my.cnf
      
      另外要注意 App Armor 是否允許 mysql 讀它的設定檔。我參考書上的建議, 另外開一個 repository, 將系統相關設定檔放到 repository 裡, 再用 soft link 指回去 (例如: ln -s my-repository/mysql /etc/mysql)。結果啟動 mysql 後, 設定檔毫無作用, 也沒看到任何錯誤訊息。

      更改 /etc/apparmor.d/usr.sbin.mysqld 讓 mysql 可以讀設定檔的實體位置後, 就解決這問題了。

      在 Fedora 下裝 id-utils

      Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...