Tornado HTTPServer

Tornado 官方文档和源代码中的几个例子都是运行在单进程模式的, 但是一样可以很简单地运行在多进程模式下。

参看:Tornado: 2. 源码分析 (2)

文章中虽然分析的是 0.2 版本的代码, 但是直到现在最新的 1.2.1 版本中,这些内容也基本没变。

httpserver.py:

If num_processes is None or <= 0, we detect the number of cores available on this machine and fork that number of child processes. If num_processes is given and > 1, we fork that specific number of sub-processes.

没有测试过多进程模式下的性能和稳定性。

Tornado 官方文档: Tornado Web Server Document 官方文档的中文翻译: python_Tornado文档翻译

官方文档中并没有提到使用多进程模式运行 Tornado 实例, 而是提出:

We ran 4 single-threaded Tornado frontends behind an nginx reverse proxy, which is how we recommend running Tornado in production (our load test machine had four cores, and we recommend 1 frontend per core).

整篇文档完全没有提及 pre-forking .

估计是因为: (httpserver.py)

Since we use processes and not threads, there is no shared memory between any server code.

所以在官方文档中提及的使用 "1 frontend per core" 的部署方式, 在性能和资源消耗上应该是和 pre-forking 没什么差别的?

而分别在 nginx 后部署多个 Tornado 单进程实例也还是有些好处的, 比如可以自己控制单进程实例的数量。

Python 中 List Comprehensions 的陷阱?

使用 Python 版本: 2.6.6

对于 List Comprehensions 中涉及到的变量,将会修改上下文相同的变量 ::

>>> user_name = "zhangkc"
>>> users = [user_name for user_name in ["zhangkc", "lixc", "caoxj"]]
>>> user_name
'caoxj'

update on 2011,04,21

其实在遇到这个问题的时候的两天后就看到有位外国技术人员在 PyCon 上的相关发布:

PyCon: Cooking with Python 3

其中写道:

If you write "[x * x for x in nums]; print x", x won't be in scope. This is a bit surprising.

在 Python 3.1 和 Python 3.2 解释器中测试过了,果然在 Python 3 中已去掉了这个“陷阱”。


update on 2012,09,16

嗯,这是 Python 早期的一个设计上的问题。在: From List Comprehensions to Generator Expressions 上有记载,解释了早期之所以这样设计的原因:

This was an artifact of the original implementation of list comprehensions; it was one of Python's "dirty little secrets" for years. It started out as an intentional compromise to make list comprehensions blindingly fast, and while it was not a common pitfall for beginners, it definitely stung people occasionally.

一道简单的笔试题:打印一个菱形

这是一道简单的笔试题,然而还是花了我一些时间。 暂时是这个粗糙的样子:

#!/usr/bin/env python2

__author__ = "zhangkaizhao <zhangkaizhao@gmail.com>"

def print_lozenge(xnum):
    alen = xnum * 2 - 1
    for i in range(alen):
        if i % 2:
            print " "
        else:
            start = (i < xnum) and (xnum - 1 - i) or (i - xnum + 1)
            end = alen - 1 - start
            xjs = range(start, end + 2, 2)
            print "".join([i in xjs and "X" or " " for i in range(alen)])

if __name__ == "__main__":
    import sys
    args = sys.argv
    if len(args) != 2:
        print "Usage: python print_lozenge.py number"
        sys.exit(1)
    xnum = args[1]
    try:
        xnum = int(xnum)
    except:
        print "number must be an odd number"
        sys.exit(1)
    if not xnum % 2:
        print "number must be an odd number"
        sys.exit(1)
    print_lozenge(xnum)

莫名奇妙的bug - 网易笔试

netease exam - indescribable bug
2011,01,01 深夜

在投了简历大概半个月后, 有一天晚上大概七点左右, 我在亲戚家准备吃晚饭的时候, 意外地接到一个来自网易的电话, 电话邀请我第三天晚上六点半参加笔试。 虽然我感觉很不好,但还是接受了。 最后证明我的这种勉强答应是错误的。 (这种学习华为的做法现在已经让我非常反感了,都累了一天还搞什么?)

第三天,在忙累了一天之后,我比较早下班,虽然我比较早下班,但还是迟到了一小会。 路途还算有点远,虽然同在一个区。

很意外地,一进笔试间就遇到老同事小猪,不过回头一想,也不意外。 既然大家都在埋头做题目了,我也不能打扰。

以为自己还带着笔,没想到由于公司的笔老是被人拿走,自己的笔也就留在了公司。 这让我吃了个亏。

接过试题,一看就傻眼。 第一道题目考C语言的,不熟悉。 第二、第三道题目居然考的是C++语言的模板的,完全不懂。 第四道题目不算是题目。 第五道题目也不算是题目,我没写上什么答案,写的话应该是我现在的这篇文字的标题。 第六道题目要说说自己的游戏经历?让人还以为要抄抄云风的《游戏之旅-我的编程感悟》。

我有些奇怪的是云风的影响力在网易是否小了很多?(指C++)

结果是, 第一道题目找到了错误的位置,strcpy 函数和 printf 函数,但是没有找到错误的原因。窘。 第二、第三道题目的回答非常简单,两个字:不懂。 第四道题目写错了一个 Linux 命令(netstat)。 第五道题目如上所述。 第六道题目就简单提起自己最喜欢的两款PC游戏。

基本上是交了白卷。

笔试完毕,交卷的时候小猪特意问那位负责这次笔试的网易员工是否搞错了题目, 不过并没有得到正确的回答。

这次还真的是莫名其妙,虽然前面三道题目应该很简单, 但是应该不是面对我们的,我们来是想看看 Python 相关的岗位的情况的。 虽然说行者道上的兄弟们相信使用 Python 的码农素质会好些,有钻研精神,爱学习, 但是一个无法改变的事实是,每个人其实都还是比较安于现实,就算是有所追求,也多半没那么快进展。 关于 C++ 的书倒是买了一些,大的小的,几乎每本都只翻了前面大概一百多页,很难继续下去。 也许压力才是增进学习的最佳因素。

