Dec 30

今天真可算得上是打假年了,“汉编”,华南虎,China IPv9,都在今年高调的出现在各大新闻媒体上。汉编抄袭 Win32Forth,却到处大肆宣传如何自主研发,说什么中国人要有自己的编程语言这类忽悠人的话。华南虎事件本想仗着一只拍摄的纸老虎腐败一把,没想到被广大网友揭穿了。就这种形势下,号称中国自主研发的 IPv9 居然也不收敛点,还公开亮相,的确,04 年之后一直没有进一步的消息,现在突然出现,并且宣布明年要公开试运行,怎么能叫人信服。

看看这几年发生的这些事情,汉芯的丑闻,号称国产的麒麟操作系统使用了FreeBSD,改 Win32Forth 的汉编,还有这蒙人的IPv9,看看这帮人拿着纳税人的钱都做了什么,当然了,这里面涉及的经济利益远远没有这么简单。

事以至此,也没什么好说的了,咱毕竟是普通的技术工作者,还是希望社会是和谐的。:D

关于 IPv9 有一些比较有意思的讨论,请看这里:

http://bj1961sy.ql.xingkong.com/21004/21004/index.html

Dec 27

这两天通过看 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 写相关程序进行学习了。

Dec 25

最近用了下 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 命令即可。

Dec 22

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的修改,这样就免去了这些扫描的过程,当然内部的实现应该比这个复杂的多。
Dec 22

今天又重新读了 The C10K Problam,决定好好写份摘要记录下学到的内容。

文章主要探讨了如何配置操作系统或者编写相应的程序可以支持10K数量级以上的客户端。目前有不少IO框架可供选择使用,譬如重量级的ACE,轻量级的libevent等。

I/O 策略

开发网络应用一般有一些好的I/O策略可以参考:

  • 是否以及如何在单线程里面处理多I/O调用
    • 完全不使用阻塞和同步调用,尽可能使用多进程和多线程实现并发
    • 使用非阻塞(non-blocking)调用开始I/O操作(write()系统调用设置O_NONBLOCK参数),使用readiness notification(poll或者/dev/poll)来确定何时启动下一个I/O通道。当然这只能在网络I/O环境下有效。
    • 使用异步调用(如aio_write())开始I/O操作,使用completion notification(信号或者completion ports)来获取I/O完成的时间。在网络I/O和磁盘I/O都有好处。
  • 如何编写服务客户端的代码
    • 为每一个客户端准备一个进程(自1980年以来经典的UNIX方式)
    • 每个OS级别的线程服务多客户端,每个客户端收以下方式控制:
      • user-level 用户级别线程(例如GUN state线程,经典的Java绿色线程)
      • 状态机
      • continuation
    • 为每个客户端准备一个OS级别线程(例如native方式的Java线程)
    • 为每个活跃客户端准备一个OS级别线程(例如使用Apache做前端的Tomcat,NT completion ports,线程池)
  • 是否使用标准的I/O服务,或者将一些代码移至内核(例如自定义驱动,内核模块或者VxD)

Level triggered & Edge triggered

采用哪种通知机制非常关键,主要有两种readiness notification类型,基于level-triggered的方式有传统的select()和poll()系统调用,level-triggered针对file descriptors的condition改变进行通知,一旦condition出现变化,那么用select()系统调用会检测到。而edge-triggered这个概念在BSDCON 2000大会上关于kqueue()的论文里面由Jonathon Lemon提出的,和level-triggered不同的是,这种通知不取决于condition的改变,而是取决于事件源的活动。

下面是引自 Kqueue 这篇论文里面的说明:

Events will normally considered to be “level-triggered”, as opposed to “edge-triggered”. Another way of putting this is to say that an event is be reported as long as a specified condition holds, rather than when activity is actually detected from the event source. The given condition could be as simple as “there is unread data in the buffer”, or it could be more complex. This approach handles the scenario described above, and allows the application to perform a partial read on a buffer, yet still be notified of an event the next time it calls the API. This corresponds to the existing semantics provided by poll() and select().

Dec 09

用上了心爱的 MacBook Pro 之后在键位的问题上最让人头疼的就是没有 forward delete 键,在 PC 键盘 backspace 的位置上是 delete 键,但功能缺非如此,不过还是有办法搞定的!

有个叫做 DoubleCommand 的工具可以重新映射键盘按键功能,哈哈,大家都知道该把哪个键改一下映射了吧。正是空格右侧的那个 enter 键,正好当 forward delete 使。

http://doublecommand.sourceforge.net/index.html 这里下载 Double Command,下载安装之后在 System Preferences 里面会多一项的,按照下面的截图修改一下。

picture-2.png