共计 10029 个字符,预计需要花费 26 分钟才能阅读完成。
Atlas 是由 Qihoo 360 公司 Web 平台部基础架构团队开发维护的一个基于 MySQL 协议的数据中间层项目。它在 MySQL 官方推出的 MySQL-Proxy 0.8.2 版本的基础上,修改了大量 bug,添加了很多功能特性。目前该项目在 360 公司内部得到了广泛应用,很多 MySQL 业务已经接入了 Atlas 平台,每天承载的读写请求数达几十亿条。
Atlas 主要功能: 1. 读写分离
2. 从库负载均衡
3.IP 过滤 4. 自动分表
5.DBA 可平滑上下线 DB
6. 自动摘除宕机的 DB
Atlas 介绍
Atlas 是一个位于应用程序与 MySQL 之间中间件。在后端 DB 看来,Atlas 相当于连接它的客户端,在前端应用看来,Atlas 相当于一个 DB。Atlas 作为服务端与应用程序通讯,它实现了 MySQL 的客户端和服务端协议,同时作为客户端与 MySQL 通讯。它对应用程序屏蔽了 DB 的细节,同时为了降低 MySQL 负担,它还维护了连接池
Atlas 相对于官方 MySQL-Proxy 的优势
1. 将主流程中所有 Lua 代码用 C 重写,Lua 仅用于管理接口
2. 重写网络模型、线程模型
3. 实现了真正意义上的连接池
4. 优化了锁机制,性能提高数十倍
Atlas 安装配置
- 从 https://github.com/Qihoo360/Atlas/releases 页面下载最新版 RPM 包,然后执行:
sudo rpm –i Atlas-XX.el6.x86_64.rpm 安装。
注:Atlas 只能安装运行在 64 位的系统上。后端 mysql 版本应大于 5.1,建议使用 Mysql 5.6 及以上
- 配置文件修改
Atlas 运行需要依赖一个配置文件(test.cnf)。在运行 Atlas 之前,需要对该文件进行配置。
Atlas 的安装目录是 /usr/local/mysql-proxy,进入安装目录下的 conf 目录,可以看到已经有一个名为 test.cnf 的默认配置文件,我们只需要修改里面的某些配置项
test.cnf
(必备,默认值即可)管理接口的用户名
• admin-username = user
(必备,默认值即可) 管理接口的密码
• admin-password = pwd
(必备,根据实际情况配置) 主库的 IP 和端口
• proxy-backend-addresses = 192.168.0.12:3306
(非必备,根据实际情况配置) 从库的 IP 和端口,@后面的数字代表权重,用来作负载均衡,若省略则默认
为 1,可设置多项,用逗号分隔。如果想让主库也能分担读请求的话,只需要将主库信息加入到下面的配
置项中。
• proxy-read-only-backend-addresses = 192.168.0.13:3306,192.168.0.14:3306
(必备,根据实际情况配置)用户名与其对应的加密过的 MySQL 密码,密码使用 PREFIX/bin 目录下的加密程
序 encrypt 加密,用户名与密码之间用冒号分隔。主从数据库上需要先创建该用户并设置密码(用户名和密
码在主从数据库上要一致)。比如用户名为 myuser,密码为 mypwd,执行./encrypt mypwd 结果为
HJBoxfRsjeI=。如果有多个用户用逗号分隔即可。则设置如下行所示:
• pwds = myuser: HJBoxfRsjeI=,myuser2:HJBoxfRsjeI=
(必备,默认值即可)Atlas 的运行方式,设为 true 时为守护进程方式,设为 false 时为前台方式,一般开发
调试时设为 false,线上运行时设为 true
• daemon = true
(必备,默认值即可)设置 Atlas 的运行方式,设为 true 时 Atlas 会启动两个进程,一个为 monitor,一个为
worker,monitor 在 worker 意外退出后会自动将其重启,设为 false 时只有 worker,没有 monitor,一般开发
调试时设为 false,线上运行时设为 true
• keepalive = true
(必备,根据实际情况配置)工作线程数,推荐设置成系统的 CPU 核数的 2 至 4 倍
• event-threads = 4
(必备,默认值即可) 日志级别,分为 message、warning、critical、error、debug 五个级别
• log-level = message
(必备,默认值即可) 日志存放的路径
• log-path = /usr/local/mysql-proxy/log
(必备,根据实际情况配置)SQL 日志的开关,可设置为 OFF、ON、REALTIME,OFF 代表不记录
SQL 日志,ON 代表记录 SQL 日志,该模式下日志刷新是基于缓冲区的,当日志填满缓冲区后,
才将日志信息刷到磁盘。REALTIME 用于调试,代表记录 SQL 日志且实时写入磁盘,默认为 OFF
• sql-log = OFF
(可选项,可不设置)慢日志输出设置。当设置了该参数时,则日志只输出执行时间超过 sql-logslow(单位:ms)的日志记录。不设置该参数则输出全部日志。
• sql-log-slow = 10
(可选项,可不设置)关闭不活跃的客户端连接设置。当设置了该参数时,Atlas 会主动关闭经过
‘wait-timeout’ 时间后一直未活跃的连接。单位:秒
wait-timeout = 10
(必备,默认值即可)Atlas 监听的工作接口 IP 和端口
proxy-address = 0.0.0.0:1234
(必备,默认值即可)Atlas 监听的管理接口 IP 和端口 admin-address = 0.0.0.0:2345
(可选项,可不设置) 默认字符集,若不设置该项,则默认字符集为 latin1
charset = utf8
(可选项,可不设置)允许连接 Atlas 的客户端的 IP,可以是精确 IP,也可以是 IP 段,以逗
号分隔,若不设置该项则允许所有 IP 连接,否则只允许列表中的 IP 连接
client-ips = 127.0.0.1, 192.168.0.1
运行 Atlas
进入 /usr/local/mysql-proxy/bin 目录,执行下面的命令启动、重启或停止 Atlas。
(1). sudo ./mysql-proxyd test start,启动 Atlas。
(2). sudo ./mysql-proxyd test restart,重启 Atlas。
(3). sudo ./mysql-proxyd test stop,停止 Atlas。
执行命令:mysql -h127.0.0.1 -P1234 - u 用户名 - p 密码,如果能连上则证明 Atlas 初步
测试正常,可以再尝试发几条 SQL 语句看看执行结果是否正确。
Atlas 读写分离
Atlas 后端连接的 MySQL 主库的 IP 和端口,可设置多项,用逗号分隔
例如
proxy-backend-addresses = 192.168.237.128:3308
Atlas 后端连接的 MySQL 从库的 IP 和端口,@后面的数字代表权重,用来作负载均衡,若省略则默认为 1,可设置多项,用逗号分隔
proxy-read-only-backend-addresses = 192.168.237.130:3308@1
关闭主备库复制关系,在主库上查看
当 MySQL 主库关闭的情况下,写操作失败,读操作依然可以执行
当 MySQL 仅有的一个从库关闭的情况下,写操作成功,读操作也漂移到主库上执行
Atlas 负载均衡
当有多个从库的情况下
Atlas 后端连接的 MySQL 主库的 IP 和端口,可设置多项,用逗号分隔
proxy-backend-addresses = 192.168.237.128:3308
Atlas 后端连接的 MySQL 从库的 IP 和端口,@后面的数字代表权重(数字越大读取的机会更高),用来作负载均衡,若省略则默认为 1,可设置多项,用逗号分隔
例如:
当第一个从库崩溃时执行查询语句,语句都在第二个节点查询
当有多个读节点时,权重越大,被读取的可能性就越高
Atlas 后端连接的 MySQL 从库的 IP 和端口,@后面的数字代表权重,用来作负载均衡,若省略则默认为 1,
可设置多项,用逗号分隔
例:
proxy-read-only-backend-addresses = 192.168.237.130:3308@1,192.168.237.131:3308@2
自动读写分离挺好,但有时候写完马上就想读,万一主从同步延迟怎么办?
SQL 语句前增加 /*master*/ 就可以将读请求强制发往主库。在 mysql 命令行测试该功能时,需要 加 - c 选项,以防 mysql 客户端过滤掉注释信息。
主库宕机,读操作受影响么?
在 Atlas 中读操作不受影响,Atlas 会将读请求转发到其他还存活的从库上。但此时写请求将会失败,因为主库宕机了。
Altas 支持多个主库的运行模式吗?
官网:目前还未对于 Atlas 后面挂接多个主库的情形进行测试过,不建议这样使用
。建议使用一主一从或一主多从的模式。
可以做双主,在 proxy-backend-addresses = ip1,ip2 但是不建议使用
Atlas 分表功能
类似在一个库,创建了多个子表
使用 Atlas 的分表功能时,首先需要在配置文件(test.cnf)设置 tables 参数。
tables 参数设置格式:数据库名. 表名. 分表字段. 子表数量,比如你的数据库名叫 school,表名叫 stu,分表字段叫 id,总共分为 100 张表,那么就写为 school.stu.id.100,如果还有其他的分表,以逗号分隔即可。用户 需要在数据库手动建立 100 张子表(stu_0,stu_1,…stu_99,注意子表序号是从 0 开始的)。且所有的子表必须在 DB 的同一个 database 里·
分表的效果是:
当通过 Atlas 执行(SELECT、DELETE、UPDATE、INSERT、REPLACE)操作时, Atlas 会根据分表字段结果(id%100=k),定位到相应的子表(stu_k)
。
例如,执行
select * from stu where >
但如果执行 SQL 语句(select * from stu;)时不带上 id,则会提示执行 stu 表不存在。
Atlas 暂不支持自动建表和跨库分表的功能
Atlas 目前支持分表的语句有 SELECT、DELETE、UPDATE、INSERT、REPLACE
需要安装非 shard 版本,sharding 版本不支持分表功能
分表设置,此例中 person 为库名,mt 为表名,id 为分表字段,3 为子表数量,可设置多项,以逗号分隔,若不分表则不需要设置该项
局限性:
应用程序连接 atlas 分表的时候,查询必须要加where 条件,分表字段 =
不能用范围查询 >,<, 或者 between and,不支持全表查询。
例:
mysql> select * from students;
ERROR 1146 (42S02): Table ‘test.students’ doesn’t exist
mysql> select * from students where id>2;
ERROR 1146 (42S02): Table ‘test.students’ doesn’t exist
Atlas 分片
Sharding 当前是 Atlas 的分布式分支,
是 Atlas 最近重点开发的功能. Sharding 的基本思想
就是把 一个数据表中的数据切分成多个部分, 存放到不同的主机上去 (切分的策略有多种),
从而缓解单台机器的性能跟容量的问题. sharding 是一种水平切分, 适用于单表数据庞大的情景
Atlas 以表为单位 sharding
, 同一个数据库内可以同时共有 sharding 的表和不 sharding 的表, 不 sharding 的表数据存在未 sharding 的数据库组中.
目前 Atlas sharding 支持 insert, delete, select, update 语句, 所有的写操作如 insert,delete, update 只能一次命中一个组, 否则会报”ERROR 1105 (HY000):write operationis only allow to one dbgroup!”错误.
Sharding 数据库组
在 Atlas 中, 将一个组看做是数据存储的单位,一个组由一台 master, 零台或者多台 slave 组成
(mysql 主从同步需要由用户自己配置). 每个组之间的数据独立, 没有关系, 表的数据的各个部分存储在各个组中.
组内读写分离
与非 sharding 的方案一样,Atlas sharding 也支持组内的读写分离
, 也就是说 Atlas 在命中了某个组之后, 还是会对这个组内的 master 和 slave 执行读写分离(读发送到 slave, 写发送到 master)
Sharding 数据切分策略
Range 方式
范围数据切分方式,比如
shard Key 范围在 0 -1000 的数据存放在 Group0 中,
范围在 1000-2000 的数据存放在 Group1 中,
2000-MaxInt 的数据存放在 Group2 中.
这些范围的大小不需要相同. 比如 id 为 shard key 的话, sql:“select * from test where id = 1500;”,
Atlas 会将此语句发往 Group1. 暂时 Atlas 的 range 是静态的, 不支持动态的增加范围
hash 方式
目前 Atlas 使用取模的方式实现 Hash, 也就是说 Hash(id) = id % group_count, 如 id =10, id % 3 = 1, 所以会命中到 DbGroup1 中.
Atlas sharding 部分新增配置项,包含两个部分:
shardrule. 一个 shardrule 对应一个分表规则,不同的 shardrule 通过下划线后面的数字区分
。
例如 shardrule-0, shardrule-1….。
一个 shardrule 里面有以下几项:
[shardrule-0]
table = test.sharding_test #分表名,由数据库 + 表名组成
type = range #sharding 类型:range 或 hash
shard-key = id #sharding 字段
groups = 0:0-999,1:1000-1999 #分片的 group,
如果是 range 类型的 sharding,则 groups 的格式是:group_id:id 范围。
如果是 hash 类型的 sharding,则 groups 的格式是:group_id。例如 groups = 0, 1
group. 一个 group 一般包含一主多从,由 master(proxy-backend-addresses)和
slave(proxy-read-only-backend-addresses)组成。group 之间的区别也是通过下
划线后面的数字区分。
假设我们有以下一个 sharding 的表, 建表语句如下:
CREATE TABLE `sharding_test` (`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(50) COLLATE utf8_bin NOT NULL,
`age` int(11) DEFAULT NULL,
`birthday` date DEFAULT NULL,
`nickname` char(50) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`) );
有两个 dbgroup(数据库组), 每个 dbgroup 有一个 master, sharding_test 使用 range 的方
式, 以 id 作为 shard key, 属于 test 数据库, dbgroup0 属于范围 0 – 999, dbgroup1 属于
范围 1000 – 1999
dbgroup0 有一主, 192.168.237.130:3308
dbgroup1 有一主, 192.168.237.131:3308
admin-username = user
admin-password = pwd
#Atlas 后端连接的 MySQL 主库的 IP 和端口,可设置多项,用逗号分隔
proxy-backend-addresses = 192.168.237.128:3308
#proxy-read-only-backend-addresses = 192.168.237.130:3308@1,192.168.237.131:3308@1
daemon = true
keepalive = false
event-threads = 4
log-level = debug
log-path = /usr/local/mysql-proxy/log
sql-log = realtime
proxy-address = 0.0.0.0:1234
admin-address = 0.0.0.0:2345
charset = UTF8
wait-timeout = 3600
pwds = root:S4HJu78/H/6I/aYp2Xdb8Q==
[shardrule-0]
table = test3.sharding_test
type = range
shard-key = id
groups = 0:0-999,1:1000-1999
[group-0]
# master
proxy-backend-addresses=192.168.237.130:3308
# slave
#proxy-read-only-backend-addresses=127.0.0.1:3308
[group-1]
proxy-backend-addresses=192.168.237.131:3308
#proxy-read-only-backend-addresses=127.0.0.1:3310
运行 Atlas
进入 /usr/local/mysql-proxy/bin 目录,执行下面的命令启动、重启或停止 Atlas。
(1). sudo ./mysql-proxyd test start,启动 Atlas。
(2). sudo ./mysql-proxyd test restart,重启 Atlas。
(3). sudo ./mysql-proxyd test stop,停止 Atlas
执行命令:mysql -h 127.0.0.1 -P 1234 -u 用户名 -p,如果能连上则证明 Atlas 初步
测试正常,可以再尝试发几条 SQL 语句看看执行结果是否正确。
关于支持的语句
Atlas sharding 只对 sql 语句提供有限的支持, 目前支持基本的 Select, insert/replace, delete, update 语句,
支持全部的 Where 语法 (SQL-92 标准), 不支持 DDL(create drop alter)以及一些管理语句
, DDL 请直连 MYSQL 执行, 请只在 Atlas 上执行 Select, insert, delete, update(CRUD)语句
对于以下语句, 如果 语句命中了多台 dbgroup, Atlas 均未做支持
(如果语句只命中了一个 dbgroup, 如 select count(*) from test where id < 1000, 其中 dbgroup0 范围是 0 – 1000, 那么这些特性都是支持的)
Limit Offset (支持 Limit 同一个 dbgroup)
Order by
Group by
Join
count, Max, Min 等函数不支持
子查询在 Sharding 中可能会返回不正确的结果, 也请不要使用子查询. 请把语句拆分成多句执行
对于写操作, 如果写操作命中了多个数据库组, 由于部分成功 (某个组执行失败) 需要回滚的问题, 暂时不支持写操作命中多个数据组的语句. 请拆分成多个 sql 语句执行
Atlas 可能会在接下来的版本中对其中的一些特性中做出支持.
例用 Atlas 插入几条数据,做一下测试:
mysql> use test3;
Database changed
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(50, ‘test’, 0), (999, ‘test’, 0);
Query OK, 2 rows affected (0.00 sec)
以上几条数据都插入到了 dbgroup0, 请注意第二条多值插入的语句, 因为 50 和 999 都命中了 dbgroup0, 所以其执行成功, 但是如果执行以下的语句:
mysql> insert into sharding_test(id, name, age) values(100, ‘test’, 0), (1500, ‘test’,
0);
ERROR 1105 (HY000): Proxy Warning – write operation is only allow to one
dbgroup! 在 sharding 的表中, 这是不允许的, 因为 id 为 100 命中了 dbgroup0, 而 id 为 1500 命中了 dbgroup1, 由于分布式的多值插入可能导致部分成功, 需要回滚, 这个 Atlas 暂不支持. update, delete, replace 同理.
再插几条数据到 dbgroup1:
mysql> insert into sharding_test(id, name, age) values(1000, ‘test’, 0), (1999,
‘test’, 0);
Query OK, 2 rows affected (0.00 sec)
mysql> select * from sharding_test;
+——+——+——+———-+———-+
| id | name | age | birthday | nickname |
+——+——+——+———-+———-+
| 1 | test | 0 | NULL | NULL |
| 50 | test | 0 | NULL | NULL |
| 999 | test | 0 | NULL | NULL |
| 1000 | test | 0 | NULL | NULL |
| 1999 | test | 0 | NULL | NULL |
mysql> select * from sharding_test where id>50;
+——+——+——+———-+———-+
| id | name | age | birthday | nickname |
+——+——+——+———-+———-+
| 999 | test | 0 | NULL | NULL |
| 1000 | test | 0 | NULL | NULL |
| 1999 | test | 0 | NULL | NULL |
#JOIN 操作,不支持
mysql> select * from sharding_test a,test.temp b on a.>ERROR 1105 (sqlst): Proxy Warning – Sharing Hit Multi Dbgroup Not Support
SQL
#update 操作
mysql> update sharding_test set name=’test2′;
ERROR 1105 (HY000): Proxy Warning – Syntax Forbidden!
mysql> update sharding_test set name=’test2′ where id<2000;
ERROR 1105 (sqlst): Proxy Warning – write operation is only allow to one
dbgroup!
mysql> update sharding_test set name=’test2′ where id<999;
Query OK, 2 rows affected (0.01 sec)
#delete 操作
mysql> delete from sharding_test;
ERROR 1105 (HY000): Proxy Warning – Syntax Forbidden!
mysql> delete from sharding_test where id<2000;
ERROR 1105 (sqlst): Proxy Warning – write operation is only allow to one
dbgroup!
mysql> delete from sharding_test where id>1900;
Query OK, 1 row affected (0.01 sec)
更多的看看官方文档:https://github.com/Qihoo360/Atlas/wiki
: