数据库调优能够使数据库利用运行得更快,但对于很多人来说,对数据库内核进行调优是一项很有挑战的“技术活”,是只属于少部分内核研发们的“游戏”。但即便是他们,对数据库内核进行性能调优,也充斥了不确定性,它须要综合思考各种简单因素,如硬件层面的 CPU、 I/O、 内存和网络,以及软件层面对于操作系统、中间件、数据库参数等配置,还有运行在数据库上的各种查问和命令等。在本次 Hackathon 2021 较量中,TPC 战队就实现了这一项“挑战”,采纳 bottom-up 的设计思路,更好地利用硬件资源,应用 TPC (thread-per-core) 线程模型优化了 TiKV 的写入性能、性能稳定性和自适应能力。TPC 战队也凭借这一硬核我的项目一举斩获了三等奖与技术后劲奖。

“该我的项目是本届 Hackathon 中最硬核的我的项目,我给了十分高的分数。 TPC 在其中做了十分多的工作,我预感到后续落地的难度,他们用了 io uring,不过貌似也遇到了不少的坑,前面也能够抉择 AIO 或者独自的异步线程机制。因为用了新的 raft engine(这个会在 TiDB 5.4 GA),也很不便做 parallel log write,充分利用多队列 IO 个性。这个个性在 Cloud 下面也是很要害的,因为 EBS 这些盘单线程写入 IOPS 其实真不高。另外,我看他们前面还会去掉 KV RocksDB 的 WAL,这样几个线程池就真能合并,只做计算操作,IO 操作都齐全变成异步了。”——评委唐刘

TPC 战队由来自 TiDB 分布式事务研发团队的陈奕霖与赵磊组成,其中,陈奕霖从 2019 年就加入 TiDB Hackathon ,并凭借线程池我的项目拿了当年的一等奖,而彼时他还是一名刚刚进入 PingCAP 的实习生。现在已毕业的他,留在 PingCAP 持续做事务相干的研发工作,曾经是一名 TiDB Hackathon 老选手了。

TiDB Hackathon 的魅力

陈奕霖:其实对于 PingCAPer 而言, Hackathon 是一个发现更多可能性的机会。咱们平时工作中都有着很多紧迫的我的项目,没机会摸索 TiDB 更多新的可能性,Hackathon 就给予这样的机会。在平时的工作场景中,咱们常常会产生一些想法,但没机会去尝试。 在 Hackathon 中就能够将这些想法实际进去,并通过 DEMO 展现它的成果与后劲,如果实现得好,最初还有可能落地进入生产代码。

我的项目灵感起源

陈奕霖:赵磊十分渴望做这个我的项目,我的项目灵感也次要来源于他。平时在做内核开发以及解决一些用户问题时,咱们发现 TiKV 的整体性能比拟个别,并且有着很强的不确定性,难以调优。赵磊在钻研另一款数据库产品的代码时,发现那个架构中的一些技术其实能够无效晋升 TiKV 的性能。所以就想把该产品架构思路中用到的一些技术利用到 TiKV 来,看是否能晋升 TiKV 的性能以及稳定性。
TPC 我的项目的首要目标在于性能晋升,TiKV 对于资源的利用始终不是很好,如对 CPU 或 IO 资源利用不充沛,通过该架构能够通过并发写 WAL 实现对 IO 资源的充分利用。线程池方面的新架构也能够比拟正当地去布局 CPU 的资源应用,特地是在云环境下,能够让 TiKV 失去更稳固、更可预期的性能。

较量中的异步合作

陈奕霖:咱们差不多在元旦假期才开始做初步开发工作,与平时工作时差不多,咱们大部分工夫还是异步化的合作,我有什么停顿就间接同步给赵磊,这个过程可能会通过邮件或 Github 告诉进行。开发过程次要分为两大块:一方面是改 TiKV 自身的 raftstore ,这是赵磊做的。另一方面是对于 Raft engine, TiKV 用来存储 Raft 日志的一个组件,我来它的异步化以及写的并发化。

其中,Raftstore 蕴含两个 thread pool:

  • store pool 用于解决 raft message、append log 等,raft log 会写入 raft db;
  • apply pool 用于解决 committed log,数据会写入 kv db,目前 raft db 和 kv db 均应用 RocksDB,之后 raft db 会切换到 raft-engine。

RocksDB 无奈很好利用古代高速硬盘,它的 foreground write (WAL) 只能提供 1 个 I/O depth 且 write group 间同步、排队的耗费很大,而 NMVe SSD 等高速硬盘须要高的 I/O depth 来打满 IOPS,或者大的 I/O size 加上不那么高的 I/O depth 来打满 bandwidth,但大的 I/O size 不适宜 OLTP 零碎,因为攒大 batch 通常意味着高提早。