所以,最后,这个莫名其妙的 bug 到底是谁产生的,我也有些不莫名其妙了。

Dropbox client

Dropbox client

2010,11,02 zhangkaizhao

dropbox client 版本:0.7.79 winxp

最近在开发类似的项目。 昨晚无聊,想探探这个客户端的内容, 结果发现其实应该非常简单, 整个 dropbox client 完全使用 Python 2.5 开发而成的。

Windows XP 下 Dropbox 默认安装在用户家目录的 Application Data/Dropbox/ 目录下。 主要分析文件:

bin/Dropbox.exe
dropbox.db

主文件 Dropbox.exe

不要被 Dropbox.exe 文件有 20M 大小而吓到, 当你使用解压缩软件查看这个文件的时候, 你将惊奇的发现,这原来不过是一个压缩文件!

$ mkdir /tmp/dropbox.exe
$ 7z x Dropbox.exe -o/tmp/dropbox.exe
$ ls -l /tmp/dropbox.exe

你将看到很多已编译的 .pyc 文件和 .pyd 文件以及动态链接库 .dll 文件:

总用量 10848
drwx------  2 zkc zkc    4096 11月  2 09:27 adodbapi
drwx------  5 zkc zkc    4096 11月  2 09:27 arch
-rw-rw-r--  1 zkc zkc    9121 12月 11 2009 asynchat.pyc
-rw-rw-r--  1 zkc zkc   18417 12月 11 2009 asyncore.pyc
-rw-rw-r--  1 zkc zkc    2209 12月 11 2009 atexit.pyc
-rw-rw-r--  1 zkc zkc   11681 12月 11 2009 base64.pyc
-rw-rw-r--  1 zkc zkc   20785 12月 11 2009 bdb.pyc
-rw-rw-r--  1 zkc zkc    2961 12月 11 2009 bisect.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 build_number
-rw-rw-r--  1 zkc zkc   77824 12月 23 2008 bz2.pyd
-rw-rw-r--  1 zkc zkc   31697 12月 11 2009 calendar.pyc
-rw-rw-r--  1 zkc zkc   35649 12月 11 2009 cgi.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 client_api
-rw-rw-r--  1 zkc zkc   14657 12月 11 2009 cmd.pyc
-rw-rw-r--  1 zkc zkc   37105 12月 11 2009 codecs.pyc
-rw-rw-r--  1 zkc zkc    6977 12月 11 2009 codeop.pyc
-rw-rw-r--  1 zkc zkc   10929 12月 11 2009 code.pyc
-rw-rw-r--  1 zkc zkc   45617 12月 11 2009 commctrl.pyc
-rw-rw-r--  1 zkc zkc   14241 12月 11 2009 common.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 common_util
drwx------  5 zkc zkc    4096 11月  2 09:27 comtypes
-rw-rw-r--  1 zkc zkc    4417 12月 11 2009 contextlib.pyc
-rw-rw-r--  1 zkc zkc   61825 12月 11 2009 cookielib.pyc
-rw-rw-r--  1 zkc zkc   12273 12月 11 2009 copy.pyc
-rw-rw-r--  1 zkc zkc    5569 12月 11 2009 copy_reg.pyc
drwx------  3 zkc zkc    4096 11月  2 09:27 core
-rw-rw-r--  1 zkc zkc    6433 12月 11 2009 cProfile.pyc
drwx------  3 zkc zkc    4096 11月  2 09:27 ctypes
-rw-rw-r--  1 zkc zkc   86016 12月 23 2008 _ctypes.pyd
-rw-rw-r--  1 zkc zkc  160097 12月 11 2009 decimal.pyc
-rw-rw-r--  1 zkc zkc   63585 12月 11 2009 difflib.pyc
-rw-rw-r--  1 zkc zkc    6673 12月 11 2009 dis.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 distutils
-rw-rw-r--  1 zkc zkc   87121 12月 11 2009 doctest.pyc
-rw-rw-r--  1 zkc zkc   18529 12月 11 2009 dropsyncore.pyc
-rw-rw-r--  1 zkc zkc    1393 12月 11 2009 dummy_threading.pyc
-rw-rw-r--  1 zkc zkc    5825 12月 11 2009 dummy_thread.pyc
drwx------  3 zkc zkc    4096 11月  2 09:27 email
drwx------  2 zkc zkc    4096 11月  2 09:27 encodings
-rw-rw-r--  1 zkc zkc    7680  9月 29 2009 _fastdetails.pyd
-rw-rw-r--  1 zkc zkc    8704  9月 29 2009 fastpath.pyd
-rw-rw-r--  1 zkc zkc   10433 12月 11 2009 filecmp.pyc
-rw-rw-r--  1 zkc zkc    3377 12月 11 2009 fnmatch.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 formencode
-rw-rw-r--  1 zkc zkc   29393 12月 11 2009 ftplib.pyc
-rw-rw-r--  1 zkc zkc    1969 12月 11 2009 functools.pyc
-rw-rw-r--  1 zkc zkc    4065 12月 11 2009 __future__.pyc
-rw-rw-r--  1 zkc zkc    7073 12月 11 2009 getopt.pyc
-rw-rw-r--  1 zkc zkc    3537 12月 11 2009 getpass.pyc
-rw-rw-r--  1 zkc zkc   17825 12月 11 2009 gettext.pyc
-rw-rw-r--  1 zkc zkc    2337 12月 11 2009 glob.pyc
-rw-rw-r--  1 zkc zkc    6545 12月 11 2009 gopherlib.pyc
-rw-rw-r--  1 zkc zkc   15809 12月 11 2009 gzip.pyc
-rw-rw-r--  1 zkc zkc    2017 12月 11 2009 hard_trace.pyc
-rw-rw-r--  1 zkc zkc    4385 12月 11 2009 hashlib.pyc
-rw-rw-r--  1 zkc zkc  323584 12月 23 2008 _hashlib.pyd
-rw-rw-r--  1 zkc zkc   11569 12月 11 2009 heapq.pyc
-rw-rw-r--  1 zkc zkc   43425 12月 11 2009 httplib.pyc
-rw-rw-r--  1 zkc zkc   37841 12月 11 2009 inspect.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 installer
-rw-rw-r--  1 zkc zkc    2145 12月 11 2009 keyword.pyc
-rw-rw-r--  1 zkc zkc    3457 12月 11 2009 linecache.pyc
-rw-rw-r--  1 zkc zkc   45185 12月 11 2009 locale.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 logging
-rw-rw-r--  1 zkc zkc    6033 12月 11 2009 _LWPCookieJar.pyc
-rw-rw-r--  1 zkc zkc   10273 12月 11 2009 macpath.pyc
-rw-rw-r--  1 zkc zkc    2945 12月 11 2009 macurl2path.pyc
-rw-rw-r--  1 zkc zkc     225 12月 11 2009 md5.pyc
-rw-rw-r--  1 zkc zkc    8561 12月 11 2009 mimetools.pyc
-rw-rw-r--  1 zkc zkc   17745 12月 11 2009 mimetypes.pyc
-rw-rw-r--  1 zkc zkc   12288  2月 16 2009 mmapfile.pyd
-rw-rw-r--  1 zkc zkc    4769 12月 11 2009 _MozillaCookieJar.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 ncrypt
-rw-rw-r--  1 zkc zkc  909312  9月 29 2009 _ncrypt.pyd
-rw-rw-r--  1 zkc zkc    9265 12月 11 2009 netbios.pyc
-rw-rw-r--  1 zkc zkc     721 12月 11 2009 new.pyc
-rw-rw-r--  1 zkc zkc   12529 12月 11 2009 ntpath.pyc
-rw-rw-r--  1 zkc zkc   22657 12月 11 2009 ntsecuritycon.pyc
-rw-rw-r--  1 zkc zkc    1857 12月 11 2009 nturl2path.pyc
-rw-rw-r--  1 zkc zkc   61505 12月 11 2009 optparse.pyc
-rw-rw-r--  1 zkc zkc   11009 12月 11 2009 os2emxpath.pyc
-rw-rw-r--  1 zkc zkc   26097 12月 11 2009 os.pyc
-rw-rw-r--  1 zkc zkc   45185 12月 11 2009 pdb.pyc
-rw-rw-r--  1 zkc zkc   43185 12月 11 2009 pickle.pyc
-rw-rw-r--  1 zkc zkc   32609 12月 11 2009 platform.pyc
-rw-rw-r--  1 zkc zkc   10641 12月 11 2009 popen2.pyc
-rw-rw-r--  1 zkc zkc   13089 12月 11 2009 posixpath.pyc
-rw-rw-r--  1 zkc zkc   10337 12月 11 2009 pprint.pyc
-rw-rw-r--  1 zkc zkc   26433 12月 11 2009 pstats.pyc
-rw-rw-r--  1 zkc zkc    6737 12月 11 2009 py_compile.pyc
-rw-rw-r--  1 zkc zkc  356352  3月 31 2009 pythoncom25.dll
drwx------  4 zkc zkc    4096 11月  2 09:27 pywin
-rw-rw-r--  1 zkc zkc  122880  2月 16 2009 pywintypes25.dll
-rw-rw-r--  1 zkc zkc    8385 12月 11 2009 Queue.pyc
-rw-rw-r--  1 zkc zkc    7025 12月 11 2009 quopri.pyc
-rw-rw-r--  1 zkc zkc   25617 12月 11 2009 random.pyc
-rw-rw-r--  1 zkc zkc    6017 12月 11 2009 repr.pyc
-rw-rw-r--  1 zkc zkc   13553 12月 11 2009 re.pyc
-rw-rw-r--  1 zkc zkc   34273 12月 11 2009 rfc822.pyc
-rw-rw-r--  1 zkc zkc    7680 12月 23 2008 select.pyd
-rw-rw-r--  1 zkc zkc   20257 12月 11 2009 sets.pyc
-rw-rw-r--  1 zkc zkc     257 12月 11 2009 sha.pyc
-rw-rw-r--  1 zkc zkc    8289 12月 11 2009 shlex.pyc
-rw-rw-r--  1 zkc zkc    7553 12月 11 2009 shutil.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 simplejson
-rw-rw-r--  1 zkc zkc   42577 12月 11 2009 socket.pyc
-rw-rw-r--  1 zkc zkc   53248 12月 23 2008 _socket.pyd
-rw-rw-r--  1 zkc zkc   24576  9月 29 2009 _speedups.pyd
drwx------  2 zkc zkc    4096 11月  2 09:27 sqlite3
-rw-rw-r--  1 zkc zkc  514570 10月 14 2009 sqlite3.dll
-rw-rw-r--  1 zkc zkc   53248 10月 16 2009 _sqlite3.pyd
drwx------ 10 zkc zkc    4096 11月  2 09:27 sqlobject
-rw-rw-r--  1 zkc zkc   12417 12月 11 2009 sre_compile.pyc
-rw-rw-r--  1 zkc zkc    6161 12月 11 2009 sre_constants.pyc
-rw-rw-r--  1 zkc zkc   21601 12月 11 2009 sre_parse.pyc
-rw-rw-r--  1 zkc zkc     513 12月 11 2009 sre.pyc
-rw-rw-r--  1 zkc zkc  663552 10月 16 2009 _ssl.pyd
-rw-rw-r--  1 zkc zkc    2625 12月 11 2009 stat.pyc
-rw-rw-r--  1 zkc zkc   12177 12月 11 2009 StringIO.pyc
-rw-rw-r--  1 zkc zkc   16353 12月 11 2009 stringprep.pyc
-rw-rw-r--  1 zkc zkc   17841 12月 11 2009 string.pyc
-rw-rw-r--  1 zkc zkc   15713 12月 11 2009 _strptime.pyc
-rw-rw-r--  1 zkc zkc    3841 12月 11 2009 struct.pyc
-rw-rw-r--  1 zkc zkc   33873 12月 11 2009 subprocess.pyc
-rw-rw-r--  1 zkc zkc   70881 12月 11 2009 tarfile.pyc
-rw-rw-r--  1 zkc zkc   16113 12月 11 2009 tempfile.pyc
-rw-rw-r--  1 zkc zkc   11505 12月 11 2009 textwrap.pyc
-rw-rw-r--  1 zkc zkc    6849 12月 11 2009 _threading_local.pyc
-rw-rw-r--  1 zkc zkc   30913 12月 11 2009 threading.pyc
-rw-rw-r--  1 zkc zkc   11953 12月 11 2009 tokenize.pyc
-rw-rw-r--  1 zkc zkc    3857 12月 11 2009 token.pyc
-rw-rw-r--  1 zkc zkc   12641 12月 11 2009 traceback.pyc
-rw-rw-r--  1 zkc zkc    1313 12月 11 2009 trace_report.pyc
-rw-rw-r--  1 zkc zkc    2705 12月 11 2009 types.pyc
drwx------  2 zkc zkc    4096 11月  2 09:27 ui
-rw-rw-r--  1 zkc zkc  479232 12月 23 2008 unicodedata.pyd
-rw-rw-r--  1 zkc zkc   36929 12月 11 2009 unittest.pyc
-rw-rw-r--  1 zkc zkc   51073 12月 11 2009 urllib2.pyc
-rw-rw-r--  1 zkc zkc   54977 12月 11 2009 urllib.pyc
-rw-rw-r--  1 zkc zkc   13281 12月 11 2009 urlparse.pyc
-rw-rw-r--  1 zkc zkc    9761 12月 11 2009 UserDict.pyc
-rw-rw-r--  1 zkc zkc   22305 12月 11 2009 uuid.pyc
-rw-rw-r--  1 zkc zkc    4433 12月 11 2009 uu.pyc
-rw-rw-r--  1 zkc zkc    8993 12月 11 2009 warnings.pyc
-rw-rw-r--  1 zkc zkc   14737 12月 11 2009 weakref.pyc
-rw-rw-r--  1 zkc zkc   21041 12月 11 2009 webbrowser.pyc
-rw-rw-r--  1 zkc zkc   98304  3月 31 2009 win32api.pyd
-rw-rw-r--  1 zkc zkc   14848  3月 31 2009 win32clipboard.pyd
drwx------  5 zkc zkc    4096 11月  2 09:27 win32com
-rw-rw-r--  1 zkc zkc  140577 12月 11 2009 win32con.pyc
-rw-rw-r--  1 zkc zkc   14848  3月 31 2009 win32event.pyd
-rw-rw-r--  1 zkc zkc  114688  3月 31 2009 win32file.pyd
-rw-rw-r--  1 zkc zkc  159744  3月 31 2009 win32gui.pyd
-rw-rw-r--  1 zkc zkc   22865 12月 11 2009 win32gui_struct.pyc
-rw-rw-r--  1 zkc zkc   20992  3月 31 2009 win32pipe.pyd
-rw-rw-r--  1 zkc zkc   45056  3月 31 2009 win32process.pyd
-rw-rw-r--  1 zkc zkc   13824  2月 16 2009 win32profile.pyd
-rw-rw-r--  1 zkc zkc  114688  3月 31 2009 win32security.pyd
-rw-rw-r--  1 zkc zkc    5632  3月 31 2009 _win32sysloader.pyd
-rw-rw-r--  1 zkc zkc   19456  3月 31 2009 win32ts.pyd
-rw-rw-r--  1 zkc zkc  761856  3月 31 2009 win32ui.pyd
-rw-rw-r--  1 zkc zkc   20480  2月 16 2009 win32wnet.pyd
-rw-rw-r--  1 zkc zkc  113345 12月 11 2009 winerror.pyc
-rw-rw-r--  1 zkc zkc  176128  3月 31 2009 winxpgui.pyd
drwx------  3 zkc zkc    4096 11月  2 09:27 wx
-rw-rw-r--  1 zkc zkc 3096576  9月 29 2009 wxmsw28uh_vc.dll
-rw-rw-r--  1 zkc zkc    4545 12月 11 2009 zipextimporter.pyc
-rw-rw-r--  1 zkc zkc   29025 12月 11 2009 zipfile.pyc

