采用Atlas+Keepalived实现MySQL读写分离、读负载均衡

时间:2022-09-21 23:18:57

一、简介

Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bug,添加了很多功能特性。目前该项目在360公司内部得到了广泛应用,很多MySQL业务已经接入了Atlas平台,每天承载的读写请求数达几十亿条。

主要功能:

123456 1.读写分离2.从库负载均衡3.IP过滤4.自动分表5.DBA可平滑上下线DB6.自动摘除宕机的DB

二、Atlas相对于官方MySQL-Proxy的优势

1234 1.将主流程中所有Lua代码用C重写,Lua仅用于管理接口2.重写网络模型、线程模型3.实现了真正意义上的连接池4.优化了锁机制,性能提高数十倍

三、Atlas详细说明

1234567 1.Atlas的安装2.Atlas的运行及常见问题3.Atlas的分表功能简介4.Atla部分配置参数及原理详解5.Atlas的架构6.Atlas的性能测试7.Atlas功能特点FAQ

四、Atlas的需求及Bug反馈方式

如果用户在实际的应用场景中对Atlas有新的功能需求,或者在使用Atlas的过程中发现了bug,欢迎用户发邮件至zhuchao[AT]360.cn,与我们取得联系,我们将及时回复。另外有热心网友建立了QQ群326544838,开发者也已经加入,方便讨论。

五、名字来源

Atlas:希腊神话中双肩撑天的巨人,普罗米修斯的兄弟,最高大强壮的神之一,因反抗宙斯失败而被罚顶天。我们期望这个系统能够脚踏后端DB,为前端应用撑起一片天。

六、安装

Atlas的安装非常简单,从https://github.com/Qihoo360/Atlas/releases地址下载相应的rpm包直接安装即可,可能有一些依赖关系,yum都能解决的,就不多讲了!

七、配置文件:

配置文件位置/usr/local/mysql-proxy/config下面,就我的内网应用而言,我创建新的配置文件如下:

123456789101112131415161718192021222324252627282930313233343536373839 [mysql-proxy]#带#号的为非必需的配置项目#管理接口的用户名admin-username=admin#管理接口的密码admin-password=passw0rd#Atlas后端连接的MySQL主库的IP和端口,可设置多项,用逗号分隔proxy-backend-addresses=192.168.1.66:3306#Atlas后端连接的MySQL从库的IP和端口,@后面的数字代表权重,用来作负载均衡,若省略则默认为1,可设置多项,用逗号分隔proxy-read-only-backend-addresses=192.168.1.64:3306,192.168.1.244:3306#用户名与其对应的加密过的MySQL密码,密码使用PREFIX/bin目录下的加密程序encrypt加密,下行的user1和user2为示例,将其替换为你的MySQL的用户名和加密密码!#pwds = user1:+jKsgB3YAG8=, user2:GS+tr4TPgqc=pwds=root:FYCDJMDki+SiquyHfJnWyQ==#设置Atlas的运行方式,设为true时为守护进程方式,设为false时为前台方式,一般开发调试时设为false,线上运行时设为truedaemon=true#设置Atlas的运行方式,设为true时Atlas会启动两个进程,一个为monitor,一个为worker,monitor在worker意外退出后会自动将其重启,设为false时只有worker,没有monitor,一般开发调试时设为false,线上运行时设为truekeepalive=true#工作线程数,对Atlas的性能有很大影响,可根据情况适当设置event-threads=64#日志级别,分为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#实例名称,用于同一台机器上多个Atlas实例间的区分#instance = test#Atlas监听的工作接口IP和端口proxy-address=0.0.0.0:1234#Atlas监听的管理接口IP和端口admin-address=0.0.0.0:2345#分表设置,此例中person为库名,mt为表名,id为分表字段,3为子表数量,可设置多项,以逗号分隔,若不分表则不需要设置该项#tables = person.mt.id.3#默认字符集,设置该项后客户端不再需要执行SET NAMES语句#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

八、启动关闭重启:

123 # /usr/local/mysql-proxy/bin/mysql-proxyd instance start# /usr/local/mysql-proxy/bin/mysql-proxyd instance stop# /usr/local/mysql-proxy/bin/mysql-proxyd instance restart

九、负载读写分离测试:

12345678910111213141516171819202122232425262728293031323334 [root@YQD-Intranet-DB-NO2~]# mysql -uroot -p***** -h192.168.1.63 -P1234WelcometotheMySQLmonitor.  Commandsendwith;org.YourMySQLconnectionidis1295815494Serverversion:5.0.81-logSourcedistribution Copyright(c)2009-2013PerconaLLCand/oritsaffiliatesCopyright(c)2000,2013,Oracleand/oritsaffiliates.Allrightsreserved. OracleisaregisteredtrademarkofOracleCorporationand/oritsaffiliates.Othernamesmaybetrademarksoftheirrespectiveowners. Type'help;'or'h'forhelp.Type'c'toclearthecurrentinputstatement. root@(none)10:28:46>showvariableslike"server_id";+---------------+-------+|Variable_name|Value|+---------------+-------+|server_id    |3    |+---------------+-------+1rowinset(0.00sec) root@(none)10:28:48>showvariableslike"server_id";+---------------+-------+|Variable_name|Value|+---------------+-------+|server_id    |2    |+---------------+-------+1rowinset(0.00sec) 开启sql日志,日志显示如下:[06/27/201410:36:56]C:192.168.1.228:50179S:192.168.1.244:3306OK0.419"SHOW CREATE TABLE `t_categary`"[06/27/201410:36:56]C:192.168.1.228:50180S:192.168.1.64:3306OK0.739"SELECT * FROM `t_categary` LIMIT 0, 1000"[06/27/201410:36:56]C:192.168.1.228:50180S:192.168.1.244:3306OK0.724"SHOW COLUMNS FROM `cat_db`.`t_categary`"

OLTP基准测试:
OLTP基准测试模拟了一个简单的的事务处理系统的工作负载。下面的例子使用的是一张百万行记录的表,第一步先生成这张表:

123456789 # time sysbench --test=oltp --db-driver=mysql --mysql-engine-trx=yes --mysql-table-engine=innodb --mysql-host=127.0.0.1 --mysql-port=1234 --mysql-user=root --mysql-password=****** --oltp-table-size=1000000 preparesysbench 0.4.12:  multi-threaded system evaluation benchmark Creating table 'sbtest'...Creating 1000000 records in table 'sbtest'... real0m58.132suser0m0.209ssys0m0.036s

接下来可以运行测试,这个例子采用了16个并发线程,只读模拟测试:

123456789101112131415161718192021222324252627282930313233343536373839404142434445 # time sysbench --test=oltp --db-driver=mysql --mysql-engine-trx=yes --mysql-table-engine=innodb --mysql-host=127.0.0.1 --mysql-port=1234 --oltp-read-only=on --mysql-user=root --mysql-password=****** --oltp-table-size=1000000 --num-threads=16 runsysbench0.4.12:  multi-threadedsystemevaluationbenchmark Runningthetestwithfollowingoptions:Numberofthreads:16 DoingOLTPtest.RunningmixedOLTPtestDoingread-onlytestUsingSpecialdistribution(12iterations,  1pctofvaluesarereturnedin75pctcases)Using"BEGIN"forstartingtransactionsUsingauto_incontheidcolumnMaximumnumberofrequestsforOLTPtestislimitedto10000Threadsstarted!Done. OLTPteststatistics:    queriesperformed:        read:                            140000        write:                          0        other:                          20000        total:                          160000    transactions:                        10000  (1007.89persec.)    deadlocks:                          0      (0.00persec.)    read/writerequests:                140000(14110.48persec.)    otheroperations:                    20000  (2015.78persec.) Testexecutionsummary:    totaltime:                          9.9217s    totalnumberofevents:              10000    totaltimetakenbyeventexecution:158.5972    per-requeststatistics:        min:                                10.86ms        avg:                                15.86ms        max:                                25.08ms        approx.  95percentile:              18.51ms Threadsfairness:    events(avg/stddev):          625.0000/4.08    executiontime(avg/stddev):  9.9123/0.00  real0m10.198suser0m1.216ssys0m2.583s

