Row Cache如何提升数据库查询性能 | 内核干货
X-Engine Row Cache以行为单位,缓存持久化层的数据。相比block cache,可以更精准的缓存热点数据,有效缩短读路径,提升点查性能。
作者 | 尚灿芳
01
X-Engine Row Cache概述
LSM-Tree架构的存储引擎下,所有的更新都是新写入一行,数据以多版本的形式存在。为有效使用内存,row cache只保留单key的最新版本,flush memtable过程中定向淘汰旧版本数据。row cache读路径几乎是无锁的,内部实现桶锁hashtable,点查性能超过memtable。
X-Engine读路径访问层次
row cache缓存热点数据行,从读路径上看,位于memtable下一层,block cache上一层。get请求在memtable中不命中时查找row cache。row cache为保证正确性维护了check模块,只有符合读写要求的请求才可以进入row cache,check失败或者row cache不命中时继续查找block cache。
block cache需要通过元信息查找定位到对应的extent再通过index block索引到对应的数据block,相比之下row cache的读路径要短很多。row cache内部实现桶锁hashtable,相对于memtable的skiplist管理更加简单,性能更好。
02
X-Engine Row Cache实现
为提升并发的读写性能,row cache分为多个shard,每个shard单独管理数据,互不干扰。每个shard内部包含独立的hashtable和多个chunks的内存池。
hashtable使用预分配内存的方式,在初始化时分配固定数量的buckets和hashnodes,每个bucket包含一把读写锁,每个hashnode包含key的hash值、指向下一个node的指针和value。对于row cache,value是指向RowcHandle对象的指针。
row cache使用RowcHandle管理每一条数据,包含key的长度信息、sequence、引用计数、分配内存的chunk和value,insert过程中只有一次内存分配操作,分配大小为RowcHandle结构大小加上(key,value)大小,内存分配调用内存池的分配接口并回传对应的chunk allocator,用于定向热度统计和释放内存。
row cahce实现
row cache的主要操作包含lookup、erase和insert。除在hashtable中同一个桶内的操作外,其它操作都可以并发执行。
Lookup
lookup操作是比较轻量级的,根据key的hash值定位到对应shard,以及hashtable中的bucket。预分配按照预估行数一比一分配bucket,一般情况下每个bucket包含较少node,可快速定位row handle,根据row handle的信息解析出value,并更新引用计数和热度信息。与之对应的是release操作,读完释放引用。
Erase
erase操作发生在异步线程flush memtable的过程中,根据key值查询是否存在row cache中,如果存在则消除key值对应的旧版本数据。erase会从hashtable中消除掉对应的node,如果引用计数减为0将row handle使用的内存释放。内存池会将这部分内存管理起来重复使用。
Insert
row cache hit miss时,数据从下层读上来并填充row cache。insert时从内存池中分配内存并填充row handle的相应信息,由于内存池是固定内存容量,若内存不足则触发evict函数同步淘汰内存池中的一个chunk。除同步淘汰外,row cache每隔一段时间调度后台线程异步淘汰一定百分比的chunks,避免频繁的触发同步淘汰,使内存使用水位尽量保持在一定百分比以内。
03
X-Engine Row Cache优化
X-Engine Row Cache第一版实现,采用经典LRU算法。由于读时也需要修改lru链表,只能加mutex锁,不能实现并发读,路径更长操作也更多。而第二个版本则使用了内存池,将淘汰等工作托管给内存池,提高了查询性能和内存利用率,后面会专门写一篇文章介绍X-Engine内存池的实现,以及如何优化Row Cache,敬请期待。
内存池版:get->shard->hashtable bucket rlock->find node->return value
lru版:get->shard->lru lock->hashtable bucket->find node->remove from lru->return value
04
性能测试
KV测试
db_bench random模式,16张表,每张表100w条数据,内存size设的足够大,线程数1,2,4,8,16,32,64,128,共测试5次,每种线程测试时间3min,5组数据取平均值,综合对比图如下,蓝色是LRU版row cache,橘黄色是内存池版row cache。
sysbench测试
sysbench point_select,16张表,每张表100w条数据,内存size设的足够大,对比了memtable和新旧两版row cache的性能。
相关阅读:
目前X-Engine引擎已经上线阿里云, 经过阿里内部业务验证,欢迎有成本和性能需求的用户购买使用。详情点击「阅读原文」