这其实就是一个使用类似 py2exe/pyinstaller 等 Python 打包程序生成的自解压可执行程序, 这里我们关注两个地方,一个是使用 wxPython 作为其 GUI 解决方案,所以有:

drwx------  3 zkc zkc    4096 11月  2 09:27 wx
-rw-rw-r--  1 zkc zkc 3096576  9月 29 2009 wxmsw28uh_vc.dll

另外一个地方是其最关键文件:

-rw-rw-r--  1 zkc zkc   18529 12月 11 2009 dropsyncore.pyc

我想 dropbox 客户端的大部分程序逻辑都在此了。 这个已编译的 .pyc 文件也不大, 其编译前的 .py 文件估计大小为 16Kb 左右, 其行数大概就是几百行。 结合使用类似 [DePython]http://www.depython.com/ 等方式, 估计很快就可完全掌握 dropbsyncore.pyc 文件的源文件内容了。 Python 拿来做客户端程序看来还是令人难以放心啊?

数据库文件 dropbox.db

这其实就是一个 sqlite3 的数据库文件, Python 自从 2.5 版本开始内置了完整的 sqlite3 标准模块, 所以一切显得那么的简单高效。 查看这个数据库文件:

$ sqlite3 dropbox.db
sqlite> .tables
block_cache   config        file_journal
sqlite> .schema block_cache
CREATE TABLE block_cache (
    id INTEGER PRIMARY KEY,
    hash VARCHAR(43) NOT NULL UNIQUE,
    sig TEXT,
    size INT,
    delete_after INT,
    needed_for INT
);
sqlite> .schema config
CREATE TABLE config (
    id INTEGER PRIMARY KEY,
    key TEXT NOT NULL UNIQUE,
    value TEXT
);
sqlite> .schema file_journal
CREATE TABLE file_journal (
    id INTEGER PRIMARY KEY,
    server_path TEXT NOT NULL UNIQUE,
    active_server_path TEXT,
    active_blocklist TEXT,
    active_mtime INT,
    active_size INT,
    active_sjid INT UNIQUE,
    active_dir INT,
    active_attrs TEXT,
    updated_server_path TEXT,
    updated_blocklist TEXT,
    updated_mtime INT,
    updated_size INT,
    updated_sjid INT,
    updated_dir INT,
    updated_attrs TEXT,
    on_disk TINYINT
);
sqlite> select * from config;
1|schema_version|STYKLg==