从时间上来看比之前haproxy测试要略慢,还是haproxy的性能更靠谱,但是haproxy需要在应用层实现读写分离,就是代码了

tpcc压测:

12345678910 root@(none) 10:46:19>create database tpcc5;Query OK, 1 row affected (0.54 sec) # mysql -uroot -p******* -h192.168.1.63 -P1234 tpcc5 < create_table.sql Warning: Using a password on the command line interface can be insecure.ERROR 1231 (42000) at line 140: Variable 'foreign_key_checks' can't be set to the value of 'NULL' # mysql -uroot -p******* -h192.168.1.63 -P1234 tpcc5 < add_fkey_idx.sql Warning: Using a password on the command line interface can be insecure.ERROR 1231 (42000) at line 23: Variable 'foreign_key_checks' can't be set to the value of 'NULL'

tpcc导入表时出错了,提示变量foreign_key_checks不能设置为NULL值,暂且不管它,继续测试:

123456789101112131415161718192021222324 # ./tpcc_load 192.168.1.63:1234 tpcc5 root "********" 3****************************************###easy### TPC-C Data Loader  ****************************************<Parameters>    [server]:192.168.1.63    [port]:1234    [DBname]:tpcc5      [user]:root      [pass]:LVS@071103  [warehouse]:3TPCCDataLoadStarted...LoadingItem..................................................5000..................................................10000..................................................15000..................................................20000..................................................25000..................................................30000..................................................35000..................................................40000..................................................45000..................................................50000下面省略N.......................................

1234567891011121314151617181920212223242526272829303132333435 # ./tpcc_start -h192.168.1.63 -P1234 -dtpcc5 -uroot -p******** -w3 -c32 -r10 -l600******************************************###easy### TPC-C Load Generator ******************************************中间省略N.................................................<RawResults>  [0]sc:5059  lt:0  rt:0  fl:0  [1]sc:5057  lt:0  rt:0  fl:0  [2]sc:506  lt:0  rt:0  fl:0  [3]sc:506  lt:0  rt:0  fl:0  [4]sc:506  lt:0  rt:0  fl:0in600sec. <RawResults2(sumver.)>  [0]sc:5059  lt:0  rt:0  fl:0  [1]sc:5059  lt:0  rt:0  fl:0  [2]sc:506  lt:0  rt:0  fl:0  [3]sc:506  lt:0  rt:0  fl:0  [4]sc:506  lt:0  rt:0  fl:0 <ConstraintCheck>(allmustbe[OK])[transactionpercentage]        Payment:43.47%(>=43.0%)[OK]  Order-Status:4.35%(>=4.0%)[OK]      Delivery:4.35%(>=4.0%)[OK]    Stock-Level:4.35%(>=4.0%)[OK][responsetime(atleast90%passed)]      New-Order:100.00%  [OK]        Payment:100.00%  [OK]  Order-Status:100.00%  [OK]      Delivery:100.00%  [OK]    Stock-Level:100.00%  [OK] <TpmC>                505.900TpmC

经过一段时间的使用,发现atlas目前是比较稳定的,但是性能不作过多评价!有时面面俱到真是难!多一层代理,性能肯定会下降,如果程序端能实现读写分离,直连集群或主备,那样的性能应该是最好的。

[参考资料]采用Atlas+Keepalived实现MySQL读写分离、读负载均衡 - http://sofar.blog.51cto.com/353572/1601552/