技术

人品爆发

周五下午,作为年终的一系列活动之一,CPC 和 NO 在一起举行一个小小的抽奖仪式。结果抽中一个睡袋,结束 N 年以前抽奖不中的记录.. 不过真正的人品爆发是下班前的一件事情:

不知道为什么,临下班的时候内部网络出现故障,结果导致 MySQL 连接过多,too many connections,当时也没有可用的 mysql client 连接,无法去 show processlist 看看都发生了什么。心急如焚,这得影响多少网民啊;另一个心急如焚的原因是偶要赶晚上8点13的火车去天津,票都已经买好,如果为了不被网民以及上级骂死而耽误火车,势必会被老婆骂死。

终于在一个偶然的机会,mysql 连接了上去(很快连接又被占满了)。看了看 processlist,一堆的 unauthenticated user 在试图 connect/login

我立刻想起就在昨天赵宏威在 MSN 上问我同样的问题,当时偶也觉得这个事情比较诡异,但没有帮他找答案,没想到第二天同样的问题就碰上我了。赶紧在 MSN 上问他最后是怎么解决的故障,说是启动的时候加 --skip-name-resolve 参数就好了。

赶紧告诉 DBA 重启,果然问题消失。然后感叹人品之坚挺——出的问题正好是别人刚碰到的,而且他又正好来问我,真是幸运啊幸运。

重新探讨故障原因,应该是 MySQL 的安全模型里面进行用户认证和授权的过程中,除了对 IP 地址做校验之外,还包括了对 HostName 验证的配置。因此所有的用户连接进来以后都需要做一次反向域名查询,然后根据 IP 和 HOST 来进行授权。这样如果因为网络故障导致反向域名解析很慢的话,就会让一个连接很长时间也无法完成...

由此引申开去:

一、MySQL 是否能处理的更好一些呢?相关的 BUG 在 2005 年就有人报告。我觉得在执行反向域名解析之前,至少可以先判断一下来源 IP 是否已经在策略表里面存在,如果存在的话就可以直接做用户认证了

二、标准 C 库(glibc)能不能想法降低做反向解析的时间?比如执行查询之前可以设置一个超时时间?因为反向解析而给用户带来困惑我已经见过好多好多回了

三、我们使用的连接池程序(据说是 resin 自带)是否有问题?当然我不是 Java 程序员,而且这次故障原因和 Java 没有任何的关系。可是明明有连接池限制怎么还会出现 too many connections?看起来是因为 mysql 连接迟迟没有响应,导致连接池程序开始后继的尝试。做新的尝试没有问题,为什么不去 close 以前的连接??或许是写这个连接池的人对 GC 过于自信了?很难想象一个有本事写连接池的 C 程序员会犯这样的失误。嘻嘻,腹谤一次 java

最后虽然有些赶时间,但还是坐上了开往天津的火车。我很严肃的思索了一下为什么今天会有如此之好的人品——结论是周五我做的唯一和以往不同的事情就是偷偷使用了老婆的保湿水和面霜,看来美容活动得坚持下去啊...

以前听人说:女人三十岁前的模样是天生的,三十岁后的模样是自己给的。我补充一下,男人三十岁前的模样是天生的,三十岁后的模样是老婆给的。

Topic: 技术

SWT 的多线程

前段时间的工作里需要做个 GUI 工具,要用 Java 里的 SWT。以前完全没接触过 SWT,就玩过一阵 SWING。其他没什么,就是多线程的时候似乎比 SWING 麻烦点,后台干活跟窗口里面的进度条之间的配合碰到了问题。google 了一下,看了123等网页,克服代码里碰到的问题后,总结如下:

1.干活是一个线程,UI是另一个线程,不要在干活的线程里牵扯到UI的操作。可以在干活的线程里用设boolean类型变量的方法,通知UI线程做相应变化。
2.使用Display.syncexec/asyncexec(Runnable) 来执行非主线程的代码。

