beansdb 卷土重来

距上次发布 beansdb-0.3.0 以来, 又过了一年. 经过一年的线上运营锤炼, 它一直在不断改进中, 到现在已经有了非常大的变化, 下面简单描述一下:

完全放弃了ToykoCabinet 作为存储引擎, 它在数据的可靠性, 一致性, 以及大数据量下的性能有不少问题, 已经不能满足 beansdb 对数据存储的需求. 于是重新实现了一种基于日志结构的存储引擎 Bitcask, 借鉴自 Riak 项目的一份设计文档: http://downloads.basho.com/papers/bitcask-intro.pdf

Bitcask 有以下优点: 读写低时延, 高写入吞吐量, 能处理大规模数据集而性能不会显著下降, 数据持久化更好, 不用担心crash会导致数据丢失, 通过简单的rsync就能在线备份数据, 还能恢复被错误覆盖的数据.算法简单, 代码容易维护和调优, 在大数据量和高负载下的性能容易估计.

Bitcask 也有缺点, 它要求所有key信息全部放入内存, 在启动时一次性载入. 这对内存索引的效率提出了非常高的要求. beansdb中改进的HashTree有更好的空间效率, 它根据key的特点进行了重新编码, 大大降低了空间消耗, 每条记录平均只需20字节, 其中包括key, 版本,hash, 位置等信息, 这样一台8G内存的服务器可以存储 4亿条记录.如果记录平均大小为1k的文本, 则能存 400G, 如果是平均大小为100k的图片, 则能存40T.

启动时间也是Bitcask算法的缺点, 目前在一分钟大概能载入5千万条记录的索引, 还有进一步优化的空间.如果是意外crash后的重启, 时间会稍微长一点, 视数据量的大小而定, 一般也不会超过10分钟.

日志结构存储的另一个问题是会有空洞, beansdb 支持外部控制的在线垃圾回收过程, 可以安排在夜里进行.通常在硬盘不是太紧张的情况下, 几个月进行一次垃圾回收就可以了.

之前网络层采用的是memcached的代码, 它使用libevent, 每个连接是跟固定的线程绑定的,在存储引擎中使用这种线程模型容易发生阻塞, 磁盘IO操作阻塞当前线程进而阻塞了其它连接的网络IO,因而直接基于epoll/kqueue 实现 leader/follower 模式的线程池, 响应时间会更好, 尤其是在并发访问比较高的时候.

为了简化维护, 在部署beansdb时增加了一层 proxy, 它是用 go 实现的, 会根据后端存储节点的数据情况自动做数据路由和负载均衡.proxy 时无状态的, 可以部署多台开实现扩容和HA. 添加新节点时只要改一下proxy的配置, 而数据迁移时无需更改任何配置.

目前我们部署了两个实例, 一个用来存文本数据, 共有13.3亿条记录, 总数据量为 2.8T, 分散在 8 个节点的 10 块SATA盘上, qps 为 160, 99% 的时间在 70ms 以内.

另外一个实例用来存储图片和单曲, 共有 7.5 亿, 数据量为 22T, 分散在 17 个节点的 约 50 块硬盘上, qps 为 180, 99% 时间在 300 ms 以内.

目前代码和文档还没有同步更新到 beansdb.googlecode.com 上去, 近期会进行完善. 有兴趣的同学, 可以先拿一份最新的代码去尝尝鲜: http://beansdb.googlecode.com/files/beansdb-0.5.2.tar.gz

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。