聊聊原美图开源的kv存储titan

小白debug 2023-09-05 09:02

市面上开源 kv 轮子一大堆,架构上都是 rocksdb 做单机引擎,上层封装 proxy, 对外支持 redis 协议,或者根据具体业务逻辑定制数据类型,有面向表格 table 的,有做成列式存储的

国内公司大部分都有自己的轮子,开发完一代目拿到 KPI 走人,二代目继续填坑,三四代沦为边缘。即使开源也很难有持续的动力去维护,比如本文要分享的 美图 titan[1],很多优化的 proposals[2] 都没实现,但是做为学习项目值得研究,万一哪天二次开发呢

整体架构

Titan 代码 1.7W 行,纯 go 语言实现。server 层只负责处理用户请求,将 redis 数据结构映射成 rocskdb key/value, 底层使用 tikv 集群

站在巨人的肩膀上,titan 无需考滤数据 rebalance, 不关心数据存储副本同步,这也是为什么代码量如此少

压测[3] 数据只有 2018 年的,性能一般,latency 也没区分 99 和 95 分位。如果基于最新版本的 tikv 集群测试效果可能更好

数据类型实现

目前数据结构只实现了 string, set, zset, hash, list, 有些也只是部分支持,只能说够用

持久化的 kv 轮子,难点就是如何把 redis 数据结构与 rocksdb key/value 做映射。原来单进程天然实现的原子性很难实现,维护一种数据涉及多个 key, 如果分布在多个 instance 进程又涉及了分布式事务,吞吐自然降低很多

比然我们常用 lua 脚本自定义一些业务逻辑,将涉及的多个 key 用 hash tag 处理下,变成同一个 redis slot, 但这在 titan 里是做不到的

性能问题,比如 HLEN 操作,本来 redis O(1) 操作,如果在 titan  的 hash metakey 中维护 len 记录,那么高并发写删 hash 时就会有大量冲突。再比如 zset 数据结构,zrange, zrangebyscore, zrangebylex 需要将 member, score 分别编码存储,用空间换时间

String

String 类型只有两种 key: MetaKey, ExpireKey

MetaKey 中 namespace 用于实现多租户隔离,但也只是逻辑上的,毕竟资源仍然是共用的,dbid 类似 redis db0, db1 ...

ExpireKey 用于主动过期数据,后台任务定期扫。每个类型都有,后面省略不表

MetaValue 前 42 字节为属性信息,后面才是真正的用户 value. 时间字段表示创建,更新,过期 timestamp, 被动过期时会检查 ExpireAt. uuid 用于唯一标识 key, titan 主动 GC 会用到

Type 表示数据类型

const (
 ObjectString = ObjectType(iota)
 ObjectList
 ObjectSet
 ObjectZSet
 ObjectHash
)

Encoding 表示具体的编码类型

const (
 ObjectEncodingRaw = ObjectEncoding(iota)
 ObjectEncodingInt
 ObjectEncodingHT
 ObjectEncodingZipmap
 ObjectEncodingLinkedlist
 ObjectEncodingZiplist
 ObjectEncodingIntset
 ObjectEncodingSkiplist
 ObjectEncodingEmbstr
 ObjectEncodingQuicklist
)

为了兼容,定义与 redis 一致

Set

MetaKey 与 String 类型一样,MetaValue 一共 50 字节,前 42 字节一样,后 8 字节维护集合 Set 成员数量信息。也就是说后续的 SCARD 是 O(1),但同时删除增加都要修改 MetaValue

DataKey 编码了 Set 唯一 uuid 与成员 member 信息,由于集合只需要成员 member, 所以 DatValue[]byte{0}

Zset

与集合一样,zset MetaKey/MetaValue 内容一样

DataKey 内容基本一样,DataValue 是 score 值,同时也维护了 score -> member 映射的 ScoreKey, 用于空间换时间方便 zrangebyscore 查询

Hash

注意这里 hash 的 MetaValue 并没有维护成员 Len 信息,所以当 HLEN 时要遍历 range 整个 data key 空间,为什么这么做呢?

titan 作者说 hash 写并发时会有大量的事务冲突,所以选择不维护。后来他们提出一个方案,对 MetaKey 拆分成多个 slot,尽可能减少冲突,同时还能提高 HELN 性能,不过后来也没实现

List

List 有两种结构,一个是 ziplist, value 是用 pb 将多个元素编码在一起, 另外一个是 linkedlist. 当前实现没看到 ziplist 到 linkedlist 的转换,其实对于持久化存储来说,只用 linkedlist 足够了

MetaValue 后 24 字节分别维护了 len, lindex 和 rindex, 其中 index 类型是 float64, 为什么不是 int64 类型呢?

原因在于对于 Linsert 操作,如果插入 (2, 3) 之间,那么会失败,但是用 float64 大概率会成功,但是考滤 float64 也有精度问题,存在失败的概率

// calculateIndex return the real index between left and right, return ErrPerc=
func calculateIndex(left, right float64) (float64, error) {
 if f := (left + right) / 2; f != left && f != right {
  return f, nil
 }
 return 0, ErrPrecision
}

DataKey 编码 index 信息,DataValue 就是值

事务冲突

由于 titan 整体都是小事务,所以对于 tikv 事务开启了 1PC 和 AsyncCommit, 来提高整体吞吐量。对于冲突的事务,titan 尽可能重试证执行成功

关于 affinity 亲缘性问题,titan 想将一个类型的 key 尽可能放到一个 tikv 实例中,当前没有实现,很难,不好搞。可以说 tikv 减少了持久化 kv 开发难度,也束缚了灵活性

删除 GC

Delete 时,删除 MetaKey,如果存在 TTL 那么删除 ExpireKey, 对于非 String,将 DataKey 扔到 sys namespace 中

$sys{namespace}:{sysDatabaseID}:GC:{datakey}

后台 doGC 调用 gcDeleteRange 慢慢删除,由于 DataKey 中存在 uuid, 基本不会重复,不影响用户重新创建相同 key

Flushdb 操作也非常重,理论上可以给所有 key 编码时带上 version, 这样可以快速 flush 快速回滚

运维周边

代码开源只是第一步,周边生态建设好用的人才多。目前看 tikv 运维 pingcap 有很多文档,基本够用了,做好参数上的调优

监控,故障处理,做好 chaos 故障注入测试

数据一致性校验,异构同步 redis 等等目前看都是缺失的

小结

目前 titan 的状态离真正 production ready 还差若干个 P0 故障,OOM 内存被打爆,spike 流量把集群打跨

代码还有些书写瑕疵,想要用的同学,有能力二次开发的做好集群压测,故障注入,限流,千万不要急于上线,随时做好回滚的准备

分享知识,长期输出价值,这是我做公众号的目标。同时写文章不容易,如果对大家有所帮助和启发,请帮忙点击在看点赞分享 三连


欢迎加我!


参考资料
[1]

美图 titan: "https://github.com/distributedio/titan",

[2]

优化 proposals: "https://github.com/distributedio/titan/tree/master/proposals",

[3]

titan benchmark: "https://github.com/distributedio/titan/blob/master/docs/benchmark/benchmark.md",


评论
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 150浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 181浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 161浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 27浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 95浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 73浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 360浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 46浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 121浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 179浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 221浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 111浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