大概的样子就是如下

public work() {
aaa().start();
bbb().start();

}

private Thread aaa() {
return new Thread() {
public void run() {
/* 干活 */
}
};

}

private Thread bbb() {
return new Thread() {
public void run() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
/* UI操作 */
}
});
}
};
}

Topic: 技术

俺也回来了

过了三天没有泡网的日子。

周四、周五、周六参加新员工培训,周四、五是在十五层的四海会议室,周六是参加一个拓展训练。正是项目最紧张的时候,前两天培训的时候每当有休息时间,我就赶紧冲回办公室,检查我们部门和其他业务部门的进度情况。周四晚上还别人都下班了还得回复并撰写一堆 email。周六晚上打开 bloglines,顿时发现三天时间积攒了好多好多的 feeds,硬着头皮看下来......找两条有意思的吧:

1. 云风也开始讨论用户身份认证方案。内容没有什么,倒是回复中有人提到多服务 SSO (single sign on) 的标准解决方案是用 kerberos。其它解决方案也是用 kerberos 的模型,日后有时间学习学习 kerberos

2. 最新的一期 Firefox trunk build 增加了好多特性。Trunk 版本自从 Win32 加入 Cairo 后我基本上就天天用了;办公室的系统由于 FireBug 还不完全支持 trunk (无法在 console 中输入命令),所以最近一直在用 2.0。不过总体来说 trunk 的可用性稳定性和正式版没有什么区别,没事可以考虑装个试试看,不过还是应该创建一个和正式版不一样的 profile。

Topic: 技术

使用 httplib 而不是 urllib/urllib2

决定写一个 python 脚本来定时检查用户登录是否好用,本打算使用以前用过的 urllib2 模块的——qyt同志和我曾合力写了一个脚本从网站上爬数据,追踪我妈购买的三支股票的情况,结果发现并不那么合适。因为挂在 passport.sohu.com 这个域名下的机器有多台,urllib2 无法分布通过不同的内部 IP 进行连接。

在 CHM 里面搜索了一番,找到了 httplib。首先用 HTTPSConnection(host) 指定连接的目标,然后就可以发送 request 了;另外它也支持 https。

另外要注意的是 httplib 缺省是阻塞无超时机制的 socket 连接。使用之前需要

  1. import socket
  2. socket.setdefaulttimeout(5.0)
Topic: 技术

FireBug 1.0 !

这个月三个重量级的产品发布了新的里程碑:jQuery 1.1,prototype 1.5,然后就是 FireBug 1.0

其实我也就是最近才偶尔用用 FireBug,不过还是觉得这玩艺深深改变了以往调试 JS 程序的方式。Internet Explorer Developer Toolbar 好不容易赶上了 DOM Inspector + Web Developer 的功能,但又远远被 FireBug 落在了身后。

如果有工夫的话,倒是想着利用 python 给 IE 做一个开发用的插件,实现 HTTP Watch 的功能

Topic: 技术

Apache2 Module 开发后记

没有接触 Apache Module 开发的人可能觉得这是一个很深奥的事情,其实对于有一定经验的人来说还是挺简单的。当然最好是有这么一个环境,一些"SMTH系"的人的 blog 时常会提到什么什么时候又写了一个 Apache Module,语气犹如吃饭睡觉一样稀松平常;深受清华影响的 SOHU 也是如此,动辄就会有个人跳出来和你讨论某样业务如果用 Apache Module 来实现会如何如何,久而久之,就会在思维深处认为写 Apache Module 简直是天经地义。

1. 最通常的用法就是 ap_hook_handler. 这里是 http request 处理的最后时期。而且注册的所有的 handler 都会执行一遍。我做的模块的最核心的流程就是在某些条件下增加一个 HTTP Header 交给最终的内容处理引擎(比如JSP/PHP之类);以及设置一个 Response HTTP Header 项,当 Apache 开始向浏览器返回 Response 的时候,会把我这里添加的项目也输出出去。