2|last_revision|KGRwMQpMMzU3Mzc2N0wKTDM1MTkyOTU1NTgxMzMwNDMyN0wKcy4=

3|proxy_server|
4|startupitem|STAwCi4=

5|proxy_requires_auth|STAwCi4=

6|show_bubbles|STAwCi4=

7|proxy_port|STgwODAKLg==

8|max_download_kBs|RjAKLg==

9|proxy_mode|STEKLg==

10|proxy_username|
11|max_upload_kBs|SS0xCi4=

12|proxy_type|VkhUVFAKcDEKLg==

13|shadowed_proxy_password|UyItOWtceDgyZ1x4YjFceGUzXHhhY1x4ZjNceGQ5XHgwYkxceGVhJ1x4OTFceGU5IgpwMQou

14|host_id|VmJjNGQ1ODYxOTIzMmVmZTc2OTlkNjI4YjBlM2NjZjUxCnAxCi4=

15|dropbox_path|VkU6XHUwMDVDZGF0YVx1MDA1Q2Ryb3Bib3hcdTAwNUNNeSBEcm9wYm94CnAxCi4=

16|email|VnpoYW5na2Fpemhhb0BnbWFpbC5jb20KcDEKLg==

17|root_ns|TDM1NzM3NjdMCi4=

18|ns_p2p_key_map|KGRwMQpMMzU3Mzc2N0wKKFYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS1cdTAwMEFNSUlDSkRD
Q0FVMmdBd0lCQXdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBWk1SY3dGUVlEVlFRREV3NWtjbTl3
XHUwMDBBWW05NExXTnNhV1Z1ZERBZUZ3MDNNREF4TURFd01EQXdNREJhRncweE1ERXlNVFV3TlRV
NU5UWmFNQmt4RnpBVlx1MDAwQUJnTlZCQU1URG1SeWIzQmliM2d0WTJ4cFpXNTBNSUhkTUEwR0NT
cUdTSWIzRFFFQkFRVUFBNEhMQURDQnh3S0JcdTAwMEF3UUN4NWxnOUtkbVNaNVpmZDZERFFSaHlP
R1YrdUFaTU90YkE5RXJzU1d6QnRQeitQNFpJelg1cWlXdUxMVkluXHUwMDBBSFVMVWR0NFNnM1Av
MmdTK0s5eG03M3MrU0paRnJHTk40dWVDSjZvditZVXN5ditSVVRycnBCTlBPeU9DN2pDTFx1MDAw
QWpVaFRGK0Y0ZFBHUXpuTjZodzhlZWtOd20vR1c3SjJNdTA3UmtCZHhmbVBaRE1rRzlvdlppem1x
bGlxTm9EaDZcdTAwMEE2L3FOSjdHc1NMdjFoUzExUmVBVEZXRjF6eTgxcGdHT3AxNk1kOW5kSGN3
UmRoTkt2N3ZZckhLdTM0SEhjY20wXHUwMDBBdHo4Q0FRVXdEUVlKS29aSWh2Y05BUUVMQlFBRGdj
RUFyR3psaUFXRnUrR3lJdGdZUUZGc0xuS2ZDelFtSkg0ZVx1MDAwQXhrZ3VsQ253L3ZxWndVeXZO
UDQzWjBpeTV0cXIybGYzenlxeldiSnpSNXFrTXlzMFlWS2F4Y04wdDBtUWoxeUpcdTAwMEE0ajlt
OXdZTjZ2TEs4ZUFuaWpINnliTThicEVncHc5eW4yKytqelRWUDQ3Rm9OcXpUSnBKejV4OTcrVDlz
T2k5XHUwMDBBNzYxbE4wbE9pb2FrQW0zNTlUN1NHL0NhWThQYlUwV2pwRUZybXg4ZXE1cVFEbE1l
QWxlcWZlS2s0TXZMSkE4R1x1MDAwQUthK09UTjc0T1NNaUlrMWZXMG5jWVBHQVpPazZyT3NyXHUw
MDBBLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLVx1MDAwQQpWLS0tLS1CRUdJTiBSU0EgUFJJVkFU
RSBLRVktLS0tLVx1MDAwQU1JSURld0lCQUFLQndRQ3g1bGc5S2RtU1o1WmZkNkREUVJoeU9HVit1
QVpNT3RiQTlFcnNTV3pCdFB6K1A0WklcdTAwMEF6WDVxaVd1TExWSW5IVUxVZHQ0U2czUC8yZ1Mr
Szl4bTczcytTSlpGckdOTjR1ZUNKNm92K1lVc3l2K1JVVHJyXHUwMDBBcEJOUE95T0M3akNMalVo
VEYrRjRkUEdRem5ONmh3OGVla053bS9HVzdKMk11MDdSa0JkeGZtUFpETWtHOW92Wlx1MDAwQWl6
bXFsaXFOb0RoNjYvcU5KN0dzU0x2MWhTMTFSZUFURldGMXp5ODFwZ0dPcDE2TWQ5bmRIY3dSZGhO
S3Y3dllcdTAwMEFySEt1MzRISGNjbTB0ejhDQVFVQ2djQkhLUEFZZHlQVUtXOVpZdzBhNXRhVUZv
Ny9mTTlSc1NLemxPckU2aXVBXHUwMDBBcnN1WTVqVzJ1SmozYWlzRWVJZEMySUVoeVNXaEFXR1pp
bWhNRVl0Y1g4cmx0cUtDUlBTRmpmWTBEOTJzeWpWRlx1MDAwQUhmL1R1aGVSZE5TR0Y2Zk4rT0Ez
MGh4Q3ptWTdmdTByNUIwckpnSUkyRDBESUhPeVFnVlk2OXJ6b2g3QzkrR3dcdTAwMEFETVFKc1I3
Qk8wb0MxZ0RuK0dxemNzTDdFK1RUT3kvem14b2cyMVZJdUl6aUQ2OUd3NkREVDJScGsrTzg4UmZk
XHUwMDBBVHNEZWhVckZQT1FEUlhyV3A5czdUSjBDWVFEbWVwd1FuT3diVjM5S2l4eHczQzhpMFJH
a0loQWc4VzM5cUhkYVx1MDAwQVVrK0dIa1lVaGhMbEJPK3l5MXM3MlNTdWxEUFo0MzQ0M3IzZjB2
SXpZRWRQaWlpdmFzUmdGZVlQRzBPaTNhUTZcdTAwMEFEVWVWaW91bU9iTHNVMUQvR2lmZDZ1WVdr
eE1DWVFERm1VWFRHclNIdkt0RUhPMlhnWHZGK2I2MUpZQU5mRDF5XHUwMDBBMGxNdndHQWF6cGph
TmF3UmNoRHdzODBOMmdrTHVOOC9rbmRqVmdZMHJubnZ3VU9OdmRpUlBUU2twd21YUlovaFx1MDAw
QXFIeEt0Y2pTcHFWNE9NMy9RT2VubDZiUTR6K0o1S1VDWVFDNFloWnpzTHppckdYVlBCYkFzQ1cx
ZEE0YzZBem5cdTAwMEFKNHN4VTVLdXFEK2VmcDUyMGFpM055WW9vcTlqRkIxWWRvL2hnc3Rnc2pG
LzIvVDE1cDl5MU8xWklqYXpSTGdNXHUwMDBBRmMrMWZoejdQZExlQ0crNExpaTlEM1AvU0Iva3Ur
dEZRblVDWUU4S0crNEtycHl4M2hzK3hXL05aTFdYR1JWQ1x1MDAwQU16aVlHSlJVSVVaTTh6M3NQ
U1FWZUFiNmJTMFV1R3Z3MEdzV3Y3TUhZdlNJejBoRnlsL201OUpMOERvWWUzVVBcdTAwMEFuVysx
Y3ljUU1iZDc2ZTNjUWpBV3VNeUFYS2x2M0ZPT0dXcGJkUUpoQUlCRjZ1QkZxT3pJTmNsWFhxWWpY
QUJHXHUwMDBBakYzM0sxZVA0OVduNDNNM0pMbEQrNHdheFc2V3g3WVlUaU9JbHVBQzBOUFBvL3ZH
YWxka1Y5bXBSVkVXN003OVx1MDAwQXUyeVZOekN4c1lvN0ZMcElpQXJyNjJqTFZqWHhCS3NMcDJN
dFJkV2lIZz09XHUwMDBBLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS1cdTAwMEEKUycwZGJh
YjMzMzZhNTg2NzU4ZTlmY2RiYzRlOGQ2NTg1NycKcDIKdHAzCnMu

