apache22 (worker) + mod_fastcgi + php5-fcgi

這篇會講怎麼在 FreeBSD 上建立標題所說的環境。

Apache 2.2 的部份,透過 ports 編譯時加上 WITH_MPM=worker 即可:

# cd /usr/ports/www/apache22
# make WITH_MPM=worker install clean

裝好後將 /usr/local/etc/apache22/httpd.confhttpd-mpm.conf 前面的 # 拿掉,並修改 /usr/local/etc/apache22/extra/httpd-mpm.conf 內 mpm_worker_module 那段:

ThreadLimit 512
StartServers 1
MaxClients 512
MinSpareThreads 1
MaxSpareThreads 512
ThreadsPerChild 512
MaxRequestsPerChild 0

這些數字的設計是故意只跑起一隻 httpd,負責所有的連線。

再來是裝 mod_fastcgi

# cd /usr/ports/www/mod_fastcgi
# make install clean

/usr/local/etc/apache22/httpd.conf 裡把 fastcgi_module 的註解拿掉後,把設定檔放到 /usr/local/etc/apache22/Includes/fastcgi.conf 裡:

#
FastCgiConfig -maxClassProcesses 1
ScriptAlias /fcgi-bin/ "/usr/local/www/fcgi-bin/"
<Directory /usr/local/www/fcgi-bin/>
    SetHandler fastcgi-script
</Directory>
#
AddHandler php-fastcgi .php
Action php-fastcgi /fcgi-bin/php

這邊數字的設計是故意讓一隻 httpd 只能生出一隻 fastcgi,再加上前面限制只有一隻 httpd,可以確保整個 apache 只會透過這個 fastcgi socket 跑 php。

接著建立 /usr/local/www/fcgi-bin 這個目錄,並把 php 放進去:

#!/bin/sh
PHPRC="/usr/local/etc"
export PHPRC
PHP_FCGI_CHILDREN=128
export PHP_FCGI_CHILDREN
exec /usr/local/bin/php-cgi

然後把有支援 FastCGIPHPAPC 裝好 (www/pecl-APC) 就可以了。

這個架構下,httpd 會產生 512 threads 處理連線,並產生一個 fastcgi 的 socket 處理 PHP 程式,這個 socket 會由 128 隻 php-cgi 聽,且這 128 隻的 cache 會共用。

APC cache 預設是 30MB,在 Layeredtech 這台 (也就是 blog.gslin.org 這台) 上面開到 256MB (大約用掉 200MB),不過這是因為上面太多客人了,預設的 30MB 對於一般網站應該是不會滿。在安裝完 APC 後可以拿 /usr/local/share/doc/APC/apc.php 看目前 APC 的使用量。

PHP opcode cache 很重要,很久前 zonble 的「雜誌專訪產生器」造成機器速度很慢的原因,就是因為 APC 的空間滿了,常常需要重新編譯 PHP code。

這樣的設定大約會消耗 1.5GB ~ 2.5GB 的記憶體空間 (大小會依照你的 PHP 有多少模組而定),如果網站沒那麼大,可以把數字調低。

YUI 3.0 Preview Release 1

YUI team 終於想開了,不再用像是 YAHOO.util.Event.addListener 這種寫 code 時會一直抱怨的命名方式,而是改用 Y 當作物件,並支援 fluent interface,也就是 Y.foo('blah').bar('blah2') 這種串接的用法:YUI 3.0 Preview Release 1

但缺點就是因為語法改變,你必須改寫... 不過應該不是大問題,因為 YUI 2 與 YUI 3 不衝突,在過渡期時你可以把兩個 framework 都讀進來。

假設前後台順利上線後,之後的計畫...

我們 (PIXNET) 預定在 8/19 凌晨開始,全面停機轉換到新後台,8/20 正式上線:【公告】後台上線停機預告。不過實際上我們待命的時間會比這個久,因為要提早開始準備,上線後還要保留二十四個小時 (預定) 修改問題。

上線後除了開始收 feedback 外,也開始要跑下一波計畫改善整個系統。

我打算實際拿 MogileFS 用,要了解穩定性與效能。MogileFS 是一個分散式的檔案系統,國外有一些站台已經在用,日本似乎也有不少人研究。

用 MogileFS 時前端會放 reverse proxy,目前看起來 Squid 3 與 Varnish 都還可以,只要不要碰到 Disk I/O 就沒問題。而 Cacheboy 是一個 Squid 2 fork 出來的專案,還要再仔細看看。

另外一種方案是不自己搞 reliable storage,除了 local 存一份外,直接丟 Amazon S3,然後買 CDN 服務,省下來的時間用在其他地方...

