技术

Python 的一个 TypeError: unbound method ... 问题

碰到这个问题的时候,网上找到最接近的案例是 http://mail.python.org/pipermail/python-list/2002-July/154968.html, 可惜没有下文。后来在 http://www.nabble.com/TypeError-in-base-class-__init__-after-reload-td15058502.html 的帮助下找到了原因。

不太好描述,写具体例子吧,一共需要三个 py 文件:
module1.py

  1. class Super:
  2.     def __init__(self):
  3.         pass

module2.py

  1. import module1
  2.  
  3. class Sub(module1.Super):
  4.     def __init__(self):
  5.         module1.Super.__init__(self)

run.py

  1. from imp import load_source
  2.  
  3. x = load_source("module2", "module2.py")
  4. #load_source("module1", "module1.py")
  5. print x.Sub()

这三个文件放在同一个目录下,然后运行 run.py,结果看起来很好;但如果我们去掉 run.py 里面的那个注释,就得到错误:
TypeError: unbound method __init__() must be called with Super instance as first argument (got Sub instance instead)

用人家的解释就是:there are some real problems with reloading modules when you have references to objects in the module object. The module is reloaded but the references are not automatically rebound to the new module.

当应用需要从一个目录下 import 所有的模块的时候,如果忘了这个依赖问题,就可能出错了;而且这个错误和遍历目录获得的文件顺序有关,有可能在开发环境下好好的,但部署到生产系统后问题才暴露。切记切记

Topic: 技术

如何用 nginx 做 postfix 的 SMTP 反向代理,以及 XCLIENT 的支持

作为 lighttpd 的竞争者,轻量级web服务器 nginx 最近才开始崭露头角,知道它还可以用来做 pop3/imap4 反向代理的估计就比较少了,至于用 nginx 做 smtp 的反向代理,估计全中国现在和我一样想到这个需求的人一只手就能数过来。

需要 smtp 反向代理是因为我们的 vip 邮箱是可以免费试用的,希望在策略上对已交费用户和免费试用用户(其中有相当部分是 spammer)做出不同处理。前面用 nginx 把不同的用户请求代理到后台不同的 postfix 上,然后 postfix 再各自配置不同的 Milter Server 做过滤。另外需要前台能支持 XCLIENT,这样 postfix/milter 可以得到客户端的 IP,对于 anti-spam 来说是很有意义的。

nginx 在大约一年前增加了对 XCLIENT 的支持,对于 webmail 服务来说,nginx 可以说是再完美不过的反向代理前台了。

nginx 配置 smtp 反向代理需要在配置文件里加这么一段:

mail {
    auth_http http://127.0.0.1/auth;
    server {
        listen 26;
        protocol smtp;
        proxy on;
        smtp_auth login plain;
    }
}

用 python 写一个简单的 auth 服务来做测试:

  1. import SimpleHTTPServer
  2.  
  3. class handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
  4.     def do_GET(self):
  5.         if (self.path == '/auth'):
  6.             # verify 'Auth-User', 'Auth-Pass', 'Client-IP'
  7.             if self.headers.get('Auth-Protocol') == 'smtp':
  8.                 self.send_response(200)
  9.                 self.send_header("Auth-Status", "OK");
  10.                 self.send_header("Auth-Server", "127.0.0.1");
  11.                 self.send_header("Auth-Port", "25");
  12.                 self.end_headers()
  13.                 return
  14.  
  15. addr = ('', 80)
  16. httpd = SimpleHTTPServer.BaseHTTPServer.HTTPServer(addr, handler)
  17. httpd.serve_forever()

修改 postfix 的 main.cf 配置,允许 nginx 代理服务器发送 XCLIENT 命令。

smtpd_authorized_xclient_hosts = 127.0.0.0/8

理论来说,到这里就应该就都配置好了。但是 nginx 会带上一个 LOGIN=foobar 的属性发给后台,而 postfix 是不支持该属性的,这将导致 postfix 报告一个 Bad XCLIENT attribute name: LOGIN 的 501 错误。很疑惑当初贡献这段代码的人是用什么 smtp server 做后台的,总之和 postfix 配合的话,必须修改 nginx 的程序(比修改 postfix 要简单些): 找到 src/mail/ngx_mail_proxy_module.c 里 "case ngx_smtp_helo:" 的那一部分,把和 "LOGIN" 相关的代码去掉就好了