2. ap_hook_handler 会应用于所有的请求,有些时候会显得效率有些低——比如对静态文件就没有必要执行额外的处理,这时候用 input_filter 可能会比较好。通过 AddInputFilter 可以设定对某些 Directory/Location 才执行对应的 filter 操作。不过据说 filter 应用也有一些效率问题,需要做详细的 benchmark 才能有结论。

input_filter 的另一个用途就是保持长连接,比如 webim 就可以通过这个方式来实现 Server 端的业务。

3. post_config 阶段可以用来检查运行模块所需要的参数是否都在 httpd.conf 里面被正确配置了。不知道 Apache 的人出于什么样阴暗的心理,post_config 会被执行两次!?这里有人提出了解决方案,如何确保自己的代码只运行一次,而不至于在 error_log 里面留下连续两行同样的LOG如同可笑的弱智bug。

由于我写的这个模块将会被部署到很多台很多台服务器上,万一哪天需要更换模块就需要找出所有部署的系统进行更新。于是每次 Apache 启动后会向一台中央服务器发送一条记录,通知该服务器维护人员的联系方式。这个流程也放在 post_config 阶段,此时 Apache 还没有 spawn 子进程,如果连接并发送记录花很长时间的话会影响 Apache 的正常服务。通常的思维是发 UDP 包出来,但这样的话需要额外写一个 UDP Server 接受它们,于是我在模块里面无耻的 fork 出一个子进程,利用 APR 提供的 socket 函数,大概 10 几行代码就搞定一次 HTTP 请求,然后马上 exit

Topic: 技术

openssl speed

使用 openssl speed [value] 可以测试某项算法的执行速度。

可以直接执行 openssl speed rsa,让他依次去计算 512bit、1024bit、2048bit、4096bit 的效率;也可以单独执行 openssl speed rsa512 来算。

在 PIII 700 上的结果为

                  sign    verify    sign/s verify/s
rsa  512 bits   0.0021s   0.0002s    475.4   5199.0
rsa 1024 bits   0.0102s   0.0005s     97.7   1883.4
rsa 2048 bits   0.0592s   0.0017s     16.9    582.2
rsa 4096 bits   0.3912s   0.0055s      2.6    181.9

speed 参数还支持 -multi n 参数来进行并发操作。在 PIII 700 双CPU 情况下并不是成倍增长,很奇怪。不过可能因为那台机器当时还有其他负载的缘故。

