08-leveldb性能优化

Posted anda0109

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了08-leveldb性能优化相关的知识,希望对你有一定的参考价值。

在《02-leveldb入门》中,我们介绍了leveldb的参数,本节就主要讲如何通过调整leveldb的参数来进行性能优化。
levedb支持配置的参数如下:
const Comparator* comparator;比较函数,主要用于key的大小比较。如果传入NULL则使用默认字节序进行比较。
bool create_if_missing = false;如果数据库不存在,则创建。
bool error_if_exists = false;如果数据库存在,返回错误。
bool paranoid_checks = false;如果开启,则在读取数据时进行严格的检查,若发现数据损坏,则立即结束。
Env* env;用户定义环境,用于文件读写、后台线程等,默认Env::Default()。
Logger* info_log;日志对象指针,如果传入为空,则使用默认定义的日志对象。
size_t write_buffer_size = 4 * 1024 * 1024;写缓冲区的大小,对应于memtable的空间大小,会影响并发写入性能,原理部分会进行详细说明。
int max_open_files = 1000;最大打开文件数,也会关系到tablecache的大小.
Cache* block_cache = nullptr;data block缓存,如果为nullptr则数据块不进行缓存。
size_t block_size = 4 * 1024;数据块的大小,默认为4k,一般不需修改。
int block_restart_interval = 16;重启点的间隔,即每16个key进行前缀压缩。
size_t max_file_size = 2 * 1024 * 1024;文件最大大小,根据存储数据大小进行调整。
CompressionType compression = kSnappyCompression;是否对数进行压缩。
const FilterPolicy* filter_policy = nullptr;布隆过滤器,使用布隆过滤器有利于提高查询效率。
结合应用场景,通过调整上述参数来达到性能优化的目的:

01、数据校验paranoid_checks

在leveldb中,数据文件的每个block对应一个4字节的crc校验位。校验位的目的是在读取的时候对数据进行校验,检查其完整性,防止磁盘损坏等原因导致读取的块错误。crc校验的具体方法就是对block内的所有数据计算crc,并进行保存。读取的时候,同样对读出来的数据再次计算crc,比较与写入时候的crc是否一致。
当将paranoid_checks设置为true的时候,代表每次读取都需要对块进行crc校验,如果校验出错则及时抛出错误,不再进行后续的解析块的流程。如果开启了块校验,则会额外消耗CPU运算时间。但在大多数正常的环境下,读取出来的块都是符合校验的,因此也可以不开启校验。但面临的风险就是,万一有数据块损坏,而后续的解析又没有出错,导致读取出来的数据与原始写入的数据不一致。
在leveldb中,如果开启块校验,如果校验出错,则整个块被丢弃。但实际情况是,可能这个块只是损坏了某个数据的几个字节,对大部分数据其实是没有影响的。因此如果开启则会丢弃整个块的数据,而如果不开启校验,则直接进行块解析,对于这种情况,未损坏的数据还是可以解析出来,只会丢弃真正损坏的尽可能少的数据。
因此,paranoid_checks设置为false可以减少读取时的校验流程,从而提升读取性能。但是在数据完整性要求比较严格的情况下,建议开启这个参数。

02、写缓冲区大小write_buffer_size

write_buffer_size对应memtable和imm_memtable的大小。数据写入时会先写入memtable,因此如果write_buffer_size越大,就意味着写缓冲区越大。写缓冲区越大,就意味着写入性能会越高。但同时,如果进程重启,由于缓冲区中的数据丢失,需要从wal中进行恢复,缓冲区越大,意味着需要从wal日志中恢复的数据越多,从而导致启动时间变长。
因此,如果想提升性能,可以尝试将该参数调大。但也必须清楚,调大这个参数带来的影响是什么。

03、最大打开文件数max_open_files

max_open_files指的是leveldb可以打开的最大文件数量,这些打开的文件的meta信息(包括index block、filter block)会缓存起来。当下次需要查询到文件时,直接从缓存中进行快速的定位,以提升性能。如果文件未被缓存,则每次查询到该文件时,都需要重新打开文件,读取磁盘,性能显然是很低的。
因此,如果你的数据量非常大,且条件允许的情况下,可以将该值调大。当然,调大后相应占用的内存空间也会变大。

04、块缓存block_cache

leveldb读取数据是以块为单位的,如果查询某个数据时,在某个块中查询到了,则会将该块缓存在block cache中,以便于下次查询同样的数据可以快速在缓存中读取。这个就类似于缓存热点数据,将最近查询的数据缓存起来,以应对重复查询。
很明显,这个值设置的越大,对性能越有利。但也不尽如此,还是得根据业务场景来看。

05、块大小block_size

block是leveldb读写数据的基本单元,写入时当数据大小达到block_size时,会进行一次刷盘。读取数据时,也是一次读取block_size大小。
因此,这个值也需要根据实际应用场景来设置。如果你存储的key/value数据非常小,则该值可以相应减小。如果你的key/value数据比较大,却将block_size设置的很小则是不合理的,意味着查询一条数据可能需要读取多次磁盘。

06、文件大小max_file_size

max_file_size指的是单个sstable的最大大小。这个同样是和应用场景相关的,如果你的key/value数据很小,则该值也应该相应的调小;如果你的key/value非常大,也需要将该值调大。但是该值也会影响到读写的放大,如果单个文件很大,则在compact时候的读写放大也会加大。
这个具体调整多大,需结合原理、场景以及实际测试进行评估。

07、数据压缩compression

leveldb中支持将数据进行Snappy压缩,Snappy算法的优势是性能高,但压缩比并不一定是最优秀的。由于其性能高,因此比较适用于数据库的压缩。数据以block为单位进行压缩。
对于写磁盘来说,由于数据压缩,同样的数据量会占用更小的磁盘IO,同时也减少了磁盘空间的占用。对于查询来说,读取同样的数据需要更少的IO,但是读取后需要进行解压缩,才能得到最终的数据。这个是典型的用CPU时间换磁盘空间。
因此,对于数据量很大,对存储成本比较敏感的情况,建议开启压缩。而数据量较小,对存储成本不敏感的情况下,建议不采用压缩。

08、过滤器filter_policy

leveldb中提供了布隆过滤器。布隆过滤器用于快速识别一个块中不存在待查询数据的情况,以减少不必要的磁盘读取,提升查询效率。详细见《07-leveldb性能优化(一)》。

以上是关于08-leveldb性能优化的主要内容,如果未能解决你的问题,请参考以下文章

08-leveldb性能优化

UGUI性能优化

mysql性能优化分析 --- 下篇

Web 前端性能优化

vue项目性能优化,优化项目加载慢的问题

Android性能优化-过度绘制解决方案