星期日, 12月 28, 2008

Smokeping 啟動速度很慢的問題

SmokePing 啟動速度緩慢的問題終於搞定,原因在於啟動時會掃一次列表裡所有的 host,對這些 hostname 檢查是否存在,不存在的 hostname 會丟出警告,但並不會因此就不檢查。這個檢查也是造成網頁介面很慢的原因。

dirty hack 的解法很簡單,把 /usr/local/smokeping/lib/Smokeping.pm 裡檢查的 code 直接註解起來就可以了。有 getaddrinfo() (檢查 IPv6 的部份) 與 gethostbyname() (檢查 IPv4 的部份) 兩個地方要修正,修完速度就變得很快了。

星期一, 11月 24, 2008

FreeBSD 的問題

如果用 FreeBSD 架設伺服器,有蠻多地雷要注意的:
  • FreeBSD 的 NFS client 寫的不好,同樣的大檔案從 NetApp Filer 上拉下來,不論是 FreeBSD 先拉,還是 Debian 誰先拉,FreeBSD 的傳輸效率只有 Debian 的 1/8。而且會對 NetApp 造成很大的 CPU loading。
  • FreeBSD 的 filesystem 在 random read 的效率不好,UFS2 的 journal 功能有問題,很容易 panic;ZFS 的效率很差,而且也不穩定。Linux 上的 XFS 有 journal,而且效率好很多。這點在跑 MySQL 時可以發現。
  • FreeBSD 有些 system call 以及 standard library 的寫法相較於 Linux 昂貴許多,而且在 SMP 環境下不 scalable。以我們遇到的 PHP 所使用到的 require_once() 所用到的 stat() 就是一個例子。
如果要搞 Startup,選 Debian 會是比較好的路...

星期五, 11月 21, 2008

HTTPS 的管理 (用 L4 switch)

用 Layer 4 Switch 幫你處理 SSL 真舒服,後面都不需要管 HTTP/HTTPS 的問題... (花了錢就儘量用硬體幫你解決問題 XD)

FreeBSD 上高可靠度的 Recursive DNS server

FreeBSD 上要做到 HA recursive DNS server 還蠻簡單的,先把 CARP 建好,再把 unbound 裝起來。重點在 unbound 有一個設定:
interface-automatic: yes
這樣才會從正確的 IP address reply。

星期日, 9月 21, 2008

Cacheboy 1.5

Cacheboy 1.4 換成 1.5 後,CPU 使用率下降許多... 之前在 80~100 Mbps 的時候會達到 CPU bound,現在看起來要到 500Mbps 以上才會到 CPU bound。拿來跑小檔案的 cache 應該會相當好,不過這也等測過才知道...

不過,不論是 Squid 還是 Cacheboy,都沒有支援 deflate 與 gzip 壓縮,所以還是沒辦法拿來擋 CSS/JavaScript 的靜態檔案,這點還得再想辦法...

星期三, 9月 17, 2008

Bug Report

負責把外部的 bug report 轉成內部 ticket system report 果然是一件很累的事情,剛剛的兩個小時才殺了 150 個,精神就已經開始委靡了...

星期六, 9月 13, 2008

PHP require_once 效率問題

測試後終於有個好解法了,感謝 mailing list 上提出的建議...

重點在於 include_path 的設定,儘量在第一個 search directory 就找到要的檔案。我們的作法是設一個 class 的目錄,用 symbolic link 把所有的 class file 或是 class directory 放進去,接著用 Zend Framework 的 Zend_Loader::registerAutoload() 在 new 的時候自動讀入,最後把 Zend Framework 裡所有的 require_once 都拿掉。

這樣的速度比起原來 system 非常高的情況好很多。

星期二, 9月 09, 2008

利用 DRBD 生出 MySQL slave

簡單說明一下,這篇要說明的環境是:在 DRBD 上跑 MySQL,上面檔案系統是 XFS,資料庫全部都是 InnoDB,已經有設定好 server-id 並打開 binlog。現在想要把這台 MySQL 轉成 master,另外要想辦法從這台資料庫複製一份適當的資料跑 MySQL slave。

想法是先把 MySQL 的寫入動作擋住,然後把資料 sync 回 filesystem,這時候到備援機上 disconnect DRBD,再回到原來的 MySQL server 上開放寫入的動作。這時候備援機上的 DRBD 就是一份完整的 data。