按照《应用密码学》里的建议(Applied Cryptography),2007 年企业应用应该考虑 1536bit,但 openssl speed 不支持1536bit的benchmark,于是自己写了一个程序来计算效率。

  1. /*
  2.  * openssl genrsa -out rsa1536.key 1536
  3.  * openssl rsa -pubout < rsa1536.key > rsa1536.pub
  4.  * gcc -o benchmark benchmark.c -lcrypto
  5.  *
  6.  */
  7. #include <unistd.h>
  8. #include <signal.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <openssl/rsa.h>
  12. #include <openssl/pem.h>
  13.  
  14. int global_flag = 0;
  15. void signal_alrm(int sig)
  16. {
  17.     global_flag = 1;
  18. }
  19.  
  20. int main(int argc, char *argv[])
  21. {
  22.     char *buf;
  23.     int size, ret;
  24.     FILE *pubfp;
  25.     FILE *prifp;
  26.     RSA *pub;
  27.     RSA *pri;
  28.     int i;
  29.  
  30.     OpenSSL_add_all_algorithms();
  31.     ERR_load_crypto_strings();
  32.  
  33.     pubfp = fopen("rsa1536.pub", "r");
  34.     prifp = fopen("rsa1536.key", "r");
  35.     pub = (RSA *)PEM_read_RSA_PUBKEY(pubfp, NULL, NULL, NULL);
  36.     pri = (RSA *)PEM_read_RSAPrivateKey(prifp, NULL, NULL, NULL);
  37.     fclose(pubfp);
  38.     fclose(prifp);
  39.  
  40.     if (pri == NULL) {
  41.         printf("PEM_read_RSAPrivateKey error\n");
  42.         ERR_print_errors_fp(stderr);
  43.         return 1;
  44.     } else if (pub == NULL) {
  45.         printf("PEM_read_RSA_PUBKEY error\n");
  46.         ERR_print_errors_fp(stderr);
  47.         RSA_free(pub);
  48.         return 1;
  49.     }
  50.  
  51.     size = RSA_size(pri);
  52.     buf = (char *)malloc(size);
  53.  
  54.     signal(SIGALRM, signal_alrm);
  55.     alarm(10);
  56.     i = global_flag = 0;
  57.     while (1) {
  58.         if (0 == RSA_sign(NID_md5, "0123456789abcdef", 16, buf, &ret, pri)) {
  59.             printf("RSA_sign error\n");
  60.             ERR_print_errors_fp(stderr);
  61.             free(buf); RSA_free(pub); RSA_free(pri);
  62.             return 1;
  63.         }
  64.         i++;
  65.         if (global_flag) break;
  66.     }
  67.     printf("RSA_sign: %d\n", i);
  68.  
  69.     i = global_flag = 0;
  70.     alarm(10);
  71.     while (1) {
  72.         if (0 == RSA_verify(NID_md5, "0123456789abcdef", 16, buf, ret, pub)) {
  73.             printf("RSA_verify error\n");
  74.             ERR_print_errors_fp(stderr);
  75.             free(buf); RSA_free(pub); RSA_free(pri);
  76.             return 1;
  77.         }
  78.         i++;
  79.         if (global_flag) break;
  80.     }
  81.     printf("RSA_verify: %d\n", i);
  82.  
  83.     free(buf); RSA_free(pub); RSA_free(pri);
  84.     return 0;
  85. }

10秒种内 sign/verify 一个长度为 16 位的字符串结果如下:
PIII 700 330/8680
XEON 2.4G 666/17034
XEON 3.0G 799/22633
XEON 5130/2.0G 1053/29154
感觉这样的效率还是不错的,需要在实际系统中进一步小心的验证。

还有就是 openssl 编译优化的问题。为了测试 ECC 的支持,我自己编译了 openssl-0.9.8。结果发现在计算 rsa512 的时候,我编译的 openssl(采取缺省configure) 比系统缺省的 openssl 慢了 10% (470 vs 420)。改了改config,可以提升到 450 左右,后来就没有再仔细琢磨下去。

最后用 openssl 0.9.8d 测试了一下 ECC 的签名校验效率(ECDSA),执行 openssl speed ecdsa (PIII 700)

                              sign    verify    sign/s verify/s
 160 bit ecdsa (secp160r1)  0.0013s   0.0061s    786.1    162.9
 192 bit ecdsa (nistp192)   0.0013s   0.0062s    774.7    160.4
 224 bit ecdsa (nistp224)   0.0016s   0.0079s    616.5    126.4
 256 bit ecdsa (nistp256)   0.0020s   0.0101s    503.8     99.0
 384 bit ecdsa (nistp384)   0.0046s   0.0249s    218.5     40.1
 521 bit ecdsa (nistp521)   0.0097s   0.0519s    103.0     19.3
 163 bit ecdsa (nistk163)   0.0046s   0.0125s    219.8     80.3
 233 bit ecdsa (nistk233)   0.0090s   0.0240s    110.7     41.6
 283 bit ecdsa (nistk283)   0.0140s   0.0447s     71.5     22.4
 409 bit ecdsa (nistk409)   0.0315s   0.1063s     31.7      9.4
 571 bit ecdsa (nistk571)   0.0705s   0.2507s     14.2      4.0
 163 bit ecdsa (nistb163)   0.0046s   0.0133s    218.8     74.9
 233 bit ecdsa (nistb233)   0.0091s   0.0268s    110.3     37.3
 283 bit ecdsa (nistb283)   0.0141s   0.0506s     71.2     19.8
 409 bit ecdsa (nistb409)   0.0316s   0.1224s     31.7      8.2
 571 bit ecdsa (nistb571)   0.0704s   0.2877s     14.2      3.5