附:最后决定利用周末时间写一个 patch,希望会被 nginx 接纳.
nginx-0.5.35-xclient.patch

json-py、simplejson、cjson

最开始我们的 web 项目的时候,因为 json-py 最易使用——只有一个独立的文件,无需安装,放在开发目录下直接 import 即可,而且当时我醉心于 pure python 的概念,所以就这么一直用下来。

直到上周对代码做压力测试,某个流程中 json encoder 的时间居然耗掉了整整 1/3,而这个流程是最常用的功能之一,于是就寻找 json-py 的替代物。

首先想到的是 simplejson。由于 django 的内置,它可能是 python 界用得最广泛的 json 库了,而且其最新版本还包括了一个 c 的扩展以提高性能。一开始我也是对它寄予厚望,但 profiling 结果很让人郁闷:它的 decode 速度的确是比 json-py 快了不少(大概速度是3倍),但 encode 速度提升及其有限。

最后只好选择了 cjson,效率非常让人满意。
但接口友好程度就比上面两个差远了:一方面是 encode 对非 unicode 的数据类型支持不太好(比如 UTF-8 字符串里高8位字符都escape),我们只好把数据统统 str.decode('utf-8') 一下后再交给它;另一方面是它对中文 unicode 字符串的 decode 实现好像也是有问题,不过还好能想恶心办法绕过去。

结论:cjson效率最好,但兼容性一般;通常来说 simplejson 可能就足够了;如果不是 js 端会传来海量数据要 decode,json-py 也可以将就用,而且就一个文件,简单易import

附:写到本文的时候,发现一个叫 demjson 的项目四个月前刚发布新版本,而且号称自己是最快的纯python解决方案,也是一个文件就可用,看来值得一试。
而且为什么有了 _speedups.c 的 simplejson 速度和 json-py 比起来差别不大,也挺让人疑惑,啥时候有时间再重新测试看看。

Topic: 技术

一周大事记

最重要的当然就是 IE8 beta1 的发布
本来不想尝鲜的,但发布第二天就有人在论坛上反馈 IE8 无法使用搜狐通行证。无奈装一个看看,最后发现是 IE8 beta1 的 bug——table Element 里面的 rows 无法访问,然后去报 bug 的地方看了看,有另外几例相关的bug报告。

不过 IE8 缺省带的 Development Tools 还不错,调试 CSS/JS 功能已经很齐全了。

和 IE8 beta1 呼应的是,firefox3 升级到了 beta5pre,beta4下周应该就发布了吧

第二重要的事情是:AOL 开放了它的 IM 协议

第三:Google 开放它的 Contact API

第四:iphone SDK

Topic: 商业 技术

我的 dd-wrt 可以 PPPoE 了

上回说到刚买的 DELL 2300 无线路由无法拨 ADSL,只能让ADSL Modem自己拨号然后配静态路由。但这种模式下设置端口转发实在不爽,于是这两天晚上又开始琢磨怎么让路由用上 PPPoE

最后在 Setup->MAC Address Clone 里面,把 WAN 口的 MAC 地址改成我笔记本网卡的地址,拨号就成功了。后来看恩山论坛也有人说起北京网通在封杀某些 MAC。仔细一想也容易实现,因为厂商可以用什么 MAC 地址都是在 IEEE OUI 注册的,把那些生产路由器的厂商的 MAC 全都封杀掉并不太难。

另外就是不知道装了什么软件或动了什么配置之后,Vista 突然无法浏览大部分网站了,IE 和 Firefox 都是如此,只能打开 www.google.cn 等几个有限的网站,可另外的 R51e/WinXP 就一点事也没有。估计是 Vista 自己的问题,就去网上搜。后来在注册表里把 MTU 的值改小到 1300 就好了——1300 是 XP 缺省的 MTU 值,不知道出于什么考虑 Vista 把缺省值改成了 1500。

Topic: 技术

FreeBSD 7.0 release

