July 2012

入手 rMBP 的第一天

Retina MacBook Pro ,只能说太帅了,哈哈

我机器拿到手,到完全可用,大概花了 4 个小时吧,从旧的 MBP 基本整个完全 copy 过来,这个时间还好啦。过程中有点小折腾,有些地方不知道具体原因,就不特意去重现了,就当 mark 下我的过程吧。

1)预计好我的到货时间,这几天我每天都在 Time Machine 。但有时候很奇怪,我两小时的使用中,也就上上网,vim 一下,竟然一次 Time Machine 要备份 2G 的东西。。。

2)机器到手!开机!经过简单的设置后,选择 restore from time machine ,企图从我昨晚的备份恢复进去新的 rMBP 中。

3)TM 的恢复时间,139G 左右的数据,恢复耗时 2.5 小时,属于可接受的正常范围。

4)正常开机,发现我的账号密码一直提示不正确。。。准备重启进入单用户模式修改密码

5)重启进入 single user mode ( 开机过程按 command + s ) ,并输入以下命令才可以正常修改密码

mount -uw /

launchctl load /System/Library/LaunchDaemons/com.apple.opendirectoryd.plist ( 如不执行这句,会爆  The daemon encountered an error processing request. 的错误)

然后就可以正常地 passwd [username] 来修改密码了

6)终于进入系统,但发现,系统竟然还是 10.7.4 ,我的旧系统已经是 10.8 了。这里我怀疑是,TM 并不会把系统也恢复进去。。。

7)重新安装 MountainLion ,及其相关的一些软件。如 command line tools for xcode , java run time , iwork , imovie 等等等。

8)最后,终于可以使用了!TM 唯一没有成功恢复进来的软件是 ClipMenu.app (失败的日志它会放在 Desktop 上),重装一下就好。基本和我原来的系统差不多了!

 

从第 4 点开始出乎我意料地不正常,导致我又花了点时间去折腾好。

 

作为敝司第一台 15” 的 MacBook ,兼第一台 rMBP ,我决定发一张工作桌面照

工作桌面

广告时间,我正在出手我的旧 MBP :http://v2ex.com/t/43849

2.6.29 – 2.6.39 之间的 kernel 不要在 LVS Director 的网卡开启 GRO

我之前开发了一个传图系统,直接使用了 @agentzh 的 lua_resty_upload (其实这里不应该用 nginx_lua 做的),但发现其在 LVS 下,POST 请求总是 socket timeout ,而直接 POST 到 real server 没有问题。无奈我当时只好用 DNS 轮训的方式,终于在最近找到原因了。

Linux 在 2.6.29 的时候,引入了一个 GRO (Generic receive offload) 。

MTU 一般都是 1500 字节,如果一个包超过了 MTU ,就会被分片。1500 这个数字,估计是基于当时的网络环境制定的,而现在,10Gbps 的网卡都普遍使用了,可能就不太适用了。如果 10Gbps 的网卡满载地来跑,一个完整的数据包会被分片 800w 片。我们可以通过调整 client 和 server 端的 MTU 令到分片尽可能减少,提高吞吐量。但是,如果 client 端(例如用户)不受我们控制呢,那我们就无法提高性能了。于是有人想到通过网卡的行为来间接实现相当于提高 MTU 的作用,这就是 GRO [1] 。

GRO 就是在网卡中将满足一定的条件(比较严格)的包,将分片的包组装合并了,才一次性交给上面的协议栈。现在的网卡一般都支持了,除了网卡支持,还要驱动也支持才可以。如果网卡和驱动都支持,那么在 2.6.29 以后的 kernel ,都会默认开启。

ethtool -k eth0 ,来查看是否有 generic-receive-offload: on ,如果是 off ,也不一定是不支持,可以通过 ethtool -K eth0 gro on 来尝试开启。

但是 GRO 和 LVS 协作得并不好,具体表现就是,POST 数据到 LVS 很慢。

抓包看我的 POST 请求,握手阶段用了较长时间,出现了数次 incorrect 后才真正开始传输。POST 小于 MTU 的数据,并不会触发这个问题,而 POST 大于 MTU 的数据,就会。证明了这里肯定是 GRO 惹的祸。

没有 google 到最根本的原因,但也有一些说法 [2] ,就是 GRO 和 LVS 之间的兼容没有做好,知道 2.6.39 已经修复了这个问题。

经验主义一点,就是 LVS 的 director 一律关闭网卡的 GRO 。

ethtool -K eth0 gro off

这个情况我遇到的,一般发生在内网 POST 的时候,而用户 POST 给我的情况太慢的不太多,也有可能是他们网络根本就慢,手机的网络环境变数太多,而我暂时也没有办法把他们过滤出来一一查看。我猜想,是因为内网的网络环境正好符合了 GRO 的 merge 的条件,GRO 起作用了,所以我的 POST 很慢。而用户的请求不符合条件,所以还是比较正常的。

 

 

Reference:

[1] http://lwn.net/Articles/358910/

[2] http://archive.linuxvirtualserver.org/html/lvs-users/2011-05/msg00004.html

几个关于 python package (objc , PIL )的 bug

最近在处理一个图片需求的时候,竟然遇到数个几年了都没人修正的 bug。。。这个过程值得记录一下。。。

