Atlas 是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bug,添加了很多功能特性。目前该项目在360公司内部得到了广泛应用,很多MySQL业务已经接入了Atlas平台,每天承载的读写请求数达几十亿条。同时,有超过50家公司在生产环境中部署了Atlas,超过800人已加入了我们的开发者交流群,并且这些数字还在不断增加。
主要功能:
1.读写分离
2.从库负载均衡
3.IP过滤
4.自动分表
5.DBA可平滑上下线DB
6.自动摘除宕机的DB
Atlas Sharding 简介
Atlas Sharding是Atlas最近重点开发的一个功能, 此功能增加了Mysql的横向扩展性跟容量, 可以满足大部分企业的需求. 目前已经在github上以Sharding分支发布.
Sharding 的基本思想就是把一个数据表中的数据切分成多个部分, 存放到不同的主机上去(切分的策略有多种), 从而缓解单台机器的性能跟容量的问题. sharding是一种水平切分, 适用于单表数据庞大的情景. 目前atlas支持静态的sharding方案, 暂时不支持数据的自动迁移.
Atlas以表为单位sharding, 同一个数据库内可以同时共有sharding的表和不sharding的表, 不sharding的表数据存在未sharding的数据库组中.
目前Atlas sharding支持insert, delete, select, update语句, 支持不跨shard的事务.
当然, 由于Mysql分布式的局限性, Atlas Sharding对于SQL的特性支持也是有限的, 但是应付日常的需求, 已经足够了.
与Mysql replication的区别
MySQL主从复制就是将一个MySQL实例(Master)中的数据实时复制到另一个MySQL实例(slave)中,这个复制是一个异步复制的过程。
数据复制有以下一些特点:
数据分布
负载平衡(需要借助Atlas或者其他proxy中间件)
备份
高可用性(high availability)和容错
复制的局限性很明显, 当数据库写入频繁, 但读取操作少的场景下, 复制就不适合了, 当写入过于频繁,很难由一台主机支撑的时候,我们还是会面临到扩展瓶颈。换句话说就是复制只能扩展读性能, 但是对于写性能的扩展是无能为力的.
数据切分(sharding): 通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。这样当写入的时候, IO就被各个shard所分担了. 同时, 在每一个Shard上也是可以有复制存在的, 借助Atlas还是能在Shard上做读分离, 所以复制跟Sharding完全是互相补充, 不排斥的.
Sharding 架构
Atlas是无状态的, 对于后端的多个组, 可以配置任意多个Atlas实例, 这一点与MongoDB的mongos类似.
Sharding数据库组
在Atlas中, 将一个组看做是数据存储的单位, 一个组由一台master, 零台或者多台slave组成(mysql主从同步需要由用户自己配置). 每个组之间的数据独立, 没有关系, 表的数据的各个部分存储在各个组中.
组内读写分离
Atlas sharding也支持组内的读写分离, 也就是说Atlas在命中了某个组之后, 还是会对这个组内的master和slave执行读写分离(读发送到slave, 写发送到master).
Sharding 数据切分策略
shard key
每一个shard table都有一个shard key, 其可以是主键, 也可以是非主键, 但是这个列必须是一个整数. Atlas会利用这个shard key来判断应该把这条记录存放到哪一个数据库组中.
现在Atlas Shardingh支持两种类型的数据切分: Range方式和Hash方式.
Range 方式
如上图中, shard Key范围在0-1000的数据存放在DbGroup0中, 范围在1000-2000的数据存放在DbGroup1中, 2000-MaxInt 的数据存放在DbGroup2 中. 这些范围的大小不需要相同.比如id为shard key的话, sql: "select * from test where id = 1500;", Atlas会将此语句发往DbGroup1. 暂时Atlas的range是静态的, 不支持动态的增加范围.
优点:
对于range的sql查询如(where id > 100 or id < 1000), range方式的sharding可以精确的命中后端的数据组, 不需要将sql发到各个mysql去请求数据, 节约了网络传输的消耗.
缺点
如果shard key是递增的, 那么可能会在一段时间内的所有sql都命中到同一个数据组, 没有体现出sharding的优势, range不适用于这种场景.
适用场景
range适用于对范围查询有大量需求, 并且shard key相对离散插入的情景
hash 方式
目前Atlas使用取模的方式实现Hash, 也就是说Hash(id) = id % dbgroup_count, 如id = 10, id % 3 = 1, 所以会命中到DbGroup1中.
优缺点
hash跟range方式是恰好相反的, hash 可以应对数据递增的情景, 即使是在递增的情况下, sharding的数据也是均匀分布在各个数据组内的, 但是其缺点就是对于范围的查询通常都需要查询所有的dbgroup, 网络的消耗比较大.
适用场景
hash 适用于shard key顺序增长, 并对范围查询的需求比较小的情景
关于支持的语句
Atlas sharding只对sql语句提供有限的支持, 目前支持基本的Select, insert/replace, delete, update语句, 支持全部的Where语法, 但是对于以下语句, 如果语句命中了多台dbgroup, Atlas均未做支持(如果语句只命中了一个dbgroup, 如select count(*) from test where id < 1000, 其中dbgroup0范围是0 - 1000, 那么这些特性都是支持的)
Limit Offset(支持Limit)
Order by
Group by
Join
ON
Count, Max, Min等函数
这些语句Atlas会返回"ERROR 1105 (HY000): Proxy Warning - Sharing Hit Multi Dbgroup Not Support SQL"错误. 请不要在Sharding的表上使用这些特性, 如果对这种特性有需求请不要让此表sharding.
注意:
子查询在Sharding中可能会返回不正确的结果, 也请不要使用子查询. 请把语句拆分成多句执行
对于写操作, 如果写操作命中了多个数据库组, 由于部分成功(某个组执行失败)需要回滚的问题, 暂时不支持写操作命中多个数据组的语句.请拆分成多个sql语句执行.
Atlas可能会在接下来的版本中对其中的一些特性中做出支持.
关于事务支持
事务在Atlas的非sharding的表是完全支持的, 但是对于sharding的表, Atlas只能提供部分的支持(不支持跨dbgroup的事务). Atlas只支持事务中涉及单个dbgroup的语句, 例如有两个dbgroup0, dbgroup1, 其切分方式是range, 规则是dbgroup0: 0 - 999, dbgroup1: 1000 - 2000,
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into sharding_test(id, name, age) values(1, 'test', 0); Query OK, 1 row affected (0.00 sec) mysql> insert into sharding_test(id, name, age) values(1500, 'test', 0); ERROR 1179 (sqlst): Proxy Warning - sharding dbgroup is in trans, transaction will not work across multi dbgroup mysql> /*master*/select * from sharding_test where id < 1000; +----+------+------+----------+----------+ | id | name | age | birthday | nickname | +----+------+------+----------+----------+ | 1 | test | 0 | NULL | NULL | +----+------+------+----------+----------+ 1 row in set (0.00 sec) mysql> /*master*/select * from sharding_test; ERROR 1179 (sqlst): Proxy Warning - sharding dbgroup is in trans, transaction will not work across multi dbgroup mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> /*master*/select * from sharding_test; +----+------+------+----------+----------+ | id | name | age | birthday | nickname | +----+------+------+----------+----------+ | 1 | test | 0 | NULL | NULL | +----+------+------+----------+----------+ 1 row in set (0.00 sec)
请注意第二条语句, 由于之前将insert与dbgroup0绑定了, 所以从此之后Atlas在此事务中只接受涉及dbgroup0的语句, 其他语句将会执行失败. "/*master*/select * from sharding_test;" 执行失败是因为, 这个语句会命中所有的dbgroup, 也是同理, 不支持这种语句. 在commit之后, sharding dbgroup不再处于事务状态, 就可以执行跨shard的操作了
换句话说, 如果是hash方式sharding的表, 基本上事务是无法支持的, 因为hash的表, 大部分操作都是会涉及多个dbgroup的.
增加节点
注意: 暂时只支持range方式的节点扩展, hash方式由于需要数据迁移, 暂时未做支持.
扩展节点在保证原来节点的范围不改变的情况下, 如已有dbgroup0为范围0 - 999, dbgroup1为范围 1000 - 1999, 这个时候可以增加范围>2000的节点. 如增加一个节点为2000 - 2999, 修改配置文件, 重启Atlas即可.