Tedis 是基于开源 TiKV 的兼容 Redis 协议的强一致性的 NoSQL 数据库开源项目。 本文介绍一下 Tedis 开源项目的架构设计和特性,以及架构背后的一些思考(包括为何选择 TiKV 和 Redis 协议)。
先来讨论为什么基于 TiKV 构建我们自己的 NoSQL 数据库。
首先简述一下 TiKV[1],TiKV 是 TiDB 的一个子项目,TiDB 是一个分布式的关系型数据库 [2],TiKV 是 TiDB 的存储层。TiKV 本身是可独立于 TiDB 的单独项目。它是一个强一致、可水平扩展的、高可用的分布式 Key-Value 存储系统。
选择 TiKV 的第一个原因是 TiKV 是一个强一致的系统。 在我的另外一篇文章中(发表在 InfoQ, 参看 https://www.infoq.cn/article/rhzs0KI2G*Y2r9PMdeNv ),我阐述了一个观点:NoSQL 数据库应该具有一致性,并且通过多副本技术达到实际的高可用,也就是说 NoSQL 数据库应该是一个“实际上的 CA” (effectively CA)系统。但是在这篇文章中我并没有明确说明 NoSQL 该具有的一致性是哪种一致性。 实际上,我所说的一致性其实就是一种强一致性 [3], 或者更准确的说是线性一致性 [4]。TiKV 正是具有这种线性一致性。TiKV 中的每个数据都会保存 3 个副本,在只有一个副本的节点宕机或者出现网络分区的情况下,另外 2 个副本仍然能够对外提供服务。理论上来讲,同时出现 2 个以上副本同时坏掉的可能性很小,也就是理论上可以达到非常高的可用性。通过 TiKV 滚动升级等运维辅助,如果在实际的生产中,有良好的运维,可以达到实际上非常高的可用性。也就是称为一个“实际上的 CA”(effectively CA)系统。
TiKV 通过 Raft [5] 协议实现了线性一致性和高可用 2 个特性。Raft 是一种分布式共识协议,通过 Raft 协议,数据可以被认为是原子的写入到 3 个副本上。共识协议的一个特点就是要写入大多数,才会认为写入成功,3 个副本的大多数就是 2 个,也就是在只有一个副本宕机或者网络分区的情况下,仍然可以成功写入,并且提供读服务。
选择 TiKV 的第二个原因是 TiKV 的架构可扩展和生态。 在 TiDB 中 TiKV 是独立的一层,形成了一个很好的可扩展架构,实际上可以在 TiKV 上扩展出很多不同的数据库出来。TiDB 层本身就是这种架构上的一个扩展。这种架构类似于 Google 公司的第一代的 Spanner 系统 [6],Spanner 系统本身也是一个强一致性的、高可用的分布式 Key-Value 系统。在 Spanner 的基础之上,Google 构建了 F1 系统 [7],实现了 SQL 协议。2017 年,Google 升级了 Spanner 到第二代 [8],让 Spanner 本身就具有了 SQL 能力。虽然一代 Spanner+F1 是这样的架构,但它仍然是一种非常优秀的架构。我们的 Tedis 项目,也是构建在这一可扩展架构上的一个项目,依托于 TiKV 提供的底层能力,向上构建了不同于 SQL 协议的 Redis 协议。 我相信 TiKV 的这种可扩展架构,未来可以成为一种生态,还可以在上面“⻓出”其他的类型的数据库,比如说 Mango 协议、图协议。这些数据库都具有与底层 TiKV 相同的线性一致性和高可用性,区别只在于对外的接口协议不同。 目前这种生态已初⻅端倪,Titan(https://github.com/distribute…) 这个开源项目,与我们的 Tedis 项目非常类似,他们的开源步伐先于我们,目前做的也非常不错。我相信,我们肯定不是这个生态中的最后一个。
总之基于 TiKV,Tedis 实现了以下的技术特性:
1. 大数据量,可以存储至少数十 TB 级别的数据。
2. 高性能,在满足高 QPS 的同时,保证比较低的延时。
3. 高可靠,数据被可靠的持久化存储,少量机器的损坏不会导致数据的丢失。
4. 高可用,作为在线服务的底层依赖存储,要有非常完善的高可用性能力,外卖服务不同于电子商务,对实时性要求非常高,对系统的可用性的要求则是更高的。
5. 易运维,可以在不停服的基础上进行数据迁移和集群扩容。
接下来,我们讨论第二个问题,为什么选择 Redis 协议。
SQL 语言与其背后的关系模型,从 1970s 发明以来,一直在应用开发领域占据这统治地位,虽然在 CAP 定理的推动下 [4],在 NoSQL 运动中,出现很多 NoSQL 系统,就如我前面阐述的一样,一致性不应该是 NoSQL 出现的理由,去 SQL 和关系模型才是 NoSQL 出现的动力。但我并不认为 NoSQL 会代替 SQL。虽然 NoSQL 出现的时候,原本表达的意思是 “NO SQL (没有 SQL) ” ,但是我觉得另外一种对 NoSQL 的解释更合适,也就是“ N ot O nly SQL ( 不仅仅有 SQL )”。NoSQL 不是 SQL 的替代品,应该是 SQL 的有力补充。在 NoSQL 运动中,涌现出来的非常优秀的 NoSQL 系统大多都有自己的独有的接口协议,比如 Redis、MongoDB、Cassandra、图数据库等等。他们都有各自非常适用的使用场景,比如 MongoDB 贴近面向对象,图数据库适合节点的图关系运算。而 Redis 贴近开发者数据结构思维,相信每个开发者都是从数组、hash 表、队列这样的数据结构中成⻓起来的。
另外,Redis 本身是一个非常优秀的产品,它的普及程度非常高,特别是在互联网行业。在每个互联网公司,Redis 都已经成为工程师开发工具箱中,必备的工具之一。Redis 已经是开发者除 SQL 之外,第二熟悉的产品了。
但是,选择 Redis 协议,也给我带来一些实际的困扰,我们有些使用者最初接触 Tedis 时,总是拿我们和 Redis 相比。但是,虽然我们采用的是 Redis 接口,但是 Tedis 本身并不对标 Redis 这个产品。Redis 是非常优秀的缓存。虽然 Redis 也可以开启持久化功能,由于 Redis 本身架构设计,开启持久化的 Redis 仍然不能达到“实际上的 CA”(effectively CA),和 100% 的持久性(durability)。这是 Redis 和 Tedis 的一个很大的区别,Tedis 是一个数据库,不是一个缓存。
讨论完上面的 2 个架构思考,我们来看一下 Tedis 的架构设计。
在 Tedis 中,我们封装了一个 TiKV 的 SDK,对 Redis 的协议进行了解析,并且将 Redis 协议转成对 TiKV 的调用。
作者介绍: 陈东明,饿了么北京技术中心架构组负责人,负责饿了么的产品线架构设计以及饿了么基础架构研发工作。曾任百度架构师,负责百度即时通讯产品的架构设计。具有丰富的大规模系统构 建和基础架构的研发经验,善于复杂业务需求下的大并发、分布式系统设计和持续优化。个人微信公众号 dongming_cdm。