原始需求是这样的:

首先,是用一个 ImageAlpha 的 app ,这个 app 其实做得不错的,但是因为基于 GUI ,如果我要处理 1000 张图片,那会累死人的

但是。。。这个 app 竟然还不能直接使用,需要安装 pyobjc ,至少在我的 MacOSX 上需要安装。

1)第一个 bug ,pip 安装 pyobjc

pip install pyobjc

报错:

 
Downloading/unpacking PyObjC
 
Running setup.py egg_info for package PyObjC
 
Downloading/unpacking pyobjc-core==2.3 (from PyObjC)
 
Running setup.py egg_info for package pyobjc-core
 
/usr/local/Cellar/python/2.7.2/lib/python2.7/distutils/dist.py:267: UserWarning: Unknown distribution option: 'use_2to3'
 
warnings.warn(msg)
 
Traceback (most recent call last):
 
File "", line 14, in
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/trashcli/build/pyobjc-core/setup.py", line 452, in
 
**extra_args
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/distutils/core.py", line 152, in setup
 
dist.run_commands()
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/distutils/dist.py", line 953, in run_commands
 
self.run_command(cmd)
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/distutils/dist.py", line 972, in run_command
 
cmd_obj.run()
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/trashcli/build/pyobjc-core/setup.py", line 110, in run
 
orig_egg_info.egg_info.run(self)
 
File "", line 7, in replacement_run
 
AttributeError: class egg_info has no attribute 'iter_entry_points'
 
Complete output from command python setup.py egg_info:
 
/usr/local/Cellar/python/2.7.2/lib/python2.7/distutils/dist.py:267: UserWarning: Unknown distribution option: 'use_2to3'
 
warnings.warn(msg)
 
running egg_info
 
Traceback (most recent call last):
 
File "", line 14, in
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/trashcli/build/pyobjc-core/setup.py", line 452, in
 
**extra_args
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/distutils/core.py", line 152, in setup
 
dist.run_commands()
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/distutils/dist.py", line 953, in run_commands
 
self.run_command(cmd)
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/distutils/dist.py", line 972, in run_command
 
cmd_obj.run()
 
File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/trashcli/build/pyobjc-core/setup.py", line 110, in run
 
orig_egg_info.egg_info.run(self)
 
File "", line 7, in replacement_run
 
AttributeError: class egg_info has no attribute 'iter_entry_points'

参考 [1] , [2] 才能完整解决

1、pip 安装失败后,会在当前目录有 build 目录,修改 setup.py 文件,build/pyobjc-core/setup.py

use_2to3 = True   =>    use_2to3 = False

2、chmod 执行权限

chmod a+x build/pyobjc-core/libxml2-src/configure
chmod a+x build/pyobjc-core/libxml2-src/install-sh

3、export MACOSX_DEPLOYMENT_TARGET=10.5 (我也不知道为什么要声明这个系统变量)

4、python build/pyobjc-core/setup.py install ,就可以把 pyobjc-core 安装上了,然后再 pip install pyobjc ,会安装其它的一些包

 

但我不喜欢用 GUI ,我相信用几行 python 就能解决,于是我用 PIL ,并参考 [3] ,但文章中的函数并不能正常运行,原文如下:

from PIL import Image
 
im = Image.open('mouse.png')
# Get the alpha band
alpha = im.split()[3]
# Convert the image into P mode but only use 255 colors in the palette out of 256
im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
# Set all pixel values below 128 to 255,
# and the rest to 0
mask = Image.eval(alpha, lambda a: 255 if a <=128 else 0)
# Paste the color of index 255 and use alpha as a mask
im.paste(255, mask)
# The transparency index is 255
im.save('mouse.gif', transparency=255)

会报错:

python pil ‘NoneType’ object has no attribute ‘bands’

2)以上就是第二个 bug … 两个解决方法

1、参考 [4] ,在调用 im.split() 前,先 im.getdata() 一下,如下

from PIL import Image
 
im = Image.open('mouse.png')
# Get the alpha band
 
im.getdata()
 
alpha = im.split()[3]
# Convert the image into P mode but only use 255 colors in the palette out of 256
im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
# Set all pixel values below 128 to 255,
# and the rest to 0
mask = Image.eval(alpha, lambda a: 255 if a <=128 else 0)
# Paste the color of index 255 and use alpha as a mask
im.paste(255, mask)
# The transparency index is 255
im.save('mouse.gif', transparency=255)

2、fix 了这个 bug 的 patch ,在这里 [5] http://hg.effbot.org/pil-2009-raclette/changeset/fb7ce579f5f9

 

为了处理 1k 张图片。。。真折腾。。。还以为我需要把 ImageAlpha 的函数抽出来了,它是用 python 调用 objective-c 的接口来做的。

 

Reference:

[1] https://github.com/pypa/pip/issues/11#issuecomment-6485553

[2] http://www.slevenbits.com/2012/05/installing-pyobjc-in-virtualenv-on-mac-os-x-10-7

[3] http://nadiana.com/pil-tips-converting-png-gif

[4] http://bugs.python.org/issue9383

[5] http://hg.effbot.org/pil-2009-raclette/changeset/fb7ce579f5f9