7.0 的新特性里令人感兴趣的包括
* 运行数据库效能提升... 目标当然是直指 Linux/MySQL 组合啦,号称快 15%【注:这样的效率提升可能是在4个甚至8个CPU以上的系统里测试得来的】
* ULE 调度器看起来真正可用了... 虽然当初从 5.x 就开始打广告
* ZFS... 貌似是所有文件系统的终结者
* 系统 malloc 系统调用采用jemalloc,号称为多处理器多线程优化,而且传统的 malloc 是为内存有限的资源环境设计的... 另外 firefox 3 也将改用 jemalloc

* auto-sizing of TCP socket buffers、TSO (TCP/IP segmentation offload)、LRO (Large Receive Offload)、sendfile(2) 优化... 等等网络方面一系列改进

除了上述对服务器来说很有意思的改进外,可能还有人会关注诸如虚拟化、BPF Just-In-Time compiler 等变化

传闻即使是一向是"Not Invented Here Syndrome"的 cisco,也开始随同 Netapp、Juniper 的步伐开始派工程师加入到 FreeBSD 的开发中去

写着写着就想到我们这种有几百台服务器的应用,其实操作系统本身并不是瓶颈,但需要有一个人(或一个小组)专门来管理我们的应用需要跑在什么样的环境上,怎样去部署,怎样根据需求去升级或者是跟随安全更新打补丁,保证生产环境和开发测试环境的一致性。。。
现在实际情况是从 FreeBSD、RedHat 9、RHEL3、RHEL4 ... 相当的不一致,苦闷啊。。。

总之,rpm 是不太符合我们需求的,包装的 apt 服务也就那么回事,还是 ports 好啊

Topic: 技术

俺的一线研发经理起步生涯

有朋友刚刚从程序员提升到经理,面对这次角色变换他有些困扰,毕竟要自我发展出新的技巧去处理新的问题。我仔细回忆 8 年前我的菜鸟经理起步过程,然后在 MSN 上给他建议:每天一会(daily meeting)

99 年 12 月,我刚刚满 22 岁,没有任何管理经验(准确的说我在 21 岁之前几乎是可以用宅男来形容),拿现在的眼光看甚至还不能算得上一个好程序员。但受某种野心的驱使,我受命领导 4 名更加没有经验的程序员(大三的学生)去进行一个软件项目——该项目最初的代码是在地球的另外一端进行的,没有面对面的代码交接,只是有那么一点儿文档;雇佣方担心我们经验不够,于是还另外从清华大学找了个靠谱的人每周来一次天津指导我们工作;我、指导者、原始开发者也就是架构设计者仅仅是通过 smth bbs 上的站内信件和消息进行日常沟通。

还要加一个限定条件:除了那四个大三学生,我当时也是 part time 做这份经理工作。怎么看怎么会是一个注定失败的软件项目,但该项目在 2000 年 4 月份上线,这就是 eyou.com;而我们最后成功的形成了一个胶冻团队,"邱哥"的称呼就是从那时候开始的。

那么想想能够值得别人借鉴的经验吧:

* 热情。经验不是问题,能力不是问题,兼职工作也不是问题,是那种迫切希望在某个领域取得成功的欲望支持我克服了许多困难,并给团队其他人增加信心。一开始我没有意识到这点,直到 2001 年初,老板让每个员工用一个英文单词来表达自己,我才从自己身上找到 passion,而不是什么 smart、friendly...之类。无独有偶,伟大的 Joel,还有其他人也是这么认为的

* daily meeting。由于这个项目的特殊性,使得我必须每天和这四个小伙子开会讨论最新的进度和碰到的问题,而他们也很乐意跟我吃一顿免费的晚饭。团队就是在会议讨论和聚餐中形成的;我也慢慢形成了和下属打交道的风格,并巩固了这种工作上人际交往的自信。

不过也是直到这次有人问起,我才感到 daily meeting 的重要性。尤其是对只专注在一个项目(或者说虽然多个项目但是同一个业务领域)上的团队来说,daily meeting 就更切合实际了——团队所有人都清楚的知道别人在进行什么工作,碰到什么难题以及可能解决的方向。

* daily code review。回忆中最让人惊奇的是,我们居然一直在做 code review,虽然这也是因为项目的特殊性导致的——大家都不在一起工作,而且代码迟迟不能组装到一起,所以我必须一个模块一个模块的检查,当场编译和修改。在这个过程中,不仅仅是我一个人在看那个倒霉家伙的代码,Toshiba 笔记本屏幕旁边还有另外三个脑袋也在研究。