19|p2p_enabled|STAwCi4=
sqlite> .quit

好家伙,东西全在这里了!


update 2010,12,13

Dropbox 的客户端逻辑其实分开好几个模块实现, dropsyncore.pyc 只是很小的一部分。 将近一年多没有运行 Dropbox ,一运行居然自动更新到最近版,从防火墙 Comodo Firewall 查看其更新下载的数据大概有 20 多M, 看来应该是将整个安装程序都下载到本地了。 新的 Dropbox.exe 中内容更多了,不过还是使用 Python 2.5 而不是目前主流的 Python 2.6 。不知道为什么。

最近 UbuntuOne 也开始推出支持 Windows 平台的客户端(beta),下载安装测试了觉得没什么值得期待的。 在自家 Ubuntu 下都那么地慢吞吞,在 Windows 下也是这德行。。。 另外, Ubuntu 使用的单点登录机制好像性能有问题。

珠三角技术沙龙 2010Q4

珠三角技术沙龙 2010Q4

Topic 1 分布式系统:一种工程方法 陈硕

之现场笔记整理

2010,10,17

单机开销

  • 上下文切换
  • 系统调用
  • TCP本机吞吐量

分布式系统 - 技术浪潮的前期

尚未形成方法论

解决方案的基础

目前成熟的: Linux 编程、 TCP/IP 网络编程

