前两天发表了价值10万元的TiDB Hackathon创意,反响还不错。可惜这个项目最大的问题是投入成本过大,至今没有天使投资人出现。所以只好再发一个,这次的特点就是成本低,见效快,投入产出比高!
先说问题。
TiKV并不单纯是给TiDB用的,作为CNCF的开源项目,是Cloud Native基础设施的一块重要拼图。如果想以各种有趣的姿势来玩耍TiKV,我们首先需要有客户端来跟TiKV进行交互,这是绕不过去的。
遗憾的是,到目前为止,我们只有一个功能完备,生产环境验证的TiKV客户端——就是内嵌在TiDB里的那一个。如果要使用的话,需要引入庞大的TiDB依赖,更要命的是,只支持Go一种语言。
虽然我们有一些其他语言的port版本,比如 Java,Rust,C,不过大多数功能有缺失。而且没经过充分验证,生产环境也不太敢上。不得不说,这对社区很不友好了。
所以Hackathon项目就是搞多种语言的客户端呗?
并非如此,实际上我怀疑两天时间写一个客户端都是完成不了的,因为开发一个TiKV客户端其实很难。主要体现在:
- 客户端是分布式事务的协调者,需要处理大量微妙的事务逻辑
- 客户端需要从PD查Region元信息,并维护一部分缓存
- 客户端要处理各种错误和异常
- 需要port大量的单元测试和集成测试来保证正确性
我想做的是充分利用现有的资源,做一个TiKV客户端测试框架,让客户端的测试验证变得更容易。开发客户端的时候,不用再写测试了,这不仅可以节省工作量,而且使用标准的流程来验证客户端,可以让我们对不同实现的质量更有信心。
我们看图说话,描述一下工作原理。
TestAdapter
为了接入测试框架,用户需要为开发中的客户端写一点简单的胶水层代码来跟测试框架交互,也就是TestAdapter。TestAdapter需要按照协议启动一个HTTP服务,本质上就是一个创建和调用Client的代理。
MockTiKV / MockPD
客户端的测试经常依赖于TiKV/PD的特殊状态,比如Region发生leader切换,或者Region在特定的位置分裂,或者TiKV宕机,等等。
但是我们在测试的过程中,不太可能去启动一套真正的集群,而且更不太可能去精细地控制集群的内部状态。所以目前TiDB的做法是用Go写了个假集群,也就是MockTiKV/MockPD,它们提供跟真正集群一样的gRPC服务,同时暴露一些接口来设置内部状态。
测试的启动(蓝色箭头)
开发者把TestAdapter的URI填入测试框架的网页输入框,点击开始测试。
测试框架在后台开启测试任务,并依次运行准备好的所有测试用例。
测试运行(黄色箭头)
每个测试在运行过程中会先创建Mock集群,然后把Mock集群的服务地址交给TestAdapter,创建一个或多个Client实例。随后,测试用例不断地给TestAdapter和Mock集群发消息来完成测试。
举个例子吧,比如测RawPut这个功能,过程就是先通过TestAdapter调用Client的RawPut接口,随后再调用Mock集群的RawGet接口看看是不是被写入了。
测试的过程中通过Admin API来控制Mock集群的状态,甚至通过failpoint注入一些错误。
测试报告(紫色箭头)
每个测试用例的结果返回给测试任务,汇总后生成测试报告展示在网页上。
客户端可以选择只支持部分功能,比如只支持RawKV,或者只支持2PC TxnKV。测试报告也做一个分门别类,分别指明客户端对于每种功能是通过,不支持,或者有bug。对于有bug的情况,可以提供相关的运行日志供检查。
这一套框架长期来看收益应该是很好的。在减轻客户端开发者负担的同时,最大的好处就是测试用例可以复用,当我们发现新bug后,可以做到一次添加就测试所有客户端的效果。后面我们还可以在官网上做一个大的客户端Dashboard,方便开发者进行选择。
与此同时,这个项目做起来工作量也不大。MockTiKV和MockPD可以复用之前的代码,只是要封装网络层。测试用例也可以从TiDB现有的代码移植,同样用Go语言的话移植成本也会比较低。
最后还有个彩蛋,就是这个项目其实之前我跟几个小伙伴已经做了一些微小工作了(tikv/client-validator,tikv/mock-tikv),后来由于个人原因(主要是懒)没有继续。当时的进展其实已经不错了,可以以命令行的方式运行并输出简单的报告,不过测试用例是很缺的,只有rawkv的简单功能测试。
大体上就是这样了,有兴趣的话,记得来联系我啊。