ofey404 / tiup-error-inj2

Minor task for PingCAP Internship Interview. Copied from [pingcap/tiup](https://github.com/pingcap/tiup)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Minor task for Pingcap Internship Interview

基于 tiup 进行开发。

一些早期测试功能用的代码存放在ofey404/tiup-error-inj,还有开发早期的日志

Task Description

小作业:实现一个工具,支持在本地一键启动一个 “支持动态错误注入的 TiDB 集群” 用于测试,同时希望工具比较易用。

工具可以接受的输入参数:

  • pd/tidb/tikv 二进制文件路径
  • pd/tidb/tikv 实例数
  • 支持以下错误注入的功能
    • 重启一个 tikv 实例
    • 给一个 tikv 实例制造网络分区(比如:让一个 tikv 实例连接不上其它 tikv 实例的 advertise-addr)

举个例子,你可以实现一个命令行工具

启动集群:cli start cluster --tikv.path bin/tikv-server --tikv.count 3

重启 tikv-0 实例:cli restart tikv-0

隔离 tikv-0 实例:cli partition tikv-0

一些参考资料:

Usage

启动一个支持错误注入的 playground

# In repository root:
go build
./tiup playground --error-injection

原本 playground 的所有参数都适用:

./tiup playground v3.0.10 --db 3 --pd 3 --kv 3

Cmd:restart

使用 pid选择实例,和 playground 的其他子命令( eg:scale-in )的工作方式保持一致。pid可以通过display子命令得到。支持一次传入多个pid

./tiup playground restart --pid 1000
./tiup playground partition --pid 1000 1001

restart命令执行之后,对应的 tikv 实例重启时,日志中会出现几条can not register addr to pd的错误,但是查看dashboard仍然能确认tikv在线。tikv启动后,会一直向PD发送心跳信息,因此可以推断重连成功了。

Cmd:partition

同样使用pid选择实例。pid可以通过display子命令得到。支持一次传入多个pid

./tiup playground partition --pid 1000
./tiup playground partition --pid 1000 1001

partition命令将会阻断所有向该实例--advertise-addr发起的 tcp 连接。

Design

使用 Golang 来编写。可以利用现有的模块。

说到隔离某个实例,最先想到的功能肯定是 iptables。隔离某个实例,就创建对应的规则。可以使用 --owner 参数来指定对应的进程,参照 iptable Tutorial

不过它是内核级功能,普通的 go 程序不能像它一样直接控制经过某个端口的包,也不能抢占端口。

让一个 tikv 实例连接不上其它 tikv 实例的 advertise-addr

Proxy server 做到的事情是端口转发+处理。

结合 proxy 的特性和隔离的要求,可以做出以下设计:

+-----------------------+                                         +--------------------------+
|                       |                                         |                          |
|            +----------+                                         +---------+                |
|            |          <-----------------------------+           |         |                |
|            |Advertise |                             |           |Advertise|                |
|            |Addr      +-------------+               |           |Addr     |                |
|            |          |    +--------v-------+       |           |         |                |
|            +----------+    |                |       |           +---------+                |
|                       |    | Proxy Server 1 |       |           |                          |
|                       |    |                |       |           |                          |
|  tikv1     +----------+    +--------+-------+       |           +--------+      tikv2      |
|            |          |             |               |           |        |                 |
|            |  Listen  |             |               |           | Source |                 |
|            |  Port    +<------------+               +-------------Port   |                 |
|            |          |                                         |        |                 |
|            +----------+                                         +--------+                 |
|                       |                                         |                          |
|                       |                                         |                          |
|            +----------+                                         |                          |
|            |          |                                         +----------+               |
|            |  Source  |                                         |          |               |
|            |  Port    |                                         |  Listen  |               |
|            |          |                                         |  Port    |               |
|            +----------+                                         |          |               |
|                       |                                         +----------+               |
|                       |                                         |                          |
|                       |                                         |                          |
+-----------------------+                                         +--------------------------+

在启动每一个实例的时候,指定一个对应的 advertise-addr,同时启动一个 Proxy server 将 advertise-addr 的流量转发到真实的 Listen Port。

初始 proxy 可以设置成直接转发,执行partition等命令时,则修改 proxy server 的设置。

这个设计还可以更精细地控制错误的类型,因为设置的每一个 proxy 相当于完全控制了这条连接的延迟、丢包等信息。

proxy server 程序的性质:

  • 需要在集群启动期间保持运行。
  • 执行 partition 命令时,修改后台的 proxy server 的状态。
  • 最好能在集群关闭时自动停止。

参照 playground 的实现:

  • 不需要考虑持久化。
  • 所有实例在同一个单机上运行,不需要考虑将 proxy 运行在多台机器上(来均衡负载)的情况。

start, restart 等功能和 playground 高度重合,可以考虑为 playground 增加一个子命令/flag 这种实现方式。

partition 命令

  • 如何更改 Proxy 设置?
    • 在执行 partition 命令的时候,用进程间通信方式告知对应的 Proxy Server。服务没有中断时间,但实现较为复杂。
    • 或者直接关闭 Proxy Server 然后用新的配置重启一次。实现简单,但是下线/上线之间服务会中断,不利于频繁/精细的调节网络状况。

发现playground自带一个方案,用http请求和后台运行的playground实例通信,把这个机制拿来用了。

Implementation

所有的修改都在components/playground/目录下进行。playground本身是一个子模块,可以通过如下的方式调试:

cd components/playground
go build
tiup --binpath ./playground playground --error--injection

playground的子命令(eg:partition--help)无法单纯通过--binpath的方式测试到,会出现解析flag错误的bug。

可以通过如下的方式进行调试:

cp ./playground ~/.tiup/components/playground/v1.2.1/tiup-playground
tiup playground --help

Flag: --error-injection

打开这个flag以后会发生的事:

对数据结构做的主要改动:

bootOptions增加了err_inj属性

TiKVInstance增加AdvertisePort属性,更改了对应的Start方法

playground增加了列表proxys,用于存放错误注入使用的代理服务器。

Cmd: restart

playground的命令-后台通信机制是,主进程开一个http服务器,然后监听进来的命令。

执行命令时,经历了这样的事,以display命令为例:

  • newDisplay()设置的display函数被调用,向playground发送一条请求。
  • playground调用对应的handleDisplay函数来处理请求,返回数据。

restart命令的解析侧和display等并没有太大区别,略过。

服务侧handleRestart的实现如下:

  • syscall.Kill掉实例对应的进程,但是保留TiKVInstance的数据结构在playground.tikvs中。
  • 然后重新调用startInstance
    • startInstance需要一份context,这样在playground进程关闭的时候,它创建的所有子进程也会一并关闭。
    • WARNING: 这里做了一个临时的更动,在bootCluster函数中保存下了一份context,然后在handleRestart`中使用了它。这并不是一个好事,因为并不是这个对象所有的部分都会使用这个context,有的是直接在对象启动的时候通过参数传进去的,这种不一致性可能会在将来的维护中造成bug。

Cmd: partition

同样讨论服务侧的handlePartition

简单遍历代理列表,根据pidip:port,改变ip:port对应的代理的设置。

Milestone

  • 201024 - 201025:全天满课……
  • 201025 - 201027:阅读必要的文档,实验了一些功能,详见开发日志
  • 201027 - 201029:阅读 tiup 的代码,在其基础上实现了一些功能。
  • 201029 - 201030:完成各个命令的开发、测试,编写文档。

About

Minor task for PingCAP Internship Interview. Copied from [pingcap/tiup](https://github.com/pingcap/tiup)

License:Apache License 2.0


Languages

Language:Go 93.7%Language:Shell 3.8%Language:Smarty 2.0%Language:Makefile 0.3%Language:Dockerfile 0.1%Language:HTML 0.1%