先决条件:网络编程

本质困难

Partial failure 部分故障

如何在出现问题的时候发出消息通知其他部分

分布式设计: design for failure

可靠性指标 MTBF

如果不是 IBM System z 神器的话,如何计算和根据计算出来的指标调整分布式系统方案

单机硬件配件

电源、 CPU 、内存、硬盘和网卡的冗余方案

程序开发

程序可靠性只需略高于硬件可靠性

资源耗尽时的错误处理

尽量简化

可重启

  • 自动恢复
  • 手动恢复

本机进程间通信(IPC)

最好只使用 TCP 协议(断开时候有通知)

优雅重启(服务器端)

步骤:

1) 先停止心跳

  • 对于短连接:关 listen port
  • 对于长连接:让客户端主动 failure 到备用地址

2) 等待直到无新连接

3) kill 并重启

多进程依次重启

监控

目的:预警

可以类似 Linux 内核 /proc 方式暴露整个系统状态(即使用 procfs )

消息机制与通信协议

通信模型

  • end to end
  • 广播

收发风格

  • 一问一答: request/response
  • 一问多答: stream oriented

编程风格

  • Reactor
  • RPC

避免阻塞

使用超时处理机制

注意网络 IO :绝对不能阻塞

心跳协议

需求

若 C 依赖于 S ,则 S 应定期向 C 发送心跳

消息内容

  • 时间
  • 负载(系统状态)

检查

注意网络延时和机器时差的容忍性

关键

  • 在工作进程中发送,不单独发起
  • 在业务连接中发送,不单独发起

系统演变(升级)

消息格式

