MySQL5.6主從復制及讀寫分離的實現(xiàn)
MySQL 5.6 基于GTID的主從復制及使用amoeba配置實現(xiàn)讀寫分離**
amoeba 簡介
Amoeba(變形蟲)項目,該開源框架于2008年開始發(fā)布一款 Amoeba forMysql軟件。這個軟件致力于MySQL的分布式數(shù)據(jù)庫前端代理層,它主要在應用層訪問MySQL的時候充當SQL路由功能,專注于分布式數(shù)據(jù)庫代理層(Database Proxy)開發(fā)。座落與 Client、DB Server(s)之間,對客戶端透明。具有負載均衡、高可用性、SQL 過濾、讀寫分離、可路由相關(guān)的到目標數(shù)據(jù)庫、可并發(fā)請求多臺數(shù)據(jù)庫合并結(jié)果。通過Amoeba你能夠完成多數(shù)據(jù)源的高可用、負載均衡、數(shù)據(jù)切片的功能,目前Amoeba已在很多企業(yè)的生產(chǎn)線上面使用
Amoeba優(yōu)點:
1.降低費用,簡單易用
2.提高系統(tǒng)整體可用性
3.易于擴展處理能力和系統(tǒng)規(guī)模
4.可以直接實現(xiàn)讀寫分離及負載均衡的效果,而不用修改代碼
Amoeba 缺點:
1.不支持事務與存儲過程
2.暫不支持分庫分表,amoeba目前只做到分數(shù)據(jù)庫實例
3.不適合從amoeba導入數(shù)據(jù)的場景或者對大數(shù)據(jù)量查詢的query并不合適(比如一次請求返回10w以上的甚至更多的數(shù)據(jù)場合)
MySQL GTID
Mysql 5.6的新特性之一,加入了全局事務性ID(GTID:GlobalTransactions Identifier)來強化數(shù)據(jù)庫的主備一致性,故障恢復,以及容錯能力;也使得復制功能的配置、監(jiān)控及管理變得更加易于實現(xiàn),且更加健壯
MySQL主從配置
環(huán)境介紹:
[root@master~]# 192.168.17.15
[root@slave~]# 192.168.17.32
安裝mysql服務器在倆臺主機上
tar xfmysql-5.6.13-linux-glibc2.5-x86_64.tar.gz -C /usr/local
cd /usr/local/
ln -sv mysql-5.6.13-linux-glibc2.5-x86_64/mysql
cd mysql
chown –R root.msyql *
cp support-files/mysql.server/etc/init.d/mysqld
chmod +x /etc/init.d/mysqld
chkconfig --add mysqld
chkconfig mysqld on
echo"PATH=/usr/local/mysql/bin:$PATH" > /etc/profile
. /etc/profile
cat /etc/my.cnf | egrep -v "^#"> /root/my.cnf
cp /root/my.cnf /etc/
主/etc/my.cnf的配置文件總匯
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
port = 3306
socket = /tmp/mysql.sock
skip-external-locking
key_buffer_size = 256M
max_allowed_packet = 1M
table_open_cache = 256
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size= 16M
thread_concurrency = 8
datadir=/mydata/data
innodb_file_per_table = 1
log-bin=/binlog/mysql-bin
binlog_format=row
log-slave-updates=true
gtid-mode=on
enforce-gtid-consistency=true
master-info-repository=TABLE
relay-log-info-repository=TABLE
sync-master-info=1
slave-parallel-workers=2
binlog-checksum=CRC32
master-verify-checksum=1
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1
report-port=3306
report-host=192.168.17.32
server-id = 20
[mysqldump]
quick
max_allowed_packet = 16M
[mysql]
no-auto-rehash
[myisamchk]
key_buffer_size = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M
[mysqlhotcopy]
interactive-timeout
初始化mysql并啟動
chown -R mysql.mysql /mydata/data/
chown -R mysql.mysql /binlog/
./scripts/mysql_install_db --user=mysql--datadir=/mydata/data/
service mysqld start
slave服務器安裝mysql與master一樣 ,但在slave服務器的/etc/my.cnf配置文件中有倆個參數(shù)需要更改一下與master服務器不同
server-id = 20
report-host = 192.168.17.32
在master服務器上創(chuàng)建slave復制用戶并測試連接
mysql> grant replication client,replication slave on *.* to 'slave'@'192.168.%.%' identified by 'budongshu';
mysql> flush privileges;
[root@slave mysql]# mysql -uslave-pbudongshu -h 192.168.17.15 #成功連接
啟動從節(jié)點的復制線程
[root@slave mysql]# mysql
mysql> change master tomaster_host='192.168.17.15',
-> master_user='slave',
-> master_password='budongshu',
-> master_auto_position=1;
mysql> start slave;
mysql> show slave status \G
Slave_IO_Running: Yes
Slave_SQL_Running:Yes
yes代表啟動成功,必須要倆個全部都是yes
在master服務器創(chuàng)建數(shù)據(jù)庫查看slave服務器是否更新
[root@master ~]# mysql -e 'create databasebds1'
[root@slave mysql]# mysql -e 'showdatabases'
+--------------------+
| Database |
+--------------------+
| information_schema |
| bds |
| bds1 | #slave服務器同步正常
| mysql |
| performance_schema |
| test |
+--------------------+
mysql> show processlist; #查看gtid進程
+----+-------------+-----------+------+---------+---------+-----------------------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------+------+---------+---------+-----------------------------------------------------------------------------+------------------+
| 4| system user | | NULL |Connect | 395 | Waiting for master tosend event | NULL |
| 5| system user | | NULL |Connect | 225 | Slave has read allrelay log; waiting for the slave I/O thread to update it | NULL |
| 6| system user | | NULL |Connect | -252924 | Waiting for an event from Coordinator | NULL |
| 7| system user | | NULL |Connect | -253320 | Waiting for an event from Coordinator | NULL |
| 9| root | localhost | NULL |Query | 0 | init |show processlist |
+----+-------------+-----------+------+---------+---------+-----------------------------------------------------------------------------+------------------+
讀寫分離配置
基于前面做的mysql主從架構(gòu),然后在前端加一臺服務器,用于實現(xiàn)mysql的讀分離,
安裝jdk (bin結(jié)尾的包,rpm包都可以,可以去oracle官網(wǎng)下載)
[root@amoeba ~]# chmod +x jdk-6u31-linux-x64-rpm.bin
[root@amoeba ~]#. /jdk-6u31-linux-x64-rpm.bin
[root@amoeba ~]# vim /etc/profile.d/java.sh
export JAVA_HOME=/usr/java/latest
export PATH=$JAVA_HOME/bin:$PATH
[root@amoeba ~]#. /etc/profile.d/java.sh
[root@amoeba ~]# java -version
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build1.6.0_31-b04)
Java HotSpot(TM) 64-Bit Server VM (build20.6-b01, mixed mode)
安裝amoeba
[root@amoeba ~]# mkdir /usr/local/amoeba
[root@amoeba ~]# tar xf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/
[root@amoeba ~]# vi/etc/profile.d/amoeba.sh
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$AMOEBA_HOME/bin:$PATH
[root@amoeba ~]# . /etc/profile.d/amoeba.sh
[root@amoeba ~]# amoeba #出現(xiàn)下邊信息代表安裝成功
amoeba start|stop
授權(quán)MySQL用戶,用于實現(xiàn)前端amoeba連接
mysql> grant all on *.* to'amoeba'@'192.168.%.%' identified by 'amoebapass';
mysql> flush privileges;
配置amoeba
[root@amoeba ~]# cd /usr/local/amoeba/conf/
amoeba.xml #定義管理信息與讀寫分離
dbServers.xml #定義后端服務器的配置
配置文件dbServers.xml介紹
[root@amoeba conf]# vi dbServers.xml
<?xml version="1.0"encoding="gbk"?>
<!DOCTYPE amoeba:dbServers SYSTEM"dbserver.dtd">
<amoeba:dbServersxmlns:amoeba="http://amoeba.meidusa.com/">
<!--
Each dbServer needs tobe configured into a Pool,
If you need toconfigure multiple dbServer with load balancing that can be simplified by thefollowing configuration:
add attribute with name virtual ="true" in dbServer, but the configuration does not allow the elementwith name factoryConfig
such as 'multiPool'dbServer
-->
<dbServer name="abstractServer" abstractive="true">
<factoryConfigclass="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
<propertyname="manager">${defaultManager}</property>
<propertyname="sendBufferSize">64</property>
<propertyname="receiveBufferSize">128</property>
<!-- mysql port-->
<propertyname="port">3306</property> #連接后端mysql服務器的端口
<!-- mysql schema-->
<propertyname="schema">test</property> #連接后端mysql服務器的默認庫
<!-- mysql user-->
<propertyname="user">amoeba</property> #連接后端mysql服務器的用戶名
<!-- mysql password --> #把password最后的注釋(-->)這個符號去掉跟上邊一樣
<propertyname="password">amoebapass</propert> #連接后端mysql服務器的密碼
</factoryConfig>
<poolConfigclass="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
<propertyname="maxActive">500</property>
<propertyname="maxIdle">500</property>
<propertyname="minIdle">10</property>
<propertyname="minEvictableIdleTimeMillis">600000</property>
<propertyname="timeBetweenEvictionRunsMillis">600000</property>
<propertyname="testOnBorrow">true</property>
<propertyname="testOnReturn">true</property>
<propertyname="testWhileIdle">true</property>
</poolConfig>
</dbServer>
<dbServer name="master" parent="abstractServer"> #定義master服務器的節(jié)點 name可以自定義
<factoryConfig>
<!-- mysql ip -->
<propertyname="ipAddress">192.168.17.15</property> #定義master服務器的IP地址
</factoryConfig>
</dbServer>
<dbServer name="slave" parent="abstractServer"> #定義slave服務器的節(jié)點
<factoryConfig>
<!-- mysql ip -->
<propertyname="ipAddress">192.168.17.32</property>
</factoryConfig>
</dbServer>
<dbServer name="multiPool" virtual="true">
<poolConfigclass="com.meidusa.amoeba.server.MultipleServerPool">
<!-- Load balancingstrategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA--> #負載均衡算法
<propertyname="loadbalance">1</property> #定義選擇哪一種算法
<!-- Separated bycommas,such as: server1,server2,server1 --> #定義數(shù)據(jù)庫池,用于實現(xiàn)負載均衡,“slave“為自定義的數(shù)據(jù)庫節(jié)點,可以寫多個用”,”隔開
<property name="poolNames">slave</property
</poolConfig>
</dbServer>
</amoeba:dbServers>
配置文件amoeba.xml 介紹
[root@amoeba conf]# vi amoeba.xml
<?xml version="1.0"encoding="gbk"?>
<!DOCTYPE amoeba:configuration SYSTEM"amoeba.dtd">
<amoeba:configurationxmlns:amoeba="http://amoeba.meidusa.com/">
<proxy>
<!-- service class mustimplements com.meidusa.amoeba.service.Service -->
<servicename="Amoeba for Mysql"class="com.meidusa.amoeba.net.ServerableConnectionManager">
<!-- port -->
<propertyname="port">3306</property> #定義amoeba代理服務器對外監(jiān)聽的端口
<!-- bind ipAddress-->
<!--
<propertyname="ipAddress">192.168.17.11</property> #定義amoeba代理服務器對外連接的監(jiān)聽ip
-->
<propertyname="manager">${clientConnectioneManager}</property>
<propertyname="connectionFactory">
<beanclass="com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory">
<property name="sendBufferSize">128</property>
<property name="receiveBufferSize">64</property>
</bean>
</property>
<propertyname="authenticator">
<beanclass="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator"> #定義客戶端使用的用戶名和密碼
<property name="user">admin</property>
<property name="password">password</property>
<property name="filter">
<beanclass="com.meidusa.amoeba.server.IPAccessController">
<propertyname="ipFile">${amoeba.home}/conf/access_list.conf</property>
</bean>
</property>
</bean>
</property>
</service>
<!-- server class mustimplements com.meidusa.amoeba.service.Service -->
<service name="AmoebaMonitor Server"class="com.meidusa.amoeba.monitor.MonitorServer">
<!-- port -->
<!-- default value: random number
<propertyname="port">9066</property>
-->
<!-- bind ipAddress-->
<propertyname="ipAddress">127.0.0.1</property>
<propertyname="daemon">true</property>
<propertyname="manager">${clientConnectioneManager}</property>
<propertyname="connectionFactory">
<beanclass="com.meidusa.amoeba.monitor.net.MonitorClientConnectionFactory"></bean>
</property>
</service>
<runtimeclass="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext">
<!-- proxy servernet IO Read thread size -->
<propertyname="readThreadPoolSize">20</property>
<!-- proxy serverclient process thread size -->
<propertyname="clientSideThreadPoolSize">30</property>
<!-- mysql serverdata packet process thread size -->
<propertyname="serverSideThreadPoolSize">30</property>
<!-- per connectioncache prepared statement size -->
<propertyname="statementCacheSize">500</property>
<!-- query timeout(default: 60 second , TimeUnit:second) -->
<propertyname="queryTimeout">60</property>
</runtime>
</proxy>
<!--
Each ConnectionManager willstart as thread
manager responsible for theConnection IO read , Death Detection
-->
<connectionManagerList>
<connectionManagername="clientConnectioneManager"class="com.meidusa.amoeba.net.MultiConnectionManagerWrapper">
<propertyname="subManagerClassName">com.meidusa.amoeba.net.ConnectionManager</property>
<!--
default value isavaliable Processors
<propertyname="processors">5</property>
-->
</connectionManager>
<connectionManagername="defaultManager" class="com.meidusa.amoeba.net.MultiConnectionManagerWrapper">
<propertyname="subManagerClassName">com.meidusa.amoeba.net.AuthingableConnectionManager</property>
<!--
default value is avaliableProcessors
<propertyname="processors">5</property>
-->
</connectionManager>
</connectionManagerList>
<!-- default using fileloader -->
<dbServerLoader class="com.meidusa.amoeba.context.DBServerConfigFileLoader">
<propertyname="configFile">${amoeba.home}/conf/dbServers.xml</property>
</dbServerLoader>
<queryRouterclass="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter">
<propertyname="ruleLoader">
<beanclass="com.meidusa.amoeba.route.TableRuleFileLoader">
<propertyname="ruleFile">${amoeba.home}/conf/rule.xml</property>
<propertyname="functionFile">${amoeba.home}/conf/ruleFunctionMap.xml</property>
</bean>
</property>
<propertyname="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property>
<propertyname="LRUMapSize">1500</property>
<propertyname="defaultPool">master</property> #把 <!-- -->注釋去掉使其配置生效, 定義默認池,默認會在此服務器上執(zhí)行
<property name="writePool">master</property> #定義只寫服務器
<propertyname="readPool">slave</property> #定義只讀服務器,也可以在dbServer.xml中定義數(shù)據(jù)池的名稱,實現(xiàn)負載均衡
<propertyname="needParse">true</property>
</queryRouter>
</amoeba:configuration>
啟動amoeba服務并測試
[root@amoeba conf]# amoeba start & #后臺啟動amoeba
[root@amoeba conf]# ss -tunlp | grep 3306 #啟動正常
tcp LISTEN 0 128 :::3306 :::* users:(("java",1796,52))
連接amoeba代理服務器,執(zhí)行插入和查詢操作,分別在后端倆臺服務器進行抓包,查看是否實現(xiàn)讀寫分離
mysql> create database bds2;
mysql> use bds2
mysql> create table tb2 (id int ) ;
mysql> select * from tb2;
tcpdump抓包查看檢測
[root@master ~]# tcpdump -i eth0 -s0 -nn -A tcp dst port 3306 and dst host192.168.17.15
13:25:46.488469 IP 192.168.17.11.39787 >192.168.17.15.3306: Flags [P.], seq 171:202, ack 444, win 490, options[nop,nop,TS val 8050703 ecr 15047099], length 31
E..S4 @.@.c1.........k....z..y.............
.z...........create table tb2 (id int ) ###寫請求在master服務器上執(zhí)行
13:25:46.523028 IP 192.168.17.32.41112 >192.168.17.15.3306: Flags [.], ack 1661, win 1117, options [nop,nop,TS val41437531 ecr 15058573], length 0
E..4..@.@.y{... ........M.$....4...]. .....
.xI[....
13:25:46.523050 IP 192.168.17.11.39787 >192.168.17.15.3306: Flags [.], ack 455, win 490, options [nop,nop,TS val 8050737ecr 15058574], length 0
E..44
@.@.cO.........k....z..y......Q......
.z.1....
[root@slave ~]# tcpdump -i eth0 -s0 -nn -Atcp dst port 3306 and dst host 192.168.17.32
15:01:20.243577 IP 192.168.17.11.54071 >192.168.17.32.3306: Flags [.], ack 196, win 457, options [nop,nop,TS val8129871 ecr 41516665], length 0
E..4@.@.@.V}....... .7..}. ....i...........
O.y~y
15:01:20.246139 IP 192.168.17.11.54071 >192.168.17.32.3306: Flags [P.], seq 133:155, ack 196, win 457, options[nop,nop,TS val 8129874 ecr 41516665], length 22
E..J@.@.@.Vf....... .7..}. ....i...........
R.y~y.....select * from tb2 ###讀請求在slave服務器上執(zhí)行
15:01:20.287625 IP 192.168.17.11.54071 >192.168.17.32.3306: Flags [.], ack 259, win 457, options [nop,nop,TS val8129915 ecr 41516669], length 0
E..4@.@.@.V{....... .7..}. ..........}.....
{.y~}
由上圖可知抓包實現(xiàn)了讀寫分離的效果