詳細的指令大致上是這樣:
  1. 先在 DRBD primary 上的 MySQL 上跑 FLUSH TABLE WITH READ LOCK;,然後跑 SHOW MASTER STATUS; 把 binlog position 記起來。
  2. 在同一台機器上跑 sync; sync; sync 把 buffer 裡的東西都寫回硬碟。
  3. 到 DRBD secondary 上跑 drbdadm disconnect [drbd_resource],其中 [drbd_resource] 要記得換成你自己在用的 resource name。
  4. 回到 DRBD primary 上直接 Ctrl-C,或是下 UNLOCK TABLES; 釋放鎖定。
  5. 這時候到 DRBD secondary 上先把 monitor program 停掉,以免他亂來。
  6. 接下來還是在 DRBD secondary 上,要「催眠」這台主機的 DRBD 是 primary:drbdadm primary [drbd_resource]
  7. 「催眠」完後跑 mount -o ro /dev/drbd0 /mnt,用 read-only 狀態掛到 /mnt。如果不小心掛成非 read-only 也沒關係,等下記得重新 resync 就可以了。
  8. 把掛上來的 /mnt 整份資料複製出來,丟到預定要當 MySQL slave 的機器上。
  9. 複製完成後 unmount /mnt,然後告訴 DRBD「其實你是 secondary」:drbdadm secondary [drbd_resource]
  10. 然後告訴 DRBD 需要重新 sync 檢查:drbdadm -- --discard-my-data connect [drbd_resource]
  11. 理論上這樣就完成了。接下來就是第一次如何設定 MySQL slave 的步驟,講 MySQL replication 的書籍應該都有說。
今天加了 MySQL slave 後應該是穩定不少,接下來再來想辦法解決頁面生成過慢的問題。

星期六, 9月 06, 2008

DRBD 與 MMM

換了 24GB 記憶體後機器當了四次,軟體方面,懷疑是不是 InnoDB 參數的問題,一開始設 18GB (75%),剛剛改成 16GB (66%),希望這樣就能解決...

如果不能解決,懷疑到硬體頭上就頭痛了,因為這樣就得再幹一組機器出來用。

另外以後確定了,資料庫一定要買有 IPMI 卡的,不然重開機這件事情得 call 機房處理 (上班時間還要補文件),對我們與機房都不方便。

另外開始考慮 MMM 了,downtime 比 DRBD 少,承載量比 DRBD 大 (因為多一台可以當 slave),再加上因為平常就有 slave,所以 warm up 時間一定會比 DRBD 短。

但這東西大約是去年春天才出來的,沒看到夠大的 site 在用... (這也是當初選 DRBD 的原因之一)

幫 mysql database 加記憶體

當初搞 HA 的好處之一,星期六早上六點半 (也就是現在) 可以在中斷服務 (<5mins) 的情況下,直接到機房加記憶體。

步驟很簡單,先 shutdown 備援機,加記憶體,上線後等備援機看起來沒問題後 shutdown 另外一台,再加記憶體。

這次加記憶體把其中一個 cluster 從 12GB 加到 24GB (大約全 PIXNET 2/5 的 user 的 Blog 資料在上面),打算用這個方法先解決 mysql 的過載問題。

Update:好像還是太久,大約 10mins。

星期三, 9月 03, 2008

Pix_Db 與 Pix_ORM

整理一下,找機會 open source 出來。這兩個 class 都是 PHP5 的 class,儘量使用 PHP5 的語言特性以及 interface,讓使用的人更方便使用。

Pix_Db 主要的特性包括:
  1. JSON 檔為設定檔。(這點在考慮改寫)
  2. 以 PDO MySQL 為底層,只打算支援 MySQL。
  3. 比其他 Database Wrapper 方便的操作方式,像是 $dbh->query('DELETE FROM comment WHERE blogid = ?, articleid = ?', $id, $article);,而非 array($id, $article)
  4. 多台 Slave 時的 Round-Robin 以及 failover。
  5. Master/Slave 架構時,如果判斷 SQL query 有寫入動作,使用 Master 連線。
  6. 解決單一 handler 配合 transaction 互相干擾的問題。
  7. 同樣帳號密碼的連線能夠重複使用。
  8. 只有一個檔案。
  9. 目前只有 293 行。
Pix_ORM 是一套 ORM framework,但與目前的 ORM framework 不同的地方在於:
  1. 架構在 Pix_Db 上。
  2. 不需要指定 columns,也不會到資料庫裡查 table metadata。
  3. 僅需要指定 primary key。
  4. 支援 has_one 與 has_many,目前沒打算支援 have_many (many-to-many),因為可以用前兩者配合出來。
  5. 可以自己寫 aliases 做到更特殊的效果。
  6. 目前只有 510 行。
目前還在研究要用什麼 license,以及程序問題...

Mercurial 對應於 Subversion 的 svn:externals

答案是:沒有。至少官方 Wiki 上是寫 0.9.5 沒有這個功能。(現在已經 1.0.2 了)

我想要把 Hasname_Controller 對應到內部的 Mercurial Repository,想要用類似的功能,結果發現本功能並不存在:Externals

