Don’t use mod_python

前天配置 mod_python 正恼火呢,没想到今天看到这篇文章,看来有同感的人真是很多阿。

#python.web 里面就建议大家不要使用 mod_python,列举了一些缺点:

  1. It complicates your upgrade process, as versions of Python, Apache, and mod_python must be coordinated. The appropriate versions are not always available for some combinations.
  2. It makes user separation or chrooting of webapps impossible.
  3. If you’re using PHP and mod_python, and you’re using MySQL in both languages, you generally must coordinate versions of MySQL as well, or suffer lots of configuration headaches. The same applies for many other popular C libraries.
  4. Apache’s processes will be heavier because you’re embedding a python interpreter in it.
    Debugging a wsgi app is a lot easier.
  5. mod_python is a module for Apache, which is tested less than other well known Apache modules such as mod_proxy. Because of this reason the server administrator (which might not be you) might not want to install this module for security reasons.
  6. You wont find a lot of hosting companies offering mod_python, which makes wsgi applications (which can be deployed through several ways) very flexible in your quest for a hosting company.

总的来说,mod_python 配置有麻烦,用起来又占系统资源,真不是什么好的选择。用 FastCGI 和 SCGI 似乎是更好的选择。

i18n failed in Chinese locale

发现 Django i18n 的一个中文支持的 bug

如果你的浏览器的 locale 只设置了 zh-cn 的话识别中文应该是没问题的,但是如果有多个 locale,僻如我一次设置了 zh-cn, en-us, de-de,那么中文就不可能被识别出来了。

要了解这个问题,我们先看下这段代码,在 trans_real.py 里面。
主要看一个名为 get_language_from_request 的函数。
从里面打开可以看到程序的基本流程。

  1. 检测 session 中有没有设置过 django_language,如果支持这个语言,那么就返回语言代码
  2. 检测 cookies 里面有没有 django_language,如果支持这个语言,那么就返回语言代码
  3. 最后就是要从 HTTP 头中的 ACCEPT-LANGUAGE 中分析语言。就是在这一步的时候,对中文的支持就存在 bug 了。
  4. 如果都无法识别,那么从返回默认的 settings.LANGUAGE_CODE

为什么会出现多个 locale 无法识别中文的情况呢?我们来看下面的关于分析 ACCEPT_LANGUAGE 的代码:

for lang, unused in parse_accept_lang_header(accept):
    if lang == '*':
        break

    # We have a very restricted form for our language files (no encoding
    # specifier, since they all must be UTF-8 and only one possible
    # language each time. So we avoid the overhead of gettext.find() and
    # look up the MO file manually.

    normalized = locale.locale_alias.get(to_locale(lang, True))
    # 这一步会将浏览器的 locale 字符串标准化,僻如 zh-cn -> zh_CN.gb2312
    if not normalized:
        continue

    # Remove the default encoding from locale_alias
    normalized = normalized.split('.')[0]
    # 这里就把上面的的 zh_CN.gb2312 变成 zh_CN
    if normalized in _accepted:
        # We've seen this locale before and have an MO file for it, so no
        # need to check again.
        return _accepted[normalized]

    for lang in (normalized, normalized.split('_')[0]):
        # 这一步让 lang 成为 (zh_CN, zh),进而匹配 supported 这个支持的语言集合。
        # 这是出错的关键,因为无论 zh 还是 zh_CN 都是无法匹配到的。
        # 在 supported 里面只支持 zh-cn 和 zh-tw,对于 zh 和 zh_CN 是无法匹配的。
        if lang not in supported:
            continue
        langfile = os.path.join(globalpath, lang, 'LC_MESSAGES',
                'django.mo')
        if os.path.exists(langfile):
            _accepted[normalized] = lang
        return lang
return settings.LANGUAGE_CODE

初探 kqueue

这两天通过看 C10K 的文章对 kqueue 萌发了比较大的兴趣。于是又温习了一下 C 语言,立即上手学着想写写东西。

说道 kqueue,可以看下之前的 blog,它是在 BSDCON 2000 时候提出来的,是一个 edge-triggered 方式的通知形式。不同与 level-triggered 方式的传统 select() 和 poll(),在 fd 列表数量很大的情况下不至于增加CPU的负担。

kqueue 的 API 设计的相当精简,只有两个新的系统调用,kqueue() 和 kevent()。kqueue() 是初始化环境,kevent() 则是负责了注册和取回事件列表。这两个 API 用起来还是相当方便的,大体上是以 kqueue() 初始化开始,然后使用 kevent() 注册感兴趣的事件和需要监视的条件,再之后就可以用 kevent() 来获得触发的事件了,一般使用一个主循环去处理就可以了。

了解原理之后就可以动手做一下了,Mac OS X 也早就提供了 kqueue 的支持,可以直接用 C 写相关程序进行学习了。

使用 Memcached

最近用了下 memcached,把 per-4.com 的缓存换了下。

memcached 使用起来比较简单,安装后输入:

# ./memcached -d -m 2048 -l 10.0.0.40 -p 11211

就可以启用 2GB 的缓存了。

用 telnet 127.0.0.1 11211 可以查询 memcached 的运行状态,输入 stats 命令即可。

Review The C10K Problem - Part 2

select(), poll() 的局限性

  • 传统方式的 select() 系统调用受到 FD_SETSIZE 大小的限制。这个限制被编译进了标准库,虽然某些C函数库允许你在编译的时候增加这个限额,但毕竟不是一个通用的方法。
  • 传统的 poll() 系统调用虽然没有 select() 的 FD_SETSIZE 大小的限制,但是在处理上千个连接的时候会变的越来越慢,虽然那时侯大部分的fd都是闲置的,但是一便便的扫描fd的状态非常耗时。

kqueue() 和 epoll()

  • kqueue() 是 FreeBSD 下推荐的支持 edge-triggered 方式的 poll 模式的替代品。
  • epoll 则是在 Linux kernel 2.6 的时候正式加入进来的,同样是推荐的 edge-triggered 的 poll 模式的替代品。

select(), poll() 与 kqueue(), epoll() 实现上的细微差别

  • 为什么 select() 和 poll() 系统调用在性能上会有问题,就和之前提到的一样,系统总是需要一次次的扫描file descriptors列表来标记那些改变的部分,然后客户端应用再次扫描这个列表取出fd进行操作,在服务器负载很高的情况下,维护的fd列表相当长,扫描的时间非常长,同时也让CPU负荷很高。
  • kqueue() 和 epoll() 则是让 kernel 主动通知应用程序关于fd的修改,这样就免去了这些扫描的过程,当然内部的实现应该比这个复杂的多。

Google Chart API

今天ShiningRay 同学介绍了个 Google 的新东西,Google Chart API,可以使用 Google 提供的这个服务来绘制一些图表了。

譬如访问这个地址:

http://chart.apis.google.com/chart?cht=p3&chd=s:hW&chs=250×100&chl=Hello|World

将会出来下面的图片:

还有很多参数可以选择,上网站看下吧。