避免协议的版本号

常见错误:发送 C struct 或 bit fields

使用比较通用的格式

  • Google Protocol Buffers
  • Apache Thrift

考虑:性能和可扩展性

灵活性

开发语言

经过实践证明了的架构

单 master + 多 slaves

自实现的 name service

最后忠告

使用最土的技术

  • 进程间通信只使用可靠的 TCP 协议
  • 进程之内,使用 mutex 和 cond var

========
updated 0 2010,10,19

活动地址: 珠三角技术沙龙 2010Q4

陈硕老师的演讲稿在其博客上: 分布式系统的工程化开发方法

Javascript

2010,10,04

当你还沉溺于各种层出不穷的“Web容器”和“Web框架”的时候, 你或许没有留意到某个再平常不过的语言正在步入强大到你将无法想像的境界?

JavaEye 不久前引用了一篇关于 Javascript 最新发展的文章: 警惕Java,迎来JavaScript 。引起了广泛的讨论。 对于其中 node.js 项目, 我编译了最新的 nodejs (v0.2.0 2010.09.24 commit 353e2565d5867f457c03e5e011b5e13a2254b96f), 并按照其 helloworld 例子做了测试, 测试结果显示其服务器端性能确实强悍! 就连 Go 语言的那个 Helloworld HTTP 例子也没这么牛。。。

( 在我的 Gateway T6832c 本本上,Intel Core 2 Duo T5750,2G DDR2 RAM , $ ab -n 10000 -c 30 http://127.0.0.1:8124/ 得到大概 7000rps 左右的速度,最长的请求也只是10多ms而已。 $ ab -n 100000 -c 1000 http://127.0.0.1:8124/ 得到大概 6000rps 左右的速度,最长的请求大概是9000多ms 。 而 Go 语言的 Helloworld HTTP 例子不大稳定, 经常在中间几万个请求时就断掉了 (apr_socket_recv: Connection reset by peer (104)), 成功时候得到大概 5000多rps 速度,最长的请求大概在16000ms左右。 不过测试中 node.js 使用 CPU 两个核心经常轮流达到 100% , 而 Go 程序使用 CPU 两个核心好像一般徘徊在 80%-90% 之间,最多不会达到 100% 。 )

粗略阅读了新颖的 node.js 官方文档, 想到的正如上面那篇文章所指出的: “它的最重要的一项革新就是实现了针对服务器端开发的面向事件的编程模型。” 就算她暂时还不能“把Java从唯我独尊的宝座上拉下来”, 但是却开始有望和其他流行的脚本语言如 Python,Ruby 等在 Web Server 领域较量了。 因为看上去她的确是已经满足作为一种“试验品”了, 嗯,强烈期待基于此强力基础项目的项目面世!

回头看看 Javascript 的近来的进展, 比如在 NoSQL 方面,CouchDB 和 MongoDB 都使用到 Mozilla 的 SpiderMonkey 项目。 其中特别是 MongoDB 已经应用于很多大型项目之中,如 sourceforge , github 等。 Javascript 的“魔掌”已经触及到越来越多本来不“属于”她的领域了。 而且其表现出来的性能真的是非常的诱人。 (MongoDB 一个很“牛”的地方是其编译期间产生的中间文件超级大,加起来大概有1GB多, 而且随着版本的更新,这个数目似乎一直在攀升。 相比其几MB的源文件和几十MB的编译后得到的二进制程序实在令人费解。。。)

不过,有点让人“担忧”的是:这是否会使开发人员的素质下降呢? 请看这篇小文章: Javascript程序员嘴最脏?? 呵呵 :-)

为什么现在不用笨重的 IDE ?

2010,10,03

Why not use IDE now?


我的有些同事,给我的感觉似乎就是,没有笨重的 IDE 开发环境,他们不能工作。。。

当他们惊讶于公司招了我这么一个几乎听都没听说过的“Python程序员”之后, 有些想了解 Python 到底要怎么开发?使用什么的开发工具? (他们当然指的是像 Visual Studio/Eclipse 那样的超级IDE了。) 我只能说,哦,估计你可以试试 PyDev 或者 limodou 前辈的 Ulipad 等等。 不过我没认真用过,不好给你好的建议。

我也相信那些笨重或者不笨重的 IDE 本身是非常优秀的, 不然怎么会有人开发?并且怎么会有人使用呢?

我上次有个 Java 相关的基础问题请教一位同事,他很快帮我解决了问题, 不过最后却说了一句话:哦,你为什么不用IDE呢? 看上去,他似乎告诉我使用IDE就可以解决这样的问题。

不久前,我的另外一位同事,从事 C++ 开发的同事。 他说,哦,你使用 Linux 环境啊,那么如何组织开发? 有没有类似 Visual Studio 的开发环境啊? 我说 Eclipse 的 CDT 插件或者 Netbeans 或许可以满足需求, 但是大部分在 Linux 上做开发的应该只是使用 Shell + GCC + GDB + autoconf(/scons) + make(/cmake) 等等, 或者只是配置一个万能的 Emacs 神器。 当然其他各种宣称强大的C/C++环境也是有的,比如 Code::Blocks 等。 不过我没有认真去尝试过,还真不好说。

另外一位不久前另某高就的同事的说法让我感到很惊异。 那位同事应该主要是开发 Flash ,并且搞搞 Java 。 他打开 Eclipse ,等了很久, 在某个打开的 Java 源文件处,输入了一些字母, 然后在光标活动处出来了一个列表可以很“快速”的选择他想要的东西, 他说,在别的编辑器中能实现这个功能? 然后他在某个单词上按下了某些按键,等了一会, 出来了一些文字,大概是关于这个单词的说明等等。 然后他说,在别的编辑器中也能有这样的功能? 要是没有这些功能,叫他怎么进行开发? 我想我当时的确有些要晕倒。 当然现在可能很多“IDE”或者只是编辑器已经有类似这样的“功能”, 然而,对于从脚本语言开始的我来说,却不是这样的。 从 Python Shell 中的 help(what_to_ask) 或者 IPython 中简简单单的“?”或者“??”, 到 pydoc 命令等, 或者自己在官方源代码里的文档目录中自己编译出各种格式的详细说明文档, 这些都是非常简单非常容易做到的事情,而且随时随地,非常方便。 (又如 Ruby 中的 rdoc 等莫不如此。)

