落地数据的key-value的库 key-valueleveldbmysql
最近在做项目时,遇到了一个问题,现在没有非常好的落地数据的key-value的库。下面就总结一下现有的实现方式,结合使用过程中发现的问题,最后找到一个简单的实现自用的库的方法。
首先总结一下现有的实现方式
1.在mysql上层封装一层接口,将mysql变成一个落地数据的key-value库,然后加上memcache。
这种方式比较适合域读多写少的地方,因为mysql的写性能比较差。读的时候多数会命中memcache所以性能比较好。
针对写性能差的缺点,mysql也有自己的解决方法:读写分离加上主从同步。
建立多个mysql节点,一个节点设置为master,然后其他节点设置为slave(这是扁平的mysql架构)。
在master上开启bin-log,然后slave会读取master的bin-log。
问题:
在一块磁盘上的分表作用有多大?
考虑只读的情况,对建立索引的查询,大部分都是一次IO就可以完成读操作。分表的作用就比较小
如果有写的情况,mysql如果只是锁记录的话,则分表做的作用也非常小。
2.leveldb
leveldb是一个非常好的支持落地数据的key-value的库,它的读性能和写性能都非常好。
性能分析:
读性能:在写不是很多的时候,能保证一次磁盘IO就能得到随机读的数据。
写性能:leveldb采取了合并写的模式,普通的写都是写到内存中,然后过一段时间会顺序的写到一个disk上。所以写的性能也是非常好的。
然后分析一下具体使用问题
在使用的过程中也发现了非常多的问题:
1.leveldb的读性能不是很稳定。我们几个开玩笑的时候说,如果一个库一般情况性能好,但是在某些情况下的性能差,还不如在所有情况下都比较差。因为在评估机器的时候,如果性能差,可以采用scale-out的方式来扩展。
leveldb的merge是一个非常耗时的操作,在通常情况下,merge会涉及到11-12个文件,一个文件2M,就是所涉及到22M文件的读写,这个会花费200ms(200M/s),这个最坏的情况会涉及到24次寻道的时间,大约会花费200ms(一次10ms)。在这个时间内,如果有读请求需要磁盘IO,那么就非常困难了。
可能的解决方法:
1).缩小文件的大小有可能能解决这个问题,比如一个文件1M,这样能降低一次merge花费的时间,涉及的文件会变少。
2).通过merge中的限制,减少merge中间可能会涉及的文件的数目。在merge时,leveldb生成一个文件时,会考虑如果这个文件merge会涉及到多少文件,可以修改这个参数做到减少merge中间可能会涉及的文件的数目。
2.leveldb不支持主从同步。
这个问题比较容易解决,可以采用和mysql的解决方法一样的思路,dump+bin-log的方法。
组装自己的落地数据的key-value库
个性化的leveldb+主从同步,用组装这个词非常合适,嘻嘻。
附:mysql主从同步的实现思路。
今天还学习了一下mysql的bin-log的实现思路,bin-log中记录了insert,update,delete操作的具体内容,然后在slave上重现执行一下bin-log。这种bin-log在slave上的执行时间是和master上一样的,本来我还以为mysql会在binlog中记录内部数据的一些操作(比如B+树的操作和文件diff等等),这样应该能减少slave上的执行时间。但是这样就会让bin-log的设计非常复杂。