为了优化 TiKV 的 disk 应用,raft engine 须要反对并发写 WAL 或者拆分 raft db 来并行写多个 WAL 文件,为了更偏心和 upstream TiKV 做性能比照,本次 Hackathon 没有对数据模型做很大改变,会实现并行写 WAL,不会拆分 raft db。而为了最大化 disk 压力、更好的 CPU 使用率以及更好的性能稳定性,TPC 抉择应用 async I/O 来实现该性能。

Store pool 实现了上述性能后,它的性能应该会大幅优于 apply pool,但可能会耗费更多的资源从而影响整体的性能,如耗费了更多的 CPU 和 disk I/O 资源导致 apply pool 变慢、积攒太多 committed logs 导致 OOM 等,且整个 pipeline 的性能受限于最慢的一个阶段,须要依据最慢的阶段做 back pressure,如调整 store pool 和 apply pool 的线程数量从而保障速度匹配。但拆分多个线程池切实是不易用、不灵便,为了防止手动调优,咱们将 store pool 和 apply pool 合并为单个线程池。为了实现这一指标,raft engine 应用 async I/O 也是必须的,kv db 同样须要应用 async I/O,但 kv db 实践上能够不写 WAL,因为数据可通过 raft log 回放且该性能已有计划,在 Hackathon 上会强行去掉 kv db 的 WAL。除了 async I/O 外,还须要实现 CPU scheduler 来保障当 CPU 成为瓶颈时,单个线程内不同工作成比例地应用资源,如原来 store pool 和 apply pool 的工作各应用 50% 的 CPU 资源。

有了 CPU scheduler 后能够把更多的线程池合并在一起从而实现真正的 unified thread pool,如 gRPC thread pool、scheduler worker pool、unified read pool、RocksDB background threads、backup thread pool 等,CPU scheduler 会给每个原先 thread pool 的任务分配肯定比例的资源,且可动静调整,从而晋升资源缓和时的性能稳定性,实现自适应,防止手动调参。

遇到的最大技术艰难

陈奕霖:这一次咱们用的各种技术都是特地激进和外围的技术,遇到了很多依赖库或者 Linux 内核的一些意外状况,编写时有一些货色并不合乎预期。比如说咱们用的 thread per core 库,当咱们想要依据 latency 去做抢占的时候,它在绝大多数的内核上都不能工作。
此外,咱们在 AWS 上尝试了很多种内核。当应用 AWS Linux 默认提供的内核配合 IO uring ,遇到很多问题。起初,咱们辗转到一个更新的内核上终于能够应用了。另一方面是文件系统,咱们罕用的有 ext4 和 xfs 两种文件系统,它们在异步写的行为有一些区别,咱们也是尝试多种内核以及换不同的文件系统后,才终于找到某一种组合,根本合乎咱们对于异步写的行为预期。咱们整体过程中遇到的最大问题,就是用的的技术太不成熟了,遇到了很多内核方面的坑,这方面其实还挺苦楚的。

较量过程中有什么遗憾?

陈奕霖:比拟遗憾的是工夫比拟紧,对整个零碎的调优还没有调到比拟好的水平,最初成果比咱们设想中的要差一点。在整个过程中,咱们花了大量的工夫让这个我的项目跑起来,让它根本合乎咱们的预期。
较量中有一个乏味的事,我其实始终都不分明队伍的宣言是什么,起初到现场才发现队旗上面的小字写的是“冠军被我内定 or 小丑竟是我本人”,后果在 Hackathon 的前几天,我忽然发现赵磊把他的头像改成了小丑……

本次较量体验

陈奕霖:之前赵磊跟咱们分享其余技术架构时,还只是一个理念或者概念层面上的,理论使用到 TiDB 上会怎么样? TiKV 的问题到底是不是在这里?其实咱们也不是很分明。通过这次 Hackathon ,咱们证实了这个想法肯定水平是对的,是的确有用的,TiKV 也因而失去了改良。我想这也是 TPC 这个我的项目给 TiKV 这个产品的进化验证了一条正确的路。

对我的项目将来有什么期待?

陈奕霖:我感觉如果间接把这次在 Hackathon 上应用的技术栈利用到 TiKV 上,可能还不是特地可行。就像唐刘老师在评估中提到的,咱们用 io uring 遇到了很多问题,然而其实能够转而求其次去应用 Linux AIO 之类的。同时,像 Raft engine 这个货色,它的异步化将来也是能够推动的。这个我的项目比拟大的作用就是指明了 TiKV 可能的演进方向。