作者 | 王明明,涛思数据软件工程师
小 T 导读:在计算机系统中,缓存是一种罕用的技术,既有硬件缓存,比方咱们常常听到的 CPU L2 高速缓存,也有软件缓存,比方很多零碎里把 Redis 当做数据库的缓存。本文为依据 TDengine 线上 Meetup 第四期王明明的分享《TDengine 缓存技术解析》(视频)整顿而成。
TDengine 是一款高性能的物联网大数据平台。为了高效解决时序数据,TDengine 中大量用到了缓存技术,本人实现了哈希表、缓存池等技术。明天我会为大家解说 TDengine 中用到的这些缓存技术。
首先我会介绍一下什么是缓存,罕用的缓存技术,最初重点分享 TDengine 中的相干技术,最好讲一下改良和优化的方向。上面咱们正式开始。
什么是缓存?
但凡位于速度相差较大的两种硬件之间,用于协调两者数据传输速度差别的构造,均可称之为缓存。
- 缓存最早是用来协调 CPU 和主内存之间的速度差别,进化出了目前的 L1/L2/L3 三层 CPU 外部的高速缓存;
- 在内存和硬盘之间也有 Cache,每次写磁盘时并没有立刻刷到磁盘上,而是写入到磁盘缓存中,由操作系统负责 flush 到磁盘;
- 此外,硬盘与网络之间也有某种意义上的 Cache,比方 CDN 缓存,代理服务器的缓存等等。
缓存工作的准则次要是援用的 局部性,包含空间局部性和工夫局部性。
- 空间局部性是指 CPU 在某一时刻须要某个数据,那么很可能下一步就须要其左近的数据,例如加载读磁盘数据的时候,尽管只须要一部分数据,然而每次都加载一个块,那么当须要左近数据的时候就能够间接从内存获取,防止再读取磁盘。
- 工夫局部性是指当某个数据被拜访过一次之后,过不了多久工夫就会被再一次拜访。例如咱们手机后盾运行程序,会把最近关上的利用缓存在后盾,很可能一会儿还会拜访雷同的利用,这种状况下间接将其从后盾调到前台即可。
在应用缓存时要依据零碎的架构、性能的要求以及要解决的问题抉择适合的缓存地位,比方内存缓存、磁盘缓存、分布式缓存等。
应用缓存有很多 长处:
- 进步性能,将相应数据存储起来以防止数据的反复创立、解决和传输,可无效进步性能。
- 进步稳定性,同一个利用中,对同一数据、逻辑性能的屡次申请是常常产生的。当申请量很大时,如果每次申请都进行解决,耗费的资源是很大的节约,也同时造成零碎的不稳固。
- 进步可用性,有时,提供数据信息的服务可能会意外进行,如果应用了缓存技术,能够在肯定工夫内仍失常提供对最终用户的反对,进步了零碎的可用性。
缓存是有状态的,包含工夫状态和空间状态。
- 工夫状态:应用程序应用的永恒数据;只在过程周期内无效;和特定的用户会话无关;解决某个音讯的工夫内无效。
- 空间状态:应用程序 / 过程 / 线程 / 单机 / 分布式 / 用户 / 角色。
应用缓存时须要思考的问题:
- 安全性:线程平安 / 权限平安
- 序列化
- 缓存数据优化
- 提前加载 / 动静加载
- 过期策略:FIFO/LRU/LFU
- 治理:效率监控,大小限度
缓存一致性问题:
- 当应用分布式的缓存时,须要思考多个缓存的一致性问题,避免因为不统一呈现问题。
- 解决一致性问题时须要依据理论的利用场景兼顾 CAP 准则。依据问题的场景不同,一致性要求也不同,能够强一致性或者弱一致性(最终一致性)。
a. 比方银行转账场景须要强一致性,数据没对立之前,不容许用户进行操作,避免金额出错。
b. 大多数互联网产品为了保障可用性和分区容错性,通常采纳弱一致性,比方不同地区的用户看到的同一个排行榜可能有十分短暂的不同,但数据同步胜利后,排行榜就雷同了,这个提早通常在几十 ms,对于用户来说是能够承受的。
罕用的缓存技术
- 应用硬件缓存(CPU Cache)
- 应用本地内存缓存(双缓冲 / 环形缓冲 / 缓冲池)
- 应用内存映射文件 (mmap)
- 应用数据库缓存 (Redis/MySQL)
TDengine 中的缓存计划
首先咱们来温习一下 TDengine 的整体架构。
- 数据节点(dnode):服务过程,能够包含多个 vnode 和 mnode,查问数据时须要 dnode 的网络地位来获取数据。
- 虚构节点(vnode):存储、查问的根本单位。多个 vnode 组成一个虚构节点组(VGroup),散布在不同的机器上,起到备份的成果。同时 vnode 也便于程度扩大。
- 治理节点(mnode):存储数据库的元数据,起到治理集群的性能。
再来看一下 TDengine 的数据模型。
- 一个采集点一张表(工夫戳作为主键,顺序存储)
- 一张表的数据在文件中以块的模式间断寄存
- 文件中的数据块大小可配
- 采纳 Block Range Index(BRIN)索引块数据
TDengine 中都有哪些数据须要缓存呢?
具体能够分为如下几类:
- 元数据(table meta/stable vgroup)
- 连贯数据(rpc/http session)
- 查问缓存(qinfo handle/ show info)
- 最新数据(last 和 last_row)
- 时序数据(buffer pool/ multilevel storage)
接下来咱们就具体看一下 TDengine 中的缓存计划。
首先是通用的哈希缓存(meta data/ rpcObj/ qinfo)。
- 哈希缓存,通过一个列表来治理,每个元素是一个缓存构造,外面包含缓存信息、哈希表、垃圾回收链表、统计信息、更新频率、锁等信息。此外,有一个刷新线程定时检测缓存列表中过期的数据,将其删除。
- 查问打算 id (query handle),query handle 是数据库查问时,server 先生产一个执行打算,返回给 client,而后 client 拿着这个打算 id,分屡次去 server 取数据,直到数据查问完。这个缓存是音讯工夫范畴,整个过程内无效的,不须要更新,应用完即开释。
- 元数据缓存(meta data),meta data 数据次要记录数据表的 scheme,所在的节点地址。通过客户端缓存 meta data 能够防止频繁的向 mnode 取数据。然而 meta 数据须要思考更新一致性问题。通过版本号来管制。
其次是 TSDB 内存块缓存 (double buffer/buffer pool)。
- TDengine 提供双缓存 / 缓存池来优化数据写入查问的性能。预调配 16M*6 的 buffer pool,应用超过 1/3 容量落地,落地时 mem 转化为 imei(不可变更),负责写入磁盘。
- 间接将最近达到的数据保留在缓存中,能够更加疾速地响应用户针对最近数据的查问剖析,整体上提供更快的数据库查问响应能力。
- TDengine 重启当前零碎的缓存将被清空,之前缓存的数据均会被批量写入磁盘,之前缓存的数据不会从新加载到缓存中。
- 数据查问时首先通过 time range 定位数据所在的地位,因为 MEM 和 IMEM 中都记录有最新、最旧数据的工夫戳。而后如果在 MEM 中,通过跳表来疾速查问数据地位。在磁盘中,通过磁盘块文件索引查找数据,最初做后果交融返回。
再来看 last 和 last_row 缓存 (local storage)。
- 时序数据库总是有对最新一行数据或者某列最新一条数据查问的需要,因而设计了 last 和 last_row 缓存来疾速响应用户需要。避免每次都去磁盘查问数据。
- 每个表开拓缓存区缓存该数据,服务启动时会全量加载,插入时会更新,此外在配置更新的时候,也会更新缓存数据。比方,默认是敞开的。用户应用命令开启缓存性能时,就会加载数据,同理敞开开关时,会开释之前的缓存区。
最初咱们再来看一下多级存储 (ssd/hdd/cloud)。
因为物联网的数据量是微小的,为了很好的均衡性能和老本,TDengine 还采纳了分级存储的思维,不同热度数据存储在不同的中央。分级存储的这一思维也体现在计算机的体系结构里(寄存器、L1/L2 Cache、内存、硬盘)。
缓存对性能晋升举例
- 测试环境: 12 核 i7 3.2GHz 64GB 4T HDD
- last_row 缓存性能比照 (select last_row(*) from stable 查问语句 1000 次,统计查问工夫)
- last 缓存性能比照 (select last() from stable 和 select last_row() from stable 查问语句 1000 次,统计查问工夫)
- 开启缓存性能比不开启缓存晋升将近 1 个数量级。缓存对系统性能晋升还是很大的,所以,在应用 TDengine 时,能够依据本人的需要,关上或敞开开关
问题及改良优化方向
先来看问题,次要是两点:
- mnode 的 meta 数据全量加载,表数量很大时,内存占用大,启动慢;
- last 和 last_row 缓存启动全量加载。
最初咱们再来看一下优化方向:
- 全量加载改为动静加载;
- 预调配缓存大小,通过 LRU 等策略来更新数据;
- qhandle 通过对象池治理,防止频繁 calloc。
如果想理解更具体的实现细节,能够在 GitHub 上查看相干源代码,也期待大家退出进来,一起改良 TDengine!
对于作者
王明明,北京邮电大学毕业,主修方向为电子信息、模式识别和图像处理。毕业后入职腾讯,先后在 TEG 魔王工作室卡牌游戏开发、腾讯地图手图后盾开发、腾讯看点常识图谱后盾开发。对网络编程、RPC 框架原理、Redis 缓存等技术有深刻的钻研。