由于 code review,我们的 daily meeting 大大超过了半小时(Scrum 的建议上限),但如果团队规模比较小,每天花一个小时做这项工作是完全没有问题的(假设一个程序员的生产力是 300 行/日,花 10-15 分钟做 review)。

这种每日的团体代码评审可能真的是个好主意:每个程序员每天都要训练如何向大家发表自己的意见;虽然没有 pair programming,但我们很快彼此熟悉代码风格,学习最酷的 shell 和编辑器命令技巧;大家对彼此的工作更加了如指掌;的确可能有人会打哈欠,但注意观察那些对别人的代码也满怀好奇的程序员,他们将会是日后你的好帮手。

写到这里,我决定给我所有的一线经理都申请笔记本,不过好像要等到下半年预算了——搜狐在很多方面都可担得上十佳雇主的称号,但在提高员工生产率方面稍微僵化了一点点。

* 每日集体午餐。如果做不到每日集体代码评审,那这个就是最低要求了。

==========这是华丽的分隔线========

* daily blog。上面的这些为什么我没能早些总结出来?每日三省吾身很重要啊..hehe

Update:
* 更新了一张来自 http://martinfowler.com/articles/itsNotJustStandingUp.html 的照片
* 另外有人说我们的座位都靠在一起,每日例会还需要到会议室去开吗?我的直觉是:需要,一定要有一个正式的会议形式,Same Place, Same Time——而且每天早上 9:00-10:00 有大把空闲的会议室可用。

Topic: 商业 技术

入手 DELL Truemobile 2300

从 lifehacker 一个耸人听闻的标题 "Turn your $60 router into a $600 router" 里看到 dd-wrt 的——本来是 Linksys/CISCO 源于 Linux 给其无线路由器开发的软件,迫于社区压力(诉讼威胁)公开源代码,从而分支出来的一个开源项目。号称比厂商原有的功能强大了不是一点半点,什么无线中继、调整信号发射功率、ssh login、vpn...当时心向往之,年后终于家里需要更换原来的无线路由了,于是就策划去买一个支持刷 dd-wrt 的回来玩。

经过一段时间潜水,得出结论目前市场上最便宜的支持刷机的无线路由就是这个 DELL 2300。然后上淘宝搜索,找了个北京卖家拍下(加上运费也就合美元 25$ 左右)

该机器出货前就已经刷成了"Firmware: DD-WRT v24 Beta (05/16/07) std",但一用就傻眼了,死活无法让路由器去 ADSL/PPPoE 拨号。google 之,确实有不少人反映 dd-wrt 的某些版本 PPPoE 是有问题的,解决方案通常是刷别的版本,同时关于 2300 容易刷成砖的传说也在广泛流传,比如康神前不久就中过一次招。

思来想去,实在忍不住刷固件的诱惑把它刷到了最新的 v24 RC6.2 std,居然还真就能拨号了,大喜之下继续设置,加了一个 Wireless MAC accesslist,结果拨号就再也无法起作用了,即使把设置改回以前也还是不能拨号。基于以上过程,俺认定无法拨号是某些配置有误导致,于是决定恢复出厂设置...
然后路由器无法进行 WEB-UI 管理了,任何 POST apply.cgi 操作都会直接返回一个空白页面,

在页面上点了好久...空白如故...难道我也荣幸的成为一名砖家?

判断WEB的操作故障应该是无法写入新设置导致的。此时 2300 还是可以 telnet 上去。于是登陆上去后用 nvram write 命令配置了某个参数,然后 commit,reboot... 重启后总算恢复了正常,又可以在浏览器里操作了。

不过我再也不敢做别的出格的尝试了,只好把 WAN 口配成静态 IP,让 ADSL 猫去自动拨号。就又去查 KM300A ADSL modom 缺省口令是什么,怎么去配置自动拨号......前前后后折腾了一晚上,现在总算能无线上网了。

没来得及测试,比如用 eMule 连续下载个三天三夜什么的。但就目前来看,DELL 2300 + dd-wrt 还是挺值得推荐的,毕竟性价比放在这里呢,虽然我实在怀疑这批2300里面的部件其实是二手货。

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