星期二, 7月 21, 2009

Squid based reverse proxy tuning

這兩天測試的感想。

不管怎麼 tune,軟體要先選對,不然 tune 起來就很悶了...

Lusca 是改自 Squid 2。Squid 2 因為很多人使用過很長一段時間,所以有很穩定的 codebase (先不管是不是 dirty hack 堆出來),Lusca 則是在 Squid2 的 codebase 下改善效能,用了一年多 (之前 Lusca 的專案名稱叫做 Cacheboy),的確很穩定。

Squid 3 對 CPU 的使用率低很多,但就我自己用的感覺,在 reqs/sec 很高的時候穩定性不太好。另外因為 Squid 3 改寫了很多東西,所以有些重要的功能反而不見了。(像是 cache_peer 的 monitorurl 設定)

雖然 Lusca 在 high reqs/sec 時 CPU usage 高很多,但就目前的 CPU 應該都夠用。就目前其中一台 E5345,上面跑 250reqs/sec 大約吃單顆 30% CPU usage。

比較需要特別提出來的是,在 reqs/sec 很高時,accesslog 寫入反而會變成效能的瓶頸。在 Lusca 可以使用 logdaemon 解決 (這個功能 merge 回 Squid 3.1 了):
access_log daemon:/home/logs/squid/access.log squid
cache_store_log daemon:/home/logs/squid/store.log
logfile_daemon /usr/local/squid/libexec/logfile-daemon
這樣 write log 就不會使 Lusca 卡住而反而造成 CPU bound。

星期四, 7月 09, 2009

修正 mod_fastcgi 在 threading 環境下會 coredump 的 bug

PIXNET 我們是用 Apache 2.2 MPM worker + mod_fastcgiPHP,但從以前就發現 httpd 會自己死掉,雖然 parent httpd 會再把他叫起來,但會造成已經連上的 connection 斷線。

昨天花了一個下午的時間追這個 bug,後來發現是 mod_fastcgi 使用 getgrgid()getpwuid() 的原因造成的,這兩個 function 在 FreeBSD 上並不是 thread-safe function,在 Open Group 的文件也說明這兩個 function 不需要 thread-safe。

所以這兩個 function 必須用 getgrpid_r()getpwuid_r() 改寫。

除了把 patch 送到 FastCGI mailing list 上讓人確認外,這邊也放一份好了:
--- fcgi_util.c.orig    2009-07-08 17:16:29.816884000 +0800
+++ fcgi_util.c 2009-07-09 08:43:09.222180000 +0800
@@ -268,13 +268,17 @@
/* Get the user membership for the file's group. If the
* uid is a member, check the group bits. */
{
- const struct group * const gr = getgrgid(statBuf->st_gid);
- const struct passwd * const pw = getpwuid(uid);
+ char buf[1024], buf2[1024];
+ struct group gr, *r;
+ struct passwd pw, *r2;

- if (gr != NULL && pw != NULL) {
- char **user = gr->gr_mem;
+ getgrgid_r(statBuf->st_gid, &gr, buf, sizeof(buf), &r);
+ getpwuid_r(uid, &pw, buf2, sizeof(buf2), &r2);
+
+ if (r != NULL && r2 != NULL) {
+ char **user = r->gr_mem;
for ( ; *user != NULL; user++) {
- if (strcmp(*user, pw->pw_name) == 0) {
+ if (strcmp(*user, r2->pw_name) == 0) {
if (mode & R_OK && !(statBuf->st_mode & S_IRGRP))
return "read not allowed by group";
if (mode & W_OK && !(statBuf->st_mode & S_IWGRP))
@@ -445,8 +449,9 @@
{
#ifndef WIN32

+ char buf[1024];
struct passwd *pw;
- struct group *gr;
+ struct group gr, *r;

if (fcgi_wrapper == NULL)
return NULL;
@@ -467,14 +472,14 @@
s->username = s->user;

s->gid = gid;
- gr = getgrgid(gid);
- if (gr == NULL) {
+ getgrgid_r(gid, &gr, buf, sizeof(buf), &r);
+ if (r == NULL) {
return ap_psprintf(p,
"getgrgid() couldn't determine the group name for gid '%ld', "
"you probably need to modify the Group directive: %s",
(long)gid, strerror(errno));
}
- s->group = ap_pstrdup(p, gr->gr_name);
+ s->group = ap_pstrdup(p, r->gr_name);

#endif /* !WIN32 */