简介
- Atlas在mysql-proxy基础上二次开发而来,主要有如下功能
- 读写分离
- 从库负载均衡
- IP白名单管理
- 大表分片操作
- 平滑上下线DB
- 自动摘除宕机的DB
架构
Atlas是一个位于应用程序与MySQL之间中间件。在后端DB看来,Atlas相当于连接它的客户端,在前端应用看来,Atlas相当于一个DB。Atlas作为服务端与应用程序通讯,它实现了MySQL的客户端和服务端协议,同时作为客户端与MySQL通讯。它对应用程序屏蔽了DB的细节,同时为了降低MySQL负担,它还维护了连接池。架构与proxy相同,可以用下面的图表示
- Atlas的线程模型
- Atlas启动后会创建多个线程,其中一个为主线程,其余为工作线程。主线程负责监听所有的客户端连接请求,工作线程只监听主线程的命令请求。
- 主线程接收到客户端的连接请求,将该请求的相关信息封装为一个名为CON的结构,再把该结构推入一个异步队列。然后通过round-robin方式选择一个工作线程,向其发送一个字节的数据包以激活它。工作线程在收到主线程的激活指令后,从异步队列中取出CON结构,开始处理客户端的请求。
- Atlas配合LVS使用的架构
LVS前端做负载均衡,两个Atlas做HA,防止单点故障。LVS周期性地对后端Atlas的存活检测有两种方式,一是直接去探测端口是否可连接,二是执行一个脚本,这个脚本会去尝试连接Atlas,通过脚本的返回值来决定每个后端是否可用。Atlas有两种运行状态,通常为online,可通过发信号将其置为offline。Atlas检测到来请求的IP是LVS的网卡IP时,如果处于online状态,就向LVS的检测脚本返回online,如果处于offline状态,就向脚本返回offline。比如我现在因为某种原因需要重启一台Atlas,但直接重启势必导致瞬间的SQL请求全部失败,对前端应用造成影响。因此我先发下线信号将Atlas置为offline状态,当LVS的检测脚本发现返回值是offline时,便将这台Atlas摘除,从此时开始便没有新的请求导向这台Atlas。等到已经打向这台Atlas的SQL请求处理完毕后(这是一个很短的时间),就可以安全重启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 id=110;,Atlas会自动从stu_10这张子表返回查询结果。但如果执行SQL语句(select * from stu;)时不带上id,则会提示执行stu 表不存在。
- 注:Atlas暂不支持自动建表和跨库分表的功能。Atlas目前支持分表的语句有SELECT、DELETE、UPDATE、INSERT、REPLACE。
配置文件
cat /usr/local/mysql-proxy/conf/test.cnf
[mysql-proxy]
(必备,默认值即可)管理接口的用户名
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-log-slow(单位: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
(可选项,可不设置)分表设置,此例中person为库名,mt为表名,id为分表字段,3为子表数量,可设置多项,以逗号分隔,若不分表则不需要设置该项,子表需要事先建好,子表名称为表名_数字,数字范围为[0,子表数-1],如本例里,子表名称为mt_0、mt_1、mt_2
tables = person.mt.id.3
(可选项,可不设置)默认字符集,若不设置该项,则默认字符集为latin1
charset = utf8
(可选项,可不设置)允许连接Atlas的客户端的IP,可以是精确IP,也可以是IP段,以逗号分隔,若不设置该项则允许所有IP连接,否则只允许列表中的IP连接
client-ips = 127.0.0.1, 192.168.1
(可选项,极少需要)Atlas前面挂接的LVS的物理网卡的IP(注意不是虚IP),若有LVS且设置了client-ips则此项必须设置,否则可以不设置
lvs-ips = 192.168.1.1
Atlas部分配置参数及原理详解
- password
- 密码使用PREFIX/bin/encrypt程序加密,避免有人打开配置文件就能看到所有用户的密码,只是简单地防护一下,并不能防止专门的恶意破解。
- 在Atlas的内存中,多个用户共用连接池,池内同时有多个用户名及使用其密码认证过的连接,在A用户连接Atlas时,从池中取出的连接有可能是B用户认证过的,这就需要使用A用户的密码将此连接change为A用户的认证连接,否则直接给A用户使用该连接就会引发权限问题。
- client-ips
- 该参数用来实现IP过滤功能。
- 在引入中间层后,因为连接DB的是Atlas,所以DB改为对部署Atlas的机器的IP作访问授权,如果任意一台客户端都可以连接Atlas,就会带来潜在的风险。
- client-ips参数用来控制连接Atlas的客户端的IP,可以是精确IP,也可以是IP段,以逗号分隔写在一行上即可,如client-ips=192.168.1.2, 192.168.2,这就代表192.168.1.2这个IP和192.168.2.*这个网段的IP可以连接Atlas,其他IP均不能连接。
- 如果该参数不设置,则任意IP均可连接Atlas。
- 如果设置了client-ips参数,且Atlas前面挂有LVS,则必须设置lvs-ips参数,否则可以不设置lvs-ips。
- lvs-ips
- 该参数是Atlas前面挂接的LVS的物理网卡的IP,不是虚IP。
- 该参数用来实现平滑重启功能,滑重启的条件:至少有两台配置相同的Atlas,且挂接在LVS之后。
- 平滑重启的原理:LVS周期性地对后端Atlas的存活检测有两种方式,一是直接去探测端口是否可连接,二是执行一个脚本,这个脚本会去尝试连接Atlas,通过脚本的返回值来决定每个后端是否可用。Atlas有两种运行状态,通常为online,可通过发信号将其置为offline。Atlas检测到来请求的IP是LVS的网卡IP时,如果处于online状态,就向LVS的检测脚本返回online,如果处于offline状态,就向脚本返回offline。比如我现在因为某种原因需要重启一台Atlas,但直接重启势必导致瞬间的SQL请求全部失败,对前端应用造成影响。因此我先发下线信号将Atlas置为offline状态,当LVS的检测脚本发现返回值是offline时,便将这台Atlas摘除,从此时开始便没有新的请求导向这台Atlas。等到已经打向这台Atlas的SQL请求处理完毕后(这是一个很短的时间),就可以安然重启Atlas而不必担心对前端造成影响了。
- 在设置了client-ips参数的情况下,必须设置lvs-ips参数,否则LVS的物理网卡的IP会被Atlas拒绝,如果未设置client-ips参数,说明不开启IP过滤功能,则lvs-ips也可以不设置。
- event-threads 线程数
过小无法充分发挥多核CPU的性能,过大造成不必要的线程切换开销,推荐设置为CPU的核数。 - min-idle-connections 最小空闲连接数(2.x以上版本不需要该项,1.x版本需要)
过小则在高并发下会有报错,过大虽然不报错但在测试时不容易看出读写分离效果,推荐设置为比客户端的并发峰值稍大, - proxy-address:Atlas的工作端口
proxy-address = 0.0.0.0:1234代表客户端应该使用1234这个端口连接Atlas来发送SQL请求。 - admin-address:Atlas的管理端口
admin-address = 0.0.0.0:2345代表DBA应该使用2345这个端口连接Atlas来执行运维管理操作。 - 管理接口的用户名和密码:admin-username项和admin-password项设置,这两项是用来进入Atlas的管理界面的,与后端连接的MySQL没有关系,所以可以任意设置,不需要MySQL在配置上做任何改动。
- log-level:日志级别
message、warning、critical、error、debug五个级别,通常设置为error。 - log-path:日志路径–如log-path = /usr/local/mysql-proxy/log。
安装配置
下载rpm包并安装
wget https://github.com/Qihoo360/Atlas/releases/download/2.2.1/Atlas-2.2.1.el6.x86_64.rpm
rpm -ivh Atlas-2.2.1.el6.x86_64.rpm
默认在”/usr/local/mysql-proxy”下给你生成4个文件夹,以及需要配置的文件,如下:
[root@localhost home]# ll /usr/local/mysql-proxy/
total 16
drwxr-xr-x. 2 root root 4096 Dec 28 10:47 bin
drwxr-xr-x. 2 root root 4096 Dec 28 10:47 conf
drwxr-xr-x. 3 root root 4096 Dec 28 10:47 lib
drwxr-xr-x. 2 root root 4096 Dec 17 2014 log
- bin目录下放的都是可执行文件
- “encrypt”是用来生成MySQL密码加密的,在配置的时候会用到
- “mysql-proxy”是MySQL自己的读写分离代理
- “mysql-proxyd”是360弄出来的,后面有个“d”,服务的启动、重启、停止。都是用他来执行的
- conf目录下放的是配置文件
“test.cnf”只有一个文件,用来配置代理的,可以使用vim来编辑 - lib目录下放的是一些包,以及Atlas的依赖
- log目录下放的是日志,如报错等错误信息的记录
- 进入bin目录,使用encrypt来对数据库的密码进行加密,比如用户名是buck,密码是hello,我需要对密码进行加密
[root@localhost bin]# ./encrypt hello
RePBqJ+5gI4=
得到的结果就是密码加密后的值,写在配置文件admin-password后面
编辑配置文件
#管理接口的用户名
admin-username = user
#管理接口的密码
admin-password = pwd
- 这是用来登录到Atlas的管理员的账号与密码,与之对应的是“#Atlas监听的管理接口IP和端口”,也就是说需要设置管理员登录的端口,才能进入管理员界面,默认端口是2345,也可以指定IP登录,指定IP后,其他的IP无法访问管理员的命令界面。方便测试,我这里没有指定IP和端口登录。
#Atlas后端连接的MySQL主库的IP和端口,可设置多项,用逗号分隔
proxy-backend-addresses = 192.168.246.134:3306
#Atlas后端连接的MySQL从库的IP和端口,@后面的数字代表权重,用来作负载均衡,若省略则默认为1,可设置多项,用逗号分隔
proxy-read-only-backend-addresses = 192.168.246.135:3306@1
- 这是用来配置主数据的地址与从数据库的地址,这里配置的主数据库是135,从数据库是134,从库为read-only,实现读写分离
#用户名与其对应的加密过的MySQL密码,密码使用PREFIX/bin目录下的加密程序encrypt加密,下行的user1和user2为示例,将其替换为你的MySQL的用户名和加密密码!
pwds = buck:RePBqJ+5gI4=
- 这个是用来配置MySQL的账户与密码的,我的MySQL的用户是buck,密码是hello,刚刚使用Atlas提供的工具生成了对应的加密密码
#Atlas监听的工作接口IP和端口
proxy-address = 0.0.0.0:1234
#Atlas监听的管理接口IP和端口
admin-address = 0.0.0.0:2345
- 这是设置工作接口与管理接口的,如果ip设置的”0.0.0.0”就是说任意IP都可以访问这个接口,当然也可以指定IP和端口,方便测试我这边没有指定,工作接口的用户名密码与MySQL的账户对应的,管理员的用户密码与上面配置的管理员的用户密码对应。
启动Atlas
[root@localhost bin]# ./mysql-proxyd test start
OK: MySQL-Proxy of test is started
注意事项
- 自动读写情况下,但有时候写完马上就想读,如果主从同步延迟怎么办?
- SQL语句前增加 /master/ 就可以将读请求强制发往主库。在mysql命令行测试该功能时,需要加-c选项,以防mysql客户端过滤掉注释信息。
- 主库宕机,在Atlas中读操作不受影响,Atlas会将读请求转发到其他还存活的从库上。但此时写请求将会失败,因为主库宕机了。
- atlas中检测线程是异步进行检测的,即使有db宕机,也不会阻塞主流程。在Atlas中没有什么异常会让主流程阻塞。
Atlas管理操作
- 登录管理接口:
mysql -uuser -ppwd -h127.0.0.1 -P2345
- 查看帮助信息:
mysql> SELECT * FROM help;
- 查看后端代理库:
mysql> SELECT * FROM backends;
+-------------+----------------+-------+------+
| backend_ndx | address | state | type |
+-------------+----------------+-------+------+
| 1 | 10.0.0.55:3306 | down | rw |
| 2 | 10.0.0.52:3306 | down | ro |
| 3 | 10.0.0.53:3306 | up | ro |
+-------------+----------------+-------+------+
3 rows in set (0.00 sec)
平滑摘除代理库
mysql> REMOVE BACKEND 2;
Empty set (0.00 sec)
mysql> SELECT * FROM backends;
+-------------+----------------+-------+------+
| backend_ndx | address | state | type |
+-------------+----------------+-------+------+
| 1 | 10.0.0.55:3306 | down | rw |
| 2 | 10.0.0.53:3306 | up | ro |
+-------------+----------------+-------+------+
2 rows in set (0.00 sec)
- 保存配置文件:
mysql> save config;
添加节点
mysql> add slave 10.0.0.52:3306;
Empty set (0.00 sec)
mysql> SELECT * FROM backends;
+-------------+----------------+-------+------+
| backend_ndx | address | state | type |
+-------------+----------------+-------+------+
| 1 | 10.0.0.55:3306 | down | rw |
| 2 | 10.0.0.53:3306 | up | ro |
| 3 | 10.0.0.52:3306 | down | ro |
+-------------+----------------+-------+------+
3 rows in set (0.00 sec)
mysql> save config;
Empty set (0.01 sec)
数据库查看负载情况
IP | 功能 |
---|---|
proxy-address = 0.0.0.0:33060 | atlas代理的端口 |
admin-address = 0.0.0.0:2345 | atlas管理节点的端口 |
mysql -umha -pmha -h127.0.0.1 -P33060
mysql> show variables like "server_id";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 3 |
+---------------+-------+
1 row in set (0.37 sec)
mysql> show variables like "server_id";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
1 row in set (0.00 sec)
mysql> show variables like "server_id";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 3 |
+---------------+-------+
1 row in set (0.00 sec)