自从SSDB 1.5.2版本起, SSDB默认使用了多线程, 将所有写操作放在一个单独的线程中, 这样可以避免写操作阻塞读操作.
在之前的版本, SSDB的网络模块采用基于epoll IO多路复用的单线程模型, 这种模型非常快速. 不过, 由于LevelDB的特性, 当写操作过快的时候, 合并(Compaction)线程无法及时地完成所有合并, 导致Level-0文件越积越多, 最终强制阻塞所有写操作.
SSDB新版本采用了多线程模型, 可以避免写操作阻塞读操作. 但是, 因为LevelDB的特性, 写操作仍然可能相互阻塞. 但是, 大部分SSDB的用户不需要担心写操作相互阻塞的问题, 因为大部分的应用的写操作不会那么快.
可能有读者会提出疑问, 既然多线程这么好, 为什么直到1.5.2版本才采用多线程机制呢? 其实, 在某些情况下, 多线程不一定比单线程程序快. 原来有两个: 一是线程竞争, 二是线程间同步.
SSDB使用pipe在网络线程和工作线程之间进行通信. 使用pipe, 使得工作线程的结果也是可select的, 这样, 就可以在网络线程中使用select/epoll得查询工作线程, 当工作线程处理完一个任务时, 网络线程能立即将这个结果返回给客户端.
不过, 经过测试, pipe至少有10us的延迟, 这对于一个高并发的数据库服务器的影响也是可观的.
不管怎么样, 在牺牲了一点点写性能之后, SSDB的总体可响应能力得到了极大的提高, 在我的机器上仍然能得到20K ops的写速度.