cetus/doc/cetus-sharding.md

414 lines
21 KiB
Markdown
Raw Normal View History

2018-03-06 15:34:44 +08:00
# Cetus sharding版使用指南
## 简介
Cetus sharding版支持对后端的数据库进行分库可以根据hash/range方式对大表进行分布式部署提升系统整体的响应和容量。
## 安装部署
### 准备
**1.MySQL**
- 5.7.16以上版本(分布式事务功能需要)
- 数据库设计(即分库,根据业务将数据对象分成若干组)
- 创建用户和密码
- 确认Cetus可以远程登录MySQL
**2.Cetus**
- 根据MySQL后端信息配置users.json、sharding.json和shard.confvariables.json可选配具体配置说明详见[Cetus 配置文件说明](https://git.ms.netease.com/dbproxy/cetus/wikis/cetus-profile)
**3.LVS & keepalived**
- 确定LVS的监听ip和端口
- 根据实际情况和需求确定多个Cetus的LVS分发权重
- 配置keepalived.conf
### 安装
Cetus只支持linux系统安装过程详见[Cetus 安装说明](https://git.ms.netease.com/dbproxy/cetus/wikis/cetus-install)
### 部署
Cetus 在部署时架构图如下图所示。
<div align=center>
<img src="/uploads/a13916278f5a0317b5ebb9f5c656837b/Cetus_deployment_sharding.png" width="50%" height="50%">
</div>
Cetus位于应用程序与MySQL数据库之间作为前端应用与数据库的通讯。其中前端应用连接LVS节点LVS节点映射端口到多个Cetus服务后者通过自身的连接池连接到后端的数据库。
MySQL和Cetus可以部署在同一台服务器上也可以部署在各自独立的服务器上但一般LVS & keepalived与MySQL、Cetus分布在不同的服务器上。
### 启动
Cetus可以利用bin/cetus启动
```
bin/cetus --defaults-file=conf/shard.conf [--conf-dir/home/user/cetus_install/conf/]
```
其中Cetus启动时可以添加命令行选项--defaults-file选项用来加载启动配置文件且在启动前保证启动配置文件的权限为660--conf-dir是可选项用来加载其他配置文件(.json文件)默认为当前目录下conf文件夹。
Cetus可起动守护进程后台运行也可在进程意外终止自动启动一个新进程可通过启动配置选项进行设置。
## 数据库设计
### 1.专用术语
**1.数据分片**
按一定的规则,将数据表横向切分成若干部分并将其部署在一个或多个数据节点上。
**2.分片表**
即Sharding表将属于同一张表中的数据根据规则拆分成多个分片分别存入底层不同的存储节点。
**3.分片键**
即Sharding KeySharding表将根据此分片键再加上拆分规则从而成为sharding表。
**4.拆分方法**
目前支持的拆分规则有hash、range其中hash支持数字类型、字符串类型range支持数字类型、字符串类型、时间类型date/datetime
Hash分片即数据库中的Hash分区。首先将Sharding表中Sharding Key的数据进行hash然后根据制定的分片规则进行数据存储。Sharding Key常选用数字类型。
Range分片类似数据库中的Range分区。将Sharding表中Sharding Key的数据进行范围分片根据规则进行数据存储。Sharding Key常选用数字类型、时间类型DATE/DATETIME
**5.全局表**
Public表即全局表具有相同VDB的存储节点公共表数据是一致的即都是全量数据但不同VDB的存储节点公共表是不同的如果想具有相同公共表需要前端再处理例如配置表confVDB1和VDB2都需要需要前端应用分别写入VDB1、VDB2。
**6.VDB**
VDBVirtual DataBase非物理DB即逻辑DB主要对应分片表表现在业务数据层即代表此VDB内的数据有相同属性值可以根据此属性值进行数据的进一步拆分从而构成分片表例如订单数据和用户数据属于同一个VDB可以根据用户ID进行分片而仓储和商品可以放入另一个VDB。不同VDB之间的数据不能进行关联查询只有在同一个VDB内才支持。
### 2.设计原则
按业务数据的内在联系(例如,支持同一业务模块,或经常需要一起存取或修改等),将数据对象分成若干个组,使同一分组的数据表高度“内聚”,不同分组之间的表高度“独立”;找出每个组中各表共同的“根元”,以此作为分片键,对数据进行分片。
VDB要在业务设计之初确定后续的底层数据存储以及上层数据操作都会与此息息相关所以需要开发、DBA一同来设计。
以下是具体样例:
**用户VDBVDB_ACCOUNT**
描述:与用户订单相关联的业务
分片键ACCOUNT_ID
TB_ORDER订单表
TB_ACCOUNT用户信息表
TB_PAY_ORDER支付订单表
TB_CHARGE_ORDER充值订单表
TB_TRANSFER_RECORD转账记录表
TB_ACTIVITY_RECORD活动记录表
TB_REFUND_ORDER退款记录表
**产品VDBVDB_PRODUCT**
描述:与产品相关联的业务
分片键PERIOD_ID
TB_PRODUCT商品信息表
TB_PRODUCT_PERIOD商品期次表
## 主要功能概述
### 1.连接池功能
Cetus内置了连接池功能。该连接池会在Cetus启动时使用默认用户自动创建到后端的连接。创建的连接使用的database是配置的默认database这些选项是由DBA根据后端数据库的实际情况进行的配置。以确保主要的业务请求过来不需要临时建立连接并切换数据库。
### 2.数据分片功能
Cetus支持对后端的数据库进行分库可以根据hash/range方式对大表进行分布式部署提升系统整体的响应和容量。由于分片处理后数据的整体性被破坏为了保证查询的结果符合预期我们需要对SQL进行分析并改写后发送到不同的后端。
### 3.分布式事务处理
如果前端执行SQL时开启了事务start transaction则统一采用分布式事务处理除非开启了单点事务的注释功能如果未开启事务直接发送SQL指令 Cetus 在处理时会判断是否开启分布式事务。
### 4.结果集压缩
由于当连接距离较远网络延迟较大时结果集较大会很大幅度地增加数据传输时长降低性能因此针对高延迟场合Cetus支持对结果集的压缩来提高性能。
网络延迟越大开启结果集压缩功能的优势越大当连接距离较近几乎没有网络延迟时Cetus无形中增加了压缩和解压步骤反而降低了性能因此在延迟较小时不建议使用结果集压缩。
### 5.安全性管理
安全性管理功能包括后端管理、基本配置管理、查看连接信息、用户密码管理、IP许可管理、远程配置中心管理和整体信息查询。
用户可以通过登录管理端口查看后端状态增删改指定后端查看和修改基本配置包括连接池配置和从库延迟检测配置查看当前连接的详细信息用户连接Cetus的密码查询和增删改查看以及增删改IP许可(可以为每个用户以及管理员用户指定允许访问的来源ip地址但是无法为来自不同ip的同一用户提供不同的权限设置)重载远程配置和查看Cetus总体状态等具体管理操作相见[Cetus 分库(sharding)版管理手册](https://git.ms.netease.com/dbproxy/cetus/wikis/cetus-shard-admin)。
### 6.状态监控
Cetus内置监控功能可通过配置选择开启或关闭。开启后Cetus会定期和后端进行通信检测后端数据库的存活状态和主从延迟时间等。可通过登录管理端口SELECT * FROM backends查看。
后端状态包括unknown后端初始状态还未建立连接、up能与后端正常建立连接可以正常提供服务、down与后端无法联通无法正常提供服务、maintaining后端正在维护无法建立连接和delete后端已被删除
主从延迟检测检测设有阈值slave-delay-down和slave-delay-recover检测到的从库延迟超过slave-delay-down阈值后端状态将被设置为DOWN从库延迟少于slave-delay-recover阈值后端状态将恢复为UP。
### 7.TCP流式
针对结果集过大情况Cetus 采用了tcp stream流式不需要先缓存完整结果集才转发给客户端以避免内存炸裂问题降低内存消耗提高性能。
### 8.域名连接后端
支持利用域名连接数据库后端Cetus设有相关的启动配置选项disable-dns-cache选择是否开启解析连接到后端的域名功能开启后可以通过设置域名并利用域名访问后端。
### 9.insert批量操作
支持在insert语句中写多个valuevalue之间用","隔开前面的insert语句可省略例如
INSERT INTO table (field1,field2,field3) VALUES ('a',"b","c"), ('a',"b","c"),('a',"b","c");
## 注意事项
### 1.连接池使用注意事项
所有的后端MySQL节点都需要有相同的用户名及口令在conf/users.json中指定不在选项中指定的用户不能用来登录Cetus不能为每个不同的后端实例单独指定登录信息。用户连接Cetus时的用户名和密码不一定与后端一致可在conf/users.json中查看。
### 2.set命令的支持说明
我们支持使用以下session级别的set命令 Set names/autocommit。global级别的set命令统一不支持其他未列出的set命令不在支持范围内不建议使用。如果业务确实需要建议联系DBA将行为配置为默认开启。
支持CLIENT_FOUND_ROWS 全局参数属性的统一设置同一个Cetus只能选择打开或者关闭不支持对每个连接单独设置这项属性可以通过设置启动配置选项来打开默认关闭。不支持CLIENT_LOCAL_FILES。其他未列出的需要额外设置的特性请测试后再确认。
### 3.环境变量修改建议
虽然我们支持客户端对连接环境变量进行修改但是我们不建议在程序中进行修改。因为一旦变量有改动。我们需要在执行SQL前对连接状态进行复位会产生额外的请求到服务端客户端响应的延迟也会增加。
### 4.代码处理
能用程序代码实现的函数尽量不用 SQL 函数,最好先在程序中计算出结果,再把值传入 SQL如时间类函数 curdate(),字符串处理类函数 trim()。因为函数用于分库键将无法路由,导致查询语句需要发送到所有后端,单事务可以搞定的事情就变成了分布式事务,性能变差。
程序做分页任务时,尽量自己记录页偏移,因为 Cetus 做偏移时offset 会重写SQL 把 offset 置为零,数据全部取回后再截取该页需要的数据,这样一来数据量无形中就变大很多倍,且不能有效利用数据库索引,性能比较差,而且一旦数据超出内存阈值前端将接收到错误。
### 5.不支持 Kill query
不支持在 Sql 执行过程中 kill query操作一旦 Sql 语句开始执行就不能通过这种方式来终止此时可以连接Cetus 管理后端,通过执行 show connectionlist 命令查看正在执行的 Sql从而找到正在执行的后端信息通过数据库中 kill query的命令进行终止操作。
### 6.不支持TLS
不支持TLS协议目前不能在某种程度上使主从架构应用程序通讯本身预防窃听、干扰和消息伪造。
### 7.不支持多租户
目前分片版本还不支持。
### 8.不支持动态扩容
目前分库版暂不支持动态扩容,需要手工迁移数据,多数情况下需要“停机”扩容。
### 9.分区限制
目前只支持一级分区且最多支持64个分库全局表的更新数量太大会导致分布式事务性能急剧恶化建议4816个分库暂不支持二级分区分区的自增主键最好用第三方比如redis。
### 10.SQL书写规范
由于SQL需要进行完整解析器建议大家在书写涉及分片的SQL时要按照标准书写在测试环境下测试通过后再上线请遵循以下规范
1. 在Select语句中尽量为表达式列或函数计算列添加别名比如“select count(\*) rowcnt from ...”以利于提高SQL解释器的分析水平。
2. Sql文本要简洁针对sharding表如果有条件请务必加sharding key做为过滤条件。
3. 开启事务请使用start transaction。
4. 少用子查询这种写法,必须用的话,可以用关联查询语法进行替换。
5. Update/delete操作要根据sharding key进行过滤后操作仅针对分片表
6. For update语句不建议使用锁开销严重建议在应用端处理该业务逻辑比如引入分布式锁或者先分配给redis等等。
### 11.SQL支持
Cetus sharding版能支持大多数的SQL语句目前限制支持的功能有以下几种
**不支持项:**
**1.不支持COUNT(DISTINCT)/SUM(DISTINCT)/AVG(DISTINCT)**
全局表没有限制;针对分片表建议分开操作,即先用 distinct 获取所有后端节点的值,类似 select distinct val from xxx order by val然后将数据整合到一起做去重计数去重求和去重求平均值的工作。
**2.不支持LAST_INSERT_ID**
目前线上没有发现该用法,如希望获取全局唯一值建议使用 redis 获取另外Cetus本身也提供了一种方法select cetus_sequence(),即可返回一个 64 位递增不连续随机数字。
**3.不支持存储过程和视图**
**4.不支持批量sql语句的执行**
**5.不支持客户端的change user命令**
**6.不支持having多个条件**
**7.不支持含有any/all/some的子查询语句**
不支持含有any/all/some的子查询语句例如select dept_no,emp_no from dept_emp where emp_no > any (select emp_no from dept_emp where dept_no='d001');若需要可转成关联查询语句。
**8.不支持load data infile**
**9.不支持handler语法**
**10.不支持lock tables语法**
**11.多个聚合函数情况下不支持having条件**
**限制支持项:**
**1.ORDER BY的限制**
针对全局表没限制针对分片表排序字段不超过8个列ORDER BY需要使用列名或者别名目前暂且不支持使用数字。
**2.DISTINCT的限制**
针对全局表没有限制针对分片表仅支持DISCTINCT字段同时也是ORDER BY字段例如select distinct col1 from tab1 order by col1另外为了在使用上更加友好对于order by未写全的Cetus会进行补充例如selectdistinct col1,col2 from tab1 order by col1Cetus会改写为 select distinct col1,col2 fromtab1 order by col1,col2但如果写成select distinct * from tab1Cetus则会返回错误为了效率提倡使用标准写法以免造成不必要的资源开销。
**3.CASE WHEN/IF 的限制**
全局表没有限制针对分片表不能用于DML语句中也不能用在GROUP BY后可以用于SELECT 后,也可以作为过滤条件。
**4.分页查询的限制**
由于对分片的支持,我们带来的新限制。在结果集大于特定值时分页时,由于性能开销较大,可能无法返回准确值。
**5.JOIN的使用限制**
不支持跨库的JOIN非分片表可以在每个分片中都保存一份以提高join的使用成功率。
**6.Where条件的限制**
当Where条件中有分区列时值不能有函数转换也不能有算术表达式必须是原子值否则处理结果会不准确或者强制走全库查询增加后端数据库的负担。
目前支持有限的子查询类型以及有限的操作类型:支持子查询作为查询条件使用;支持子查询作为数据源使用。
**7.查询业务的限制**
在做SQL查询时应注意以下约束只支持同一个 VDB 内的关联查询;针对 sharding 表,在查询条件中可以使用 sharding key 的要求加上该过滤条件,
另外,使用 sharding key 时,不建议使用带有函数转换、算术表达式等逻辑处理, 会严重影响效率。
**8.PREPARE的限制**
不支持服务器端 PREPARE,可以用客户端的 PREPARE 代替。
**9.中文列名的限制**
对表列的中文列名或别名的使用有限制,使用中文列名或中文别名时必须加引号``。
### 12.事务处理限制
跨库事务的有限支持,针对同一分区键分布的事务,我们默认通过分布式事务方式执行,如果需要考虑性能,可以考虑在所有数据操作都在同一分区时,手动通过注释制定走单机事务提交。
不跨分区的事务需要在第一条语句中引用分区键方便Cetus进行SQL转发和路由并使用单机事务提升效率。
在分布式事务里面,要求用户尽量不要嵌入 select因为 select 是会加锁的,会导致性能非常差。
能用单事务就不要走分布式事务,所谓单事务就是此事务确定只会根据分片键定位到一个后端节点。
DML语句的限制Update/Delete 支持子查询,但子查询中不要有嵌套(仅针对分片表);不支持对 sharding key 列进行 update仅针对分片表Insert 使用时要写全列名例如insert into a(col1,col2) values(xx,xx)Insert 不支持子查询,如有特殊业务需要用到,可以使用注释仅针对分片表详见注释功能Insert 支持多 value 语句例如insert into a(col1,col2) values(x,x),(xx,xx);支持 replace into/insert on duplicate key 语法。
TODOMySQL崩溃了主从数据不一致怎么办
### 13.分区键的数值类型
用于分区的列可以是“int”或“char”类型“int”对应到MySQL中各种整数类型“char”对应到各种定长和变长字符串类型日期类型在SQL中按字符串处理的话可以支持。 后续会支持特定格式的字符型表示的时间类型,如“YYYYMMDD” 和 “YYYYMMDD HH24:MI:SS” 格式,时间格式不支持针对时区进行转换,统一使用本地时间。
### 14.分区相关注释
Cetus提供注释功能用以解决日常维护时的需求DBA同学经常使用和一些针对前端业务的特殊需求例如强制该SQL只通过主库或者从库进行操作
注释书写样式 /\*# key=value \*/。
其中,以“/\*#”号开头(“/\*” 与“#”之间不允许有空格),“\*/”结尾, 中间以键值对形式书写如果value包含[a-zA-Z0-9_-.]以外的其它特殊字符,需加双引号 。Key/value的值大小写均可建议统一小写。
Sharding版支持的key类型table|group|mode|transaction支持的value包括all/readwrite/readonly/single_node。
使用示例如下:
**1.Key类型为table的用法**
用法:/\*#table=employee\*/
SQL: select /\*# table=employee key=123\*/emp_no,emp_name from employee;
说明查询表employee中分区键的值是123的记录。
**2.Key类型为group的用法**
用法:/\*# group=dataA\*/
SQL: select /\*# group=dataA \*/ count(\*) from employee;
说明查询后端节点dataA中表employee的记录数。
用法:/\*# group=all \*/
SQL: create /\*# group=all \*/ table employee xxxx;
说明:在后端所有节点均创建此表。
**3.Key类型为mode的用法**
用法:/\*# mode=readwrite \*/
SQL: select /\*# mode=readwrite \*/ count(\*) fromemployee;
说明:此查询语句强制选择主库执行,查询操作默认选择从库执行。
**4.Key类型为transaction的用法**
用法:/\*# transaction=single_node \*/
SQL: update /\*# transaction=single_node \*/ departmentsset dept_name='ecbj' where dept_no='d010';
说明此dml语句将强制采用非分布式事务一旦Cetus在执行时判断应该采用分布式事务会返回错误。
**5.复合用法**
用法:/\*# table=employee key=123\*/ /\*#mode=readwrite\*/
SQL: select /\*# table=employee key=123\*/ /\*#mode=readwrite\*/ emp_no,emp_name from employee;
说明查询表employee中分区键的值是123的记录且强制从主库读取。
注意table、group这两个key是互斥的即table或者group分别可以和mode/transaction共用但它俩不能同时出现否则会返回错误。另外请将注释部分写到第一个关键字之后。注释一旦使用其优先级高于后续where条件如果有的话中的分区路由信息。
## Cetus应用示例
### 1.连接Cetus
```
$ mysql --prompt="proxy> " --comments -h**.**.**.** -P**** -u**** -p***
proxy>
```
在连接Cetus时使用在配置文件中确认好的用户名和密码登陆登陆的ip和端口为Cetus监听的ip和端口。
可同时启动监听同一个ip不同端口的Cetus。
### 2.管理Cetus
```
$ mysql --prompt="admin> " --comments -h**.**.**.** -P**** -u**** -p***
admin> show connectionist
```
可以使用在配置文件中的admin用户名和密码登陆地址为admin-address的MySQL对Cetus进行管理例如在查询Cetus的连接详细信息时可以登录后通过命令 show connectionlist显示从前端到后端端口映射关系以及涉及到的 xa 信息。
具体使用说明详见[Cetus 分库(sharding)版管理手册](https://git.ms.netease.com/dbproxy/cetus/wikis/cetus-shard-admin)
### 3.查看Cetus参数
```
$ cd /home/user/cetus_install/
bin/cetus --help | -h
```
可以查看帮助获取Cetus启动配置选项的参数及含义。