雖然不是什麼大問題,不過用慣了 svn:externals,現在沒有這個東西總是覺得怪怪的。

星期二, 9月 02, 2008

Mercurial

commit mail 的部份主要是參考這篇:Setting up Mercurial to e-mail on changes,寫的還可以,自己多 try 幾次後就大概懂了。

終於把 Mercurial 的 commit mail 搞定了,不過這是內建的 commit mail hook。接下來要試著跑自訂的程式,這樣才能在 commit 後上 IRC 上叫叫叫...

Cacheboy 1.4

Cacheboy 的 CPU usage 比起 Squid 3 高出不少,即使都是大檔案,Cacheboy 的 CPU usage 限制只能到 120Mbps 就上不去,但 Squid 3 在 100Mbps 的時候還是只有 20% CPU usage...

不過如果是大量的小檔案造成 I/O bound 時就差很多了,看得出來 Cacheboy 的穩定性比 Squid 3 高很多,至少會慢慢把圖吐出來而不會破圖。

兩者適合用在不同的地方,放著跑,繼續測試...

星期一, 9月 01, 2008

MySQL 與 DRBD

沒想到才 9/1 就遇上第一次 MySQL 當掉跳到另外一台的情況,而且還是最大的那個 cluster。也如同預期的有 warm up 的問題... (Cache 尚未全部讀入,速度比較慢,造成頁面生成時間過久而產生 500 或其他類似的症狀)

這個時間 (星期一下午) 的量,看起來要花十分鐘 warm up,這是最大的一台,其他台應該會更快。

Google SSO 的通知 (SAML implement)

前陣子 Google 寄信來說我們的 Google Apps SSO implement 有問題,需要修正送出的格式。照著信件裡的說明改完,過沒多久又寄信來通知說有問題,然後還透過台灣 Google 打電話到公司來。

花了一些時間比較 Google 提供的範例,結果看了老半天看不出來... 決定等 Google 停權的那一刻再來檢查。(因為這陣子實在是沒時間跟美國人慢慢耗)

通知信是寫 8/28 (美國的時區,我忘了是哪個),我記成 9/1,今天到公司要查正確的時間才發現早就過了,而且 Google Apps 的 SSO 登入看起來也都沒問題,省了下午要盯住的時間...

星期日, 8月 31, 2008

funp.com 的 DNS 設定

debug 的時候發現有蠻多人的 blog 頁開起來很慢,看起來是中間某個站台卡住,為了確認問題是我們自己還是外站,拿 HttpFox 出來檢查看看每個 request 的速度,才發現是卡在 funp.com 查不到 IP address。

目前的設定是把 funp.com 的 NS RR 指到 dns{1,2}.funp.com.tw,但又把 funp.com.tw 的 NS RR 指到 dns{1,2}.funp.com... *gosh*

所以邊檢查邊跟 IRC 上的同事聊天,出現以下的對話:
22:33 <@gslin_tfn> funp.com 的 DNS 亂設一通...
22:34 <@gslin_tfn> 害我覺得怎麼 pixnet blog 頁面 load 這麼慢 -_-
22:34 <@gslin_tfn> 誰去抗議一下啊...
22:34 <@gslin_tfn> xxxx_: 那個誰去抗議一下啊
22:34 <@gslin_tfn> xxxx_: 那個誰去抗議一下啊
22:34 <@gslin_tfn> xxxx_: 那個誰去抗議一下啊
22:34 <@far> XDD
22:35 <@gslin_tfn> funp.com NS 指到 funp.com.tw,然後 funp.com.tw 的 NS 指到 funp.com..........
22:35 <@gslin_tfn> 你不要以為現在是七月就會通啊啊啊
22:36 <@repeat> gslin_tfn: 應該是因為不是七月了所以不會通…
22:36 <@gslin_tfn> 啥,不是七月了喔?
22:36 <@repeat> 今天農八月一日。
22:36 <@gslin_tfn> XDDDDDDDDDD
22:36 <@ronnywang> 難怪到今天才不通
補充一下,會不會通是看 DNS implement 有沒有照規矩來,有照規矩來的應該「不會通」XD

在狀態乾淨的情況下要找 funp.com,從 root 找到 dns{1,2}.funp.com.tw 後會再從 root 要 funp.com.tw 的 NS 資料,然後得到 dns{1,2}.funp.com.tw,於是又回到起點,就噴掉了...

各種瀏覽器的支援

IE6 是最麻煩的,有一堆 css workaround 得處理 (像是用 _ 開頭對 IE6 另外計算 css 效果),IE6 本身的 javascript 也有問題,不只是速度,還有對於螢幕、視窗大小的計算。(可以 jQuery 解決一部份問題)

Safari 不要遇到 bug 都很好,遇到的時候就 Orz 了,像是 z-index + select + draggable 似乎很容易中地雷 Orz

