Skip to content

Commit

Permalink
Replace images in blog-cn (Part-1) (pingcap#186)
Browse files Browse the repository at this point in the history
* replace images in 30mins-become-contributor-of-tikv

* replace images in add-a-built-in-function

* replace images in building-distributed-db-with-raft

* replace images in distributed-system-test-2

* replace images in distributed-system-test-3

* replace images in flame-graph

* replace images in for-community-tidb-2019-level-up

* replace images in  how-do-we-build-tidb and fix some typos

* replace images in grpc-rs and fix some typos

* replace images in how-tikv-store-get-data
  • Loading branch information
siyu-hu authored and YiniXu9506 committed Mar 21, 2019
1 parent ef5f4ad commit 95126db
Show file tree
Hide file tree
Showing 56 changed files with 105 additions and 84 deletions.
2 changes: 1 addition & 1 deletion 30mins-become-contributor-of-tikv.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ tags: ['TiKV','社区','Contributor']

SQL 语句发送到 TiDB 后经过 parser 生成 AST(抽象语法树),再经过 Query Optimizer 生成执行计划,执行计划切分成很多子任务,这些子任务以表达式的方式最后下推到底层的各个 TiKV 来执行。

![图 1](https://upload-images.jianshu.io/upload_images/542677-5e242bc6212f6b8c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](media/30mins-become-contributor-of-tikv/1.png)

<center>图 1</center>

Expand Down
2 changes: 1 addition & 1 deletion add-a-built-in-function.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,4 @@ SQL 语句发送到 TiDB 后首先会经过 parser,从文本 parse 成为 AST

编辑按:添加 TiDB Robot 微信,加入 TiDB Contributor Club,无门槛参与开源项目,改变世界从这里开始吧(萌萌哒)。

![](media/tidb-robot.jpg "tidb_rpbot")
![](media/add-a-built-in-function/tidb-robot.jpg)
14 changes: 5 additions & 9 deletions building-distributed-db-with-raft.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ tags: ['Raft', '数据分片', '水平扩展']
## Sharding 的几种策略
在集群中的每一个物理节点都存储若干个 Sharding 单元,数据移动和均衡的单位都是 Sharding 单元。策略主要分两种,一种是 Range 另外一种是 Hash。针对不同类型的系统可以选择不同的策略,比如 HDFS 的Datanode 的数据分布就是一个很典型的例子:

![][1]

![](media/building-distributed-db-with-raft/1.png)

### 首先是 Range
Range 的想法比较简单粗暴,首先假设整个数据库系统的 key 都是可排序的,这点其实还是蛮普遍的,比如 HBase 中 key 是按照字节序排序,MySQL 可以按照自增 ID 排序,其实对于一些存储引擎来说,排序其实是天然的,比如 LSM-Tree 或者 BTree 都是天然有序的。Range 的策略就是一段连续的 key 作为一个 Sharding 单元:

![][2]
![](media/building-distributed-db-with-raft/2.png)

例如上图中,整个 key 的空间被划分成 (minKey, maxKey),每一个 Sharding 单元(Chunk)是一段连续的 key。按照 Range 的 Sharding 策略的好处是临近的数据大概率在一起(例如共同前缀),可以很好的支持 range scan 这样的操作,比如 HBase 的 Region 就是典型的 Range 策略。

Expand All @@ -31,7 +30,7 @@ Range 的想法比较简单粗暴,首先假设整个数据库系统的 key 都
### 另外一种策略是 Hash
与 Range 相对的,Sharding 的策略是将 key 经过一个 Hash 函数,用得到的值来决定 Sharding ID,这样的好处是,每一个 key 的分布几乎是随机的,所以分布是均匀的分布,所以对于写压力比较大、同时读基本上是随机读的系统来说更加友好,因为写的压力可以均匀的分散到集群中,但是显然的,对于 range scan 这样的操作几乎没法做。

![][3]
![](media/building-distributed-db-with-raft/3.png)

比较典型的 Hash Sharding 策略的系统如:Cassandra 的一致性 Hash,Redis Cluster 和 Codis 的 Pre-sharding 策略,Twemproxy 有采用一致性 Hash 的配置。

Expand All @@ -46,7 +45,7 @@ Range 的想法比较简单粗暴,首先假设整个数据库系统的 key 都

在 TiKV 中,我们选择了按 range 的 sharding 策略,每一个 range 分片我们称之为 region,因为我们需要对 scan 的支持,而且存储的数据基本是有关系表结构的,我们希望同一个表的数据尽量的在一起。另外在 TiKV 中每一个 region 采用 Raft 算法在多个物理节点上保证数据的一致性和高可用。

![][4]
![](media/building-distributed-db-with-raft/4.png)

从社区的多个 Raft 实现来看,比如 Etcd / LogCabin / Consul 基本都是单一 raft group 的实现,并不能用于存储海量的数据,所以他们主要的应用场景是配置管理,很难直接用来存储大量的数据,毕竟单个 raft group 的参与节点越多,性能越差,但是如果不能横向的添加物理节点的话,整个系统没有办法 scale。

Expand Down Expand Up @@ -98,7 +97,4 @@ Spanner 的论文中并没有过多的介绍 pd 的设计,但是设计一个

在这里,TiKV 使用了一个 epoch 的机制,用两个逻辑时钟来标记,一个是 raft 的 config change version,另一个是 region version,每次 config change 都会自增 config version,每次 region change(比如split、merge)都会更新 region version. pd 比较的 epoch 的策略是取这两个的最大值,先比较 region version, 如果 region version 相等则比较 config version 拥有更大 version 的节点,一定拥有更新的信息。

[1]: http:https://static.zybuluo.com/zyytop/pcxq0hldin90nounfefy37t2/WechatIMG12.png
[2]: http:https://static.zybuluo.com/zyytop/5h4vfs0g6t7y3609lbuslozw/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-10-13%20%E4%B8%8B%E5%8D%884.40.22.png
[3]: http:https://static.zybuluo.com/zyytop/8kaltq5ww337kgxq63asdbnz/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-10-19%20%E4%B8%8B%E5%8D%886.14.37.png
[4]: http:https://static.zybuluo.com/zyytop/fgyzrywyj0bfl50ilz5t4k44/%E5%9B%BE4.png

16 changes: 9 additions & 7 deletions distributed-system-test-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ meetup_type: memoir

当然测试可能会让你代码变得没有那么漂亮,举个例子:

![](http:https://static.zybuluo.com/zyytop/igccqzz7wgbkuxtszt3fnnzs/1.jpg)
![](media/distributed-system-test-2/1.jpg)

这是知名的 Kubernetes 的代码,就是说它有一个 DaemonSetcontroller,这 controller 里面注入了三个测试点,比如这个地方注入了一个 handler ,你可以认为所有的注入都是 interface。比如说你写一个简单的 1+1=2 的程序,假设我们写一个计算器,这个计算器的功能就是求和,那这就很难注入错误。所以你必须要在你正确的代码里面去注入测试逻辑。再比如别人 call 你的这个 add 的 function,然后你是不是有一个 error?这个 error 的问题是它可能永远不会返回一个 error,所以你必须要人肉的注进去,然后看应用程序是不是正确的行为。说完了加法,再说我们做一个除法。除法大家知道可能有处理异常,那上面是不是能正常处理呢?上面没有,上面写着一个比如说 6 ÷ 3,然后写了一个 test,coverage 100%,但是一个除零异常,系统就崩掉了,所以这时候就需要去注入错误。大名鼎鼎的 Kubernetes 为了测试各种异常逻辑也采用类似的方式,这个结构体不算长,大概是十几个成员,然后里面就注入了三个点,可以在里面注入错误。

Expand Down Expand Up @@ -44,9 +44,9 @@ meetup_type: memoir

以前我遇到一个问题很有意思,当时我们在做一个消息系统,有大量连接会连这个,一个单机大概是连八十万左右的连接,就是做消息推送。然后我记得,当时的 swap 分区开了,开了是什么概念?当你有更多连接打进来的时候,然后你内存要爆了对吧?内存爆的话会自动启用 swap 分区,但一旦你启用 swap 分区,那你系统就卡成狗了,外面用户断连之后他就失败了,他得重连,但是重连到你正常程序能响应,可能又需要三十秒,然后那个用户肯定觉得超时了,又切断连接又重连,就造成一个什么状态呢?就是系统永远在重试,永远没有一次成功。那这个行为是不是可以预测?这种错误当时有没有做很好的测试?这都是非常重要的一些教训。

硬件测试以前的办法是这样的(Joke)
硬件测试以前的办法是这样的Joke

![](http:https://static.zybuluo.com/zyytop/qxx4emlxbxns9ifx4qpbwke6/2.jpg)
![](media/distributed-system-test-2/2.jpg)

假设我一个磁盘坏了,假设我一个机器挂了,还有一个假设它不一定坏了也不一定挂了,比如说它着火了会怎么样?前两个月吧,是瑞士还是哪个地方的一个银行做测试,那哥们也挺逗的,人肉对着服务器这样吹气,来看监控数据那个变化,然后那边马上开始报警。这还只是吹气而已,那如果更复杂的测试,比如说你着火从哪个地方开始烧,先烧到硬盘、或者先烧到网卡,这个结果可能也是不一样的。当然这个成本很高,然后也不是能 scale 的一种方案,同时也很难去复制。

Expand All @@ -64,7 +64,7 @@ It can be used to perform fault injection in the **POSIX API** without having to

举一个例子,正常来讲我们敲 ls 命令的时候,肯定是能够把当前的目录显示出来。

![](http:https://static.zybuluo.com/zyytop/9nido67ui4w89hyptchngewz/3.png)
![](media/distributed-system-test-2/3.png)

这个程序干的是什么呢?就是 run,指定一个参数,现在是要有一个 enable_random,就是后面所有的对于 IO 下面这些 API 的操作,有 5% 的失败率。那第一次是运气比较好,没有遇到失败,所以我们把整个目录列出来了。然后我们重新再跑一次,这时候它告诉我有一次读取失败了,就是它 read 这个 directory 的时候,遇到一个 Bad file descriptor,这时候可以看到,列出来的文件就比上面的要少了,因为有一条路径让它失败了。接下来,我们进一步再跑,发现刚列出来一个目录,然后下次读取就出错了。然后后面再跑一次的时候,这次运气也比较好,把这整个都列出来了,这个还只是模拟的 5% 的失败率。就是有 5% 的概率你去 read、去 open 的时候会失败,那么这时候可以看到 ls 命令的行为还是很 stable 的,就是没有什么常见的 segment fault 这些。

Expand Down Expand Up @@ -92,13 +92,14 @@ InnoDB: Error number 5 means 'Input/output error'.

换一个思路来看,假设没有这个东西,你复现这个 bug 的成本是什么?大家可以想想,如果没有这个东西,这个 bug 应该怎么复现,怎么让 MySQL 读取的东西出错?正常路径下你让它读取出错太困难了,可能好多年没出现过。这时我们进一步再放大一下,这个在 5.7 里面还有,也是在 MySQL 里面很可能有十几年大家都没怎么遇到过的,但这种 bug 在这个工具的辅助下,马上就能出来。所以 Fault injection 它带来了很重要的一个好处就是让一个东西可以变得更加容易重现。这个还是模拟的 5% 的概率。这个例子是我昨天晚上做的,就是我要给大家一个直观的理解,但是分布式系统里面错误注入比这个要复杂。而且如果你遇到一个错误十年都没出现,你是不是太孤独了? 这个电影大家可能还有印象,威尔史密斯主演的,全世界就一个人活着,唯一的伙伴是一条狗。

![](http:https://static.zybuluo.com/zyytop/alxnjqkoeq63zwvnru86poxu/4.jpg)
![](media/distributed-system-test-2/4.jpg)

实际上不是的,比我们痛苦的人大把的存在着。

举 Netflix 的一个例子,下图是 Netflix 的系统。

![](http:https://static.zybuluo.com/zyytop/yzje24743ddveinu1h7dwq15/5.png)

![](media/distributed-system-test-2/5.png)

他们在 2014 年 10 月份的时候写了一篇博客,叫《 Failure Injection Testing 》,是讲他们整个系统怎么做错误注入,然后他们的这个说法是 Internet Scale,就是整个多数据中心互联网的这个级别。大家可能记得 Spanner 刚出来的时候他们叫做 Global Scale,然后这地方可以看到,蓝色是注射点,黑色的是网络调用,就是所有这些请求在这些情况下面,所有这些蓝色的框框都有可能出错。大家可以想一想,在 Microservice 系统上,一个业务调用可能涉及到几十个系统的调用,如果其中一个失败了会怎么样?如果是第一次第一个失败,第二次第二个失败,第三次第三个失败是怎么样的?有没有系统做过这样的测试?有没有系统在自己的程序里面去很好的验证过是不是每一个可以预期的错误都是可预测的,这个变得非常的重要。这里以 cache 为例,就说每一次访问 Cassandra 的时候可能出错,那么也就给了我们一个错误的注入点。

Expand All @@ -114,7 +115,8 @@ InnoDB: Error number 5 means 'Input/output error'.

**Jepsen: Distributed Systems Safety Analysis**

![](http:https://static.zybuluo.com/zyytop/nrx2pne826o8rubsi4wfutez/6.jpg)

![](media/distributed-system-test-2/6.jpg)

大家所有听过的知名的开源分布式系统基本上都被它找出来过 bug。但是在这之前大家都觉得自己还是很 OK 的,我们的系统还是比较稳定的,所以当新的这个工具或者新的方法出现的时候,就比如说我刚才提到的那篇能够线性 Scale 的去查错的那篇论文,那个到时候查错力就很惊人了,因为它能够自动帮你探测。另外我介绍一个工具 Namazu,后面讲,它也很强大。这里先说Jepsen, 这货算是重型武器了,无论是 ZooKeeper、MongoDB 以及 Redis 等等,所有这些全部都被找出了 bug,现在用的所有数据库都是它找出的 bug,最大的问题是小众语言 closure 编写的,扩展起来有点麻烦。我先说说 Jepsen 的基本原理,一个典型使用 Jepsen 的测试通过会在一个 control node上面运行相关的 clojure 程序,control node 会使用 ssh 登陆到相关的系统 node(jepsen 叫做 db node)进行一些测试操作。

Expand Down
12 changes: 7 additions & 5 deletions distributed-system-test-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Simulate the following errors:

再来看看 Cloudera,下图是整个 Cloudera 的一个 Failure Injection 的结构。

![](http:https://static.zybuluo.com/zyytop/q5urfv8k4v3qv5dzjewtsf9p/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-12-07%20%E4%B8%8B%E5%8D%881.58.25.png)
![](media/distributed-system-test-3/1.png)

一边是 Tools,一边是它的整个的 Level 划分。比如说整个 Cluster, Cluster 上面有很多 Host,Host 上面又跑了各种 Service,整个系统主要用于测试 HDFS, HDFS 也是很努力的在做有效的测试。然后每个机器上部署一个 AgenTEST,就用来注射那些可能出现的错误。

Expand Down Expand Up @@ -104,13 +104,14 @@ Simulate the following errors:

+ american fuzzy lop

![](http:https://static.zybuluo.com/zyytop/tw2w9n4gz6g7x1nqjlr10dok/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-12-07%20%E4%B8%8B%E5%8D%882.12.41.png)
![](media/distributed-system-test-3/2.png)


其实还有一些更加先进的工具,大家平时觉得特别稳定的东西,都被摧残的不行。Nginx 、NGPD、tcpdump 、LibreOffice ,如果有用 Linux 的同学可能知道,还有 Flash、sqlite。这个东西一出来,当时大家很兴奋,说怎么一下子找了这么多 bug,为什么以前那么稳定的系统这么不堪一击,会觉得这个东西它还挺智能的。就比如说你程序里面有个 if 分支,它是这样的,假如你程序有一百条指令,它先从前面一直走,走到某条分支指令的时候,它是一直持续探索,一个分支走不下去,它会一直在这儿持续探索,再给你随机的输入,直到我探索进去了,我记下来了下次我知道我用这个输入可以进去特定的分支。那我可以再往下走,比如说你 if 分支进去之后里面还有 if ,那你传统手段可能探测不进去了但它可以,它记录一下,我这个可以进去,然后我重来,反正我继续输入这个,我再往里面走,一旦我探测到一个新的分支,我再记住,我再往里面走。所以它一出来的时候大家都说这个真厉害,一下发现这么多 bug。但最激动的不是这些人,最激动的是黑客,为什么?因为突然有很多栈溢出、堆溢出漏洞被发现了,然后就可以写一堆工具去攻击线上的这么多系统。所以很多的技术的推进在早期的时候是黑客做出来,但是他们的目的当然不一定是为了测试 bug,而是为了怎么黑一个系统进去,这是他们当时做的,所以这个工具也是非常强大、非常有意思的,大家可以拿去研究一下自己的系统。

大家印象里面各种文件系统是很稳定的,可是当用 American fuzzy lop 来测试的时候,被惊呆了。 Btrfs 连 5 秒都没有坚持到就跪了,大家用的最多的 Ext4 是最坚挺的,也才抗了两个小时!!!

![](http:https://static.zybuluo.com/zyytop/6u4uzgefxk7pt6ghf2fkxcia/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-12-07%20%E4%B8%8B%E5%8D%882.16.11.png)
![](media/distributed-system-test-3/3.png)

再来说说 Google,Google 怎么做测试对外讲的不多,最近 Chrome team 开源了他们的 Fuzz 测试工具 OSS-Fuzz,这个工具强大的地方在于自动化做的极好:

Expand All @@ -129,11 +130,12 @@ Simulate the following errors:

还有 Tracing,比如说我一个 query 过来,然后经过这么多层,经过这么多机器,然后在不同的地方,不同环节耗时多久,实际上这个在分布式系统里面,有个专门的东西做 Tracing ,就是 distribute tracing tools。它可以用一条线来表达你的请求在各个阶段耗时多长,如果有几段,那么分到几个机器,分别并行的时候好了多长时间。大体的结构是这样的:

![](http:https://static.zybuluo.com/zyytop/dtla8gkdbpqigym0kvzio04b/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-12-07%20%E4%B8%8B%E5%8D%882.19.33.png)
![](media/distributed-system-test-3/4.png)


这里是一个具体的例子:

![](http:https://static.zybuluo.com/zyytop/akcaktnflk9fajbr8skrrhrx/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202016-12-07%20%E4%B8%8B%E5%8D%882.20.13.png)
![](media/distributed-system-test-3/5.png)

很清晰,一看就知道了,不用去看 log,这事其实一点也不新鲜,Google 十几年前就做了一个分布式追踪的工具。然后开源社区要做一个实现叫做 Zipkin,好像是 java 还是什么写的,又出了新的叫 OpenTracing,是 Go 写的。我们现在正准备上这个系统,用来追踪 TiDB 的请求在各个阶段的响应时间。

Expand Down
Loading

0 comments on commit 95126db

Please sign in to comment.