vlambda博客
学习文章列表

开源中间件Vitess助力MySQL实现分库分表

关于Vitess

Vitess自2011年以来一直为YouTube的所有数据库流量提供服务,目前已被许多企业采用,以满足其生产需求。

Vitess是一个用于部署、扩展和管理大型mysql实例集群的数据库解决方案。它的架构是在公共或私有云架构中高效运行,就像在专用硬件上一样。它结合并扩展了许多重要的mysql特性和nosql数据库的可伸缩性。

Vitess可以解决以下问题
1. 实现MYSQL的分片,应用只需很少的更改或无需更改
2. 部署和管理大型数据库集群实例
3. 裸设备到云的迁移
Vitess相对MySQL改进
MySQL
Vitess
每个MySQL连接的内存开销都在256KB到3MB之间,具体取决于您使用的是哪个MySQL版本。随着用户群的增长,您需要添加RAM来支持更多连接,但RAM无助于加快查询速度。另外,与获取连接相关的CPU成本也很高。
Vitess基于gRPC的协议创建了非常轻量级的连接。Vitess的连接池功能使用Go的并发支持将这些轻量级连接映射到一小群MySQL连接。因此,Vitess可以轻松处理数千个连接。
编写不好的查询(如未设置LIMIT的查询)可能会对所有用户的数据库性能产生负面影响。
Vitess采用SQL解析器,使用一组可配置的规则来重写可能会损害数据库性能的查询。
分区是对数据进行分区以提高可伸缩性和性能的过程。MySQL缺乏本地分片支持,要求您编写分片代码并在应用程序中嵌入分片逻辑。
Vitess支持各种分片方案。它还可以将表迁移到不同的数据库中,并扩大或缩小碎片的数量。这些功能是非侵入式执行的,只需几秒钟的只读停机时间即可完成大部分数据转换。
使用可用性复制的MySQL集群具有主数据库和一些副本。如果主人失败,副本应该成为新的主人。这要求您管理数据库生命周期并将当前系统状态传达给您的应用程序。
Vitess有助于管理数据库场景的生命周期。它支持并自动处理各种场景,包括主站故障切换和数据备份。
MySQL群集可以为不同的工作负载定制数据库配置,例如用于写入的主数据库,用于Web客户端的快速只读副本,批处理作业的较慢只读副本等等。如果数据库具有水平分片,则每个分片都会重复该设置,并且该应用需要插入逻辑以了解如何找到正确的数据库。
Vitess使用由一致数据存储支持的拓扑,如etcd或ZooKeeper。这意味着群集视图始终是最新的,并且对于不同的客户端是一致的。Vitess还提供了一个代理,可以有效地将查询路由到最合适的MySQL实例。
Vitess整体架构
Topology
Topology服务是一个包含服务器信息,分片方案和主从信息的元数据信息存储服务。Topology服务是基于一致性存储方案来实现数据一致性,例如:zookeeper和etcd。用户可以通过使用vtctl(命令行)和vtctld(web)访问Topology。
vtgate
vtgate是一个轻量代理服务器,它将查询路由到正确的vttablet并将合并的结果返回给客户端。vtgate接收到请求时会对sql进行解析,根据Topology服务中的元数据判断路由到哪个vttablet;
vtgate是直接接受应用程序发起的查询的服务。因为客户端只需要能够找到一个vtgate实例即可正常访问,所以客户端的实现可以非常简单。
vttablet
vttablet是一个位于MySQL数据库实例前面的代理服务器,并且要求与对应的MYSQL实例部署在同一个Pod上。在JED中对于每个MySQL实例对应的都有一个JED-Tablet实现
vtctl
vtctl是用于管理弹性数据库集群的命令行工具。它允许人或应用程序轻松地与弹性数据库实现交互。通过Vtctl可以标识主从数据库, 创建表, 启动故障转移, 执行分片(重新分片)等操作。
vtctld
vtctld是一个HTTP服务器,允许您浏览存储在锁服务器中的信息。
vtworker
vtworker负责处理长时间运行的进程。如:
1. 在分片分割和连接过程中重新划分不同的作业检查数据完整性
2. 垂直分割不同作业检查垂直分割和连接期间的数据完整性
vtctlclient
通过客户端进行基本功能的校验。
使用方法:vtctlclient -server 127.0.0.1:15999 command param
Vitess的使用方式
Vitess借助Kubernetes能更好的实现逻辑库及节点管理。
Kubernetes 是 Google 开源的 Docker 容器集群管理系统,Vitess 是 Kubernetes 用户的逻辑存储引擎的一个可选项。
Kubernetes 对一个计算集群中的节点进行调度,对这些节点之上的负载进行管理,并对包含有同一应用的容器进行分组以易于管理和发现。使用 Kubernetes,你可以很容易去创建和管理一个 Vitess 集群,可谓开箱即用。
基本概
keyspace
keyspace 是逻辑上的数据库,在非shard场景下,一个keyspace对应一个MYSQL DataBase。从Keyspace中读取数据和从一个MYSQL DataBase中读取数据很像。但是根据读取数据时不同的一致性要求,可以从一个master database或者从一个replica读取数据。当一个keySpace被sharding成多个Shard时,一个keyspace会对应多个MYSQL database。在这种情况下一个查询会被路由到一个或者多个shard上,这取决于请求的数据所在的位置。
shard
一个shard就是在一个keyspace中的一个 horizontal partition 。每个 shard 都会包含一个master实例和多个replica实例,目前一个shard包含一个Master实例,一个Replica实例和一个ReadOnly实例,但是若支持半同步复制则需要在一个Shard中包含一个Master实例,两个Replica实例和一个ReadOnly实例。而且不同的shard之间绝对不会存在数据重叠的现象。
master
主库提供读写服务
replicate
提供读服务,缓解主库读压力
rdonly
会与主库断开复制,允许异步的服务(备份、分析)使用
从上面可以看出一个KeySpace可以跨越多个Mysql实例,而且每个Shard中的数据都是KeySpace中的一个数据子集,一个KeySpace由分散在各个Shard中的数据子集组成。每个Shard在物理硬件上由多个MySQL实例和Tablet实例组成,一个shard具体包括:一个Master Mysql实例、一个Replica MySQL实例、一个ReadOnly MySQL实例和三个Tablet实例。
Vindexes分片键(路由)的设置
选择作为分片键的字段值应尽量唯一;
在路由计算之前先将Sharding Key转换成字节数组,[0x80]是Sharding key的一个中间值。比如一个KeySpace如果有两个Shard,如果Sharding key对应的字节数组小于0x80的可以落到一个Shard上,大于或等于0x80则落到另一个Shard上。
下面是4个shard的例子:

我们用线段来代表KeyRange,线段的最小值[0x00]、最大值[0xFF]。从[0x00]到[0xFF]整条线段代表了整个KeyRange。
Start=[0x00], End=[0xFF]:整个Key Range,也可以用空值表示,比如Start=[], End=[]
Start=[0x00], End=[0x80]:小于0x80的 Key Range,整个Range的前1/2
Start=[0x80], End=[0xFF]:大于0x80的 Key Range,整个Range的后1/2
Start=[0x40], End=[0x80]:第二个1/4 Key Range.,整个Range的1/4