另外一個要研究的是透過 PF 做 load balancer,用 pfsync 與 CARP 拉高穩定性。

資料庫的部份,除了 InnoDB 外,我想看看 PBXTMaria 進展的如何。

接下來想研究的東西就跟前後台無關了,像是 OpenVZXen...

這次 PIXNET 前後台的一些整理

趁著在家養傷 (腳痛) 寫程式的時候,順便把這陣子 PIXNET 在重新改寫的部份紀錄下來,從底層與 OS 比較有關的、PHP 的,以及 Web UI 的部份。

FreeBSD 的 NFS client 的效能並不好,在這次 PIXNET 前後台大改版前,我這幾天重新跑數據看目前舊系統的架構,可以看出來 PHP code 放到 NFS 上面所吃的 system CPU resource 比 userland CPU resource 還多:(這是其中一台 blog 主機的 CPU usage,用 Munin 畫出來的圖,中間斷掉那段是我在改 Munin 的設定...)

從圖上可以看出這台跑 blog 的主機有 4 Logical CPUs,但卻有很多 idle time。這是因為 NFS 量更大時會不穩定,所以我們無法使用更高。這次改版把所有的 code 都放到 local disk 上,應該會有很大的改進。

MySQL 還是用 Linux 比較好,同一台機器 (Xeon E5405 + 16GB RAM + 10KRPM*2) 分別跑過 FreeBSD 7-STABLE、8-CURRENT (20080812)、Linux 2.6。在 FreeBSD 上用 UFS2 (包括 noatime + async 與 noatime + softupdate 都有測試) 一直都是 I/O bound,而在 Linux 上用 XFS 一直都很順。這是用 MySQL slave 跑 real traffic 而非模擬測試。

新的資料庫系統還是用 Linux 平台,然後引入 DRBDInnoDB 達到 High Availibility。不過我想在這陣子忙完後測 MMM,以他的實做方式看起來會比 DRBD 好。(但 DRBD 開發比較久,資料比較豐富,也比較容易找到穩定的設定)

PHP 的部份仍然使用 Apache 2.2 + mod_fastcgi 與 PHP。不過這次不跑 event mode,而是跑 worker (threading mode)。在正確的設定下,APC 的 cache 是整台機器共用,使用的記憶體更省。上面是 blog2 (worker MPM),下面是 blog5 (event MPM) 的記憶體使用量:(附註:我覺得 event 應該也可以做到同樣的事情,這次換 worker 是因為種種機緣 XD)

其中 FreeBSD 上可用記憶體空間的意義可以參考 Inactive memory 這篇,並不是只有 Free 代表可用空間。

靜態檔案在重新建立架構時,儘量拆開到其他 domain 上,除了可以 pipeline download,也可以節省使用者送 cookie 的頻寬,這部份的伺服器改用 nginx,因為要用他的 gzip on the fly 讓下載的量減少。我們用到的 javascript framework 盡量都塞進這個系統裡。

PHP 的部份,這次是賭了一把,選擇 Zend Framework 實做前後台,而且完完全全使用 ORM framework 處理資料。以目前的量去推算,看起來應該是沒問題,不過還沒上線前誰都不敢說,換燈管的 CTO 還為此先準備另外的機器,如果真的不行就用先暫時用機器海換出來...

我們用到的部份包括 Zend_ControllerZend_ViewZend_Feed。(不,我們沒有用 Zend_Db,而是有個撞到腦袋的人寫了 Pix_Table_Cluster...)

不過 Zend_Controller 並不好用,沒有針對開發者的想法發展 (另外一種說法是,沒有針對 PHP 語言特性實做簡潔有力的語法),所以之後可能會自己開發 Pix_Controller。舉兩個例子說明:

  • 要抓參數可以用 $this->getRequest()->getParam() 抓,也可以用 $this->_getParam() 抓。我可以理解後面是前面的捷徑,但如果 implements ArrayAccess 不是更好嗎?$this->getRequest() 抓出來的 object 可以直接 $obj['blog'] 抓出 blog 這個變數。
  • 如果我想把 /foo/bar/12/34/56/78 拆開,我必須用 Route 做,然後再用 getParam 抓到參數。或是在 barAction 裡面直接自己拆開。我個人比較偏好的方法是先去找 bar_12_34_56_78_Action,沒有再一路往上找,最後會是 bar_Action('12', '34', '56', '78'),這樣寫 code 才會方便。
  • 對 Helper 的使用相當不方便,但這個部份還沒有仔細想要怎麼做才會方便。