Firefox 本身也有好幾個版本要測試,不過畢竟是平常就有在用,自然就會測試到... 像是我自己在家裡用 3.1 w/Tracemonkey,公司會用 3.0 nightly,其他人會用 3.0.x,另外在 Mac 上也有人用 Firefox 3。至於 Firefox 2 用的人就比較少了,不過 repeat 以及 sandy 倒是都還有裝起來用。

Opera 真的沒人用 Orz

Bugzilla 與 Trac

本來內部是用 Bugzilla 在處理 bug (repeat 甚至把整個繁體中文的語言包翻完),不過這個系統實在太複雜... 後來還是換成 Trac,配合一些規定 (Workflow) 在管理,看起來還算可以。

這四天內開了超過四百個 ticket,從官方 blog 上的回報、Ptt Blog 板的回報,以及內部自己測試的回報,現在也只能儘量修。

Anyway,等告一段落再整理一些東西出來。

Subversion

Subversion 1.5 後終於有存 merge history,不再需要自己計算 merge 的部份。不過目前的版本問題還是不少 (目前是 1.5.1),使得使用起來還是綁手綁腳的。

一個常見的情況是錯誤的 commit:有些 developer 會把非 branch only 的修改直接 commit 到 branch 裡 (就別問為什麼會這樣了),這時候一個簡單的作法是把這個 commit merge 回 trunk。但這樣會造成 Subversion 之後要再從 trunk merge 到 branch 時混亂。目前的解法是在 trunk 再 commit 一次,然後故意 merge trunk to branch 造成 conflict,然後把他解掉。

不過這陣子開始在研究 Mercurial 了,因為 Mercurial 也有 centerialized pattern 可以中央集中管理,目前已經測的差不多,只要把 Subversion 的 post-commit 都移植過去就可以了。

require_once 的效能

因為這是 PHP 的問題 (而且看起來 PHP 5.2 系列沒解),我在 Zend Framework 的 mailing 上有問關於 ZF 有沒有避免的方法:require_once performance issue in ZF

其中第一篇回應指出既然都用 autoload,那麼就拿掉所有的 require_once,應該可以解決我的問題,我測了一下,似乎有幫助,但沒有想像中那麼多。看起來還是得仔細調整 include_path 以避免大量的 lstat miss。

第二篇回應基本上是個搞不清楚狀況的人問一些狀況外的問題。要裝一套有 opcode cache 的軟體已經是常識了,另外整個問題在於 system call,而非 I/O bound,要人丟到 memory disk 上面沒有意義。

不管怎麼樣,以目前的效率來說,還是得不斷的試著調整系統,17 台 PHP server 感覺還是太多,希望可以壓到 10 台左右。

本次升級有感

當你想用 dirty hack 儘快解決事情,之後一定會遇到 bug,然後花更多的時間解決。

不過有更多的人不懂這一點,仍然不會學到教訓。

星期五, 4月 11, 2008

用 MySQL connect timeout 處理 DB failover 以及 load sharing

程式碼大約是這樣:
function foo(array $db_srvs)
{
// $db_srvs 是簡單的 array('db1', 'db2', 'db3') 即可
shuffle($db_srvs);
ini_set('mysql.connect_timeout', 1);
foreach ($db_srvs as $h) {
$db = @mysql_connect($db_srvs, $user, $pass, $dbname);
if ($db)
return $db;
}
return NULL;
}

當然還是要有其他的 monitoring software 去盯 MySQL server,不然會有很多連線會卡一秒鐘...

星期二, 4月 08, 2008

用 rsync 同步程式碼

如標題所寫的,用 rsync 同步程式碼。

我的打算是用 Subversion 更新,然後用 post-commit 把程式碼推出去,配合 --exclude 的參數去掉 .svn/ 的目錄。

星期一, 4月 07, 2008

KISS

好的架構會保持 KISS principle

Zend Framework 裡 Zend_Controller 的 module

現在還在想要怎麼處理這個部份,如果全部塞 default module,那麼事情都很簡單,但是 Controller 檔案就會很大,撇開效能問題,管理上也是一個大問題。

如果使用 module 拆開,那麼 controllers/models/views 都會拆開,controllers 本身是小問題,但 models 必須逐個加到 include_path 裡 (參考「缺乏 Model 支援的 Zend Framework」這篇的方法),而且 views 的部份就沒有比較好的方法共用 (像是我寫了一個 forwardurl.phtml,以非 30x Redirect 的方式重導)。

應該會用後者的方法,不過要想方法把 models 與 views 的問題解決...

有時候很好玩

有台機器叫做 develop,但是大家都沒在上面開發,都跑去一台叫做 testphp 的機器開發,然後上面跑 RoR...