我现在有点明白为什么书店里大部分的语言书都是写静态语言的了, 因为他们的确需要! 对于大部分脚本语言来说,像上面所说的,要获取说明等很容易。 比如大部分规范的 Python 程序都有很好的 docstring ,特别是类库。 最无奈的,大不了去查下源代码,而静态语言你想做这样的事情估计很难。 我去查 Java 的 API 文档,很全很详细,但是他们是一种参考工具书那样的东西, 类似词典,并不是我想要的那种有导向效果的文档。 干巴巴的词典,除非你是个背诵狂,否则你会选择从这里入手? IDE把这些也都搞上去了,或者就是想解决这个问题?

以上这位同事在离职前很得意地跟我们说他去面试一家公司的时候, 把内存的工作原理讲了一遍,把人家面试官都“惊呆”了。。。 最后在他最后离开公司之前我们调试他的程序的时候, 我们把他的程序(webapp)部署到了局域网内的某台服务器上, 结果某个环节并没有发挥应有的效果,他走到跟前说, 你怎么使用这个地址呢,是“localhost”吧! 我当时的确被雷到了,我希望他当时是累得最后连话都说错了。

我对于IDE并没有太大的成见,我抱有的态度是, 我的实际开发项目都不大,或者很小, 根本不需要这么强大的东西来管理规划我的代码或者模块。 如果你已经把一个项目很好的拆分开来, 每个小的部分只关心她自己的逻辑或者业务, 那么你还需要那么笨重的东西么? 何况那些IDE里有的功能, 很多我们都可以自己写个简单的脚本之类来实现, 而且可以做的更加随心所欲,遇到问题自己也了如指掌。 比如自己写个 bash 脚本, 自动编译整个 webapp 并且部署到 tomcat 上再重启 tomcat , 这不就是一个非常简单的事情么? 哪里需要麻烦笨重的IDE在占用极大的系统资源中缓慢的进行这个简单的工作?

不过,对于一些庞大的项目,或者一些需要改造的老旧项目, 在我们开始接触和熟悉的时候,IDE或许会帮到我们很多忙。

我基本上使用 VIM 来完成我大部分的编码工作, 并且使用各种 GNU 工具,如 grep/find/lsof 等等在 Shell 环境中进行调配和控制, 因为她们使这个过程更加简单、高效和可靠。 特别在掌握更多的基本操作,如 VIM 的折叠操作等之后更加如此。

我不喜欢使用图形界面来控制各种服务器相关的配置, 因为那样代价很高,特别是对于远程操作来说。 我也不提倡在源代码中使用英文之外的语言撰写,如中文, 因为某些时候可能连接到远程服务器的终端并不能很好的处理编码的问题。 所以,这不是说我以为自己的英语水平很高很拽, 而是实际问题让我觉得这样做应该会更好些。

最后,有句话好像是这样说的: “开发一个傻瓜都会使用的软件,只有傻瓜愿意使用它。” ( 【外刊IT评论】软件编程21法则 第20条 )

另外,可能动态语言的壮大使得普通开发工作对于IDE的“渴求”慢慢降低了, infoq中文不久前有一篇文章介绍动态语言的企业应用: 动态语言企业应用优缺点浅析

--

我以我的无知来讨论问题,结果可能显得我更加的无知。

Tomcat 7

2010,10,03

Tomcat 7 正式版终于发布了。 JavaEye 翻译的文章:Tomcat 7 的七大新特性 中,可能让使用 Java 开发 Servelet 应用的人感觉到些许进展, 然而,在这些特性之中,他们大部分已经在脚本语言的 Web 框架中应用许久, 比如 Python 的 Tornado 框架等等。

Python 的 WSGI 协议或许让人更容易理解 Web 应用之间的流程, 不过 Servelet 的原理也许让人更容易理解 HTTP 协议的原理和应用。

关于 Tomcat 的工作原理有本书《How Tomcat Works》。 不过,一些简单文章可以让我们更快的初步了解其基本的实现原理, How Java Web Servers Work 应该是其中最简单易懂的一篇了。 这篇文章有中文翻译,如: How Java Web Servers Work 看完这篇小文章,相信 HTTP 协议最基础的地方已经有些明了。 不会像以前那样虽然知道请求 Request 和应答 Response , 就是很难言明这些到底是怎么回事或者如何使用这些达到各种需求。 另外一篇是比较详细点的: How Servlet Containers Work 这篇文章暂时没有认真阅读,对 Servlet 的分析应该更加深入一些。 也有其中文翻译,如: How Servlet Containers Work 看完这些再去学习那些 Web 框架或者 Web Container 之类的或许会更容易而且更明了一些。

其实最重要的是,我们也可了解协议本身及其如何应用,
明白了这些也许让我们觉得写个简单的协议不过是件再简单不过的事情了?

Mail Server

最近在忙邮件服务器,那个强大的 Zimbra 在 Ubuntu Server 10.04 LTS 中好像性能不大理想,估计是因为官方目前尚未正式支持。 我安装的时候参照了这个教程: Host Email and Calendars with Zimbra 6 on Ubuntu 10.04 LTS (Lucid)

最后还是决定使用 postfix + dovecot + squirrelmail ,这些感觉简单高效很多,最多就是那个 webmail 丑了些。

但是其实还是对 Mail Server 很多东西不清楚。看了鸟哥的文章,写得深入浅出,真的非常棒!我想给那些完全不懂邮件服务器的人看估计他们也看得懂了。终于逐渐清晰了 MTA/MDA 等等的原理了,知道了 SMTP 到底在干什么了 :-)

鸟哥的这篇教程在 Mail 伺服器
虽然 鸟哥的 Linux 私房菜 中很多内容都很旧了,但是读起来还是可以学到非常多的基本知识的。
真赞!

Older