另外一個沒有用的是 Zend_Form,原因在於 Zend_Form 的預設值會使得客製化很困難。所以我們自己開發了 Pix_Form,只產生個別的元件,而不產生整體的 Form,所以你可以拿到一個版面後套版進去用。但仍然可以用 Pix_Form validate。

Deploy PHP code 的事情,目前是用 rsync 做,但 rsync 的效率並不高 (不過目前是夠用了),只能加減請 coder 擔待點。前陣子找了不少這類軟體在測試,像是 csync2,不過他同步的方式與期望了方式有落差,也許改變流程,配合 csync2 的方式做,或者是不改變流程,自己從頭幹一個出來?

Web UI 的部份這次改寫時直接強迫大家裝 Html Validator 直接檢查。我對 XHTML 1.0 沒有什麼好感 (事實上這次改版大多都是用 HTML 4.01),但至少不要有 <div> 不對稱這類 browser 會亂猜一通的問題。這樣才不用在奇怪的 DOM tree 裡面操作。

在政策上,javascript 全部用 jQuery,目前的 javascript code 幾乎都是 jQuery 寫出來的。Unobtrusive Javascript 目前只是個理想,有很多地方還是得直接處理。

另外就是 CDN 的事情,有機會再說 orz

Subversion 1.5 的 merge

Subversion 1.5 最重要的改善就是 merge track,實際用過以後可以發現仍然不如 Git 方便,但比起以前得自己計算 revision 改善許多。

不過也因為 merge 本身帶有意義 (會另外儲存 merge info),在「用 Subversion 的 Merge 來 Undo」這篇所介紹的方法就不適合了,因為 svn merge -r 1234:1233 . . 會帶有 merge info。

現在比較好的方法是:svn diff -r 1234:1233 . | patch -p0,不會產生 merge info。

PHP 4.4.9 - PHP4 最後一個版本

2008/08/07 出的 PHP 4.4.9 released! 會是 PHP 4 最後一個版本,不再有任何更新 (即使有安全漏洞,也不會有安全性更新)。這次的 PHP 4 ChangeLog 也很短,除了把 PCRE 版本升級到 7.7 以外,其他都是 bug 的修正。

官方目前唯一維護的版本是 PHP 5,更細的說是 5.2.x 版,目前大多數的 PHP 軟體 (還活著的 Open Source Project) 應該都可以在上面跑。

另外一個重點是 PHP 5.3 在 2008/08/01 的時候出了第一個 alpha 版,這個版本比 PHP 5.2 多了 namespace、lambda function,另外有 phar (應該是藉由 namespace 的幫忙而實做出來)。除了這些功能外,cyclic garbage collection 也是一項很重要的功能:以前如果遇到 cyclic reference 得自己用 unset() 確保 PHP 能夠回收,在 PHP 5.3 就不需要自己用 unset() 打斷 cyclic...

目前官方是希望今年十月釋出 PHP 5.3 正式版,應該會有 Framework 利用這些特性重新改寫...

利用 CSS 產生的隱私問題

Update:這個隱私問題在 2010 年就有被修正,請參考「關於 CSS 中 :visited 的隱私問題」的說明。

雖然很早前就知道 CSS link 可以這樣做,不過實做起來就真的感覺到很邪惡了,既然被 full disclosure,這陣子應該會引起更熱烈的討論:Guessing gender from browser history

首先請先參考 pesty 這篇「網路廣告商怎麼知道你是誰? 從 ClickStream 來判斷用戶資料」,裡面有提到利用 cookie 資訊去猜測目前這個 user 的性別。首先先知道這個使用者逛過哪些網站,然後再用統計方法算出來。

以往廣告商要判斷使用者逛過哪些網站,僅限於自己旗下的網站。舉例來說,很多網站有放 DoubleClick 的廣告,那麼 DoubleClick 就可以利用 IP 資訊、Cookie 資訊、User-Agent 之類的資訊來判斷哪些 request 是同一個使用者,所以 DoubleClick 就可以判斷出這個使用者有上過他旗下哪些網站。

但利用 CSS 隱私漏洞,如果想要知道某個使用者是不是上過某個特定 URL 是可行的。簡單的解釋是:插入一個 link,然後對這個 link 做 CSS 效果,對於瀏覽過的 link (也就是 a:visited) 使他顯示的顏色不同,然後再用 Javascript 去讀顏色,就可以得知使用者是否有上過這個網站。很邪惡,方法也已經有一陣子了 (像是 SocialHistory.js 這種工具),不過大家一直想不出好的解法,於是就一直爛下去...

這個 CSS hack 加上統計分析,可以分析出年齡範圍、性別、興趣,非常邪惡 -_-