签名速度还可以,就是校验速度慢死了..

Topic: 技术

做一个半瓶子 Javascript 程序员

最近项目需要一部分 javascript 代码做 DOM 操作,并且最终是要提供给其他项目调用的。组内的其它同事对 JS 不算精通,虽然 Web 前端开发咱不专业,但好歹有幸和 Lewisrealazy 两位高人同事过,这就叫没吃过猪肉也看过猪跑,于是承担起代码初始编写的任务。

过程很简单:首先是根据需求写了大约 1100 行可以工作的代码,交付给第一个用户 todd,然后俺按照他的建议花了大约1天半的时间把代码改写了一遍,剩下最后的逻辑和界面剥离的任务交给别的同事完成。

以前也用过 javascript,这次才真正以开发产品的目的来写代码。(伪)静态类、函数式编程、闭包这些概念首次接触到,感觉 Javascript 是一门很严肃的程序设计语言,要想掌握或者说精通绝对是一个挑战。具体到 Javascript 在浏览器环境(DOM/HTML)的运行就更需要经验了,好比把 Linux 程序移植到 Solaris 和 AIX,总会在一些细微的地方有什么东西会跳出来捣乱。

假设你已经很熟悉一门开发语言了,由于某些原因需要做一点儿 Javascript/AJAX 开发,那怎么开始呢?

1. 从根本上要重视 Javascript 语言。相比较服务器端主流的 C/C++/Java/PHP 而言,Javascript 属于动态语言(在对 Python/Javascript 有了一些初步了解后,我发现严格上来说 PHP 都不能算动态语言),我认为只有掌握了语言的精髓才能写出好的代码。

2. 需要一个好的调试环境。至少现在为止,Firefox + FireBug 的组合应该是无人可敌的吧。

3. 参考手册。MSDN 和 MDC 上都有很好的在线文档。我个人偏好 MDC,包括 Gecko DOM ReferenceCore JavaScript 1.5 GuideCore JavaScript 1.5 Reference。微软还有一个中文的离线文档 jscript5.chm,似乎是随着 Office 2000 一起安装的,网上很多地方提供下载。

4. 学习别人的代码。prototype 是一个很好的起点。

今天刚刚发现一个更简单的代码集合,里面包括"$ function, getElementsByClassName, event handling, the JS 1.6 array methods, and the DOMContentLoaded event",如果 prototype 看的头大,可以先把这个看明白再说。

除了 prototype 外,JQuery 偏重于 DOM/CSS 特效,被视为 prototype 有力的竞争对手。

5. 补充读物。推荐 deanppk 的 blog。

成为一个 JS 半瓶子程序员并不是太难达到的目标。:)

Topic: 技术

非常时期下载 sf 软件的方法

已经 2 天了,连接国外死慢死慢,估计这样的日子还要持续一段时间。今天发现了一个速度还不错的 sourceforge 的 mirror,这里推荐一下。

首先要知道项目名,比如 abc123,那么它的 mirror 地址为

http://ftp3.ie.freebsd.org/pub/sourceforge/a/ab/abc123/?C=M;O=D

后面的 C=M;O=D 表示文件列表的顺序为日期最新的排在前面,加快查询速度,呵呵。

比如,FileZilla 就可以从这个地址找到

http://ftp3.ie.freebsd.org/pub/sourceforge/f/fi/filezilla/?C=M;O=D

Topic: 技术
订阅 RSS - 技术 | BT的花