MySQL5.6主從複製及讀寫分離的實現
html
MySQL 5.6 基於GTID的主從複製及使用amoeba配置實現讀寫分離前端
1、amoeba 簡介java
Amoeba(變形蟲)項目,該開源框架於2008年開始發佈一款 Amoeba forMysql軟件。這個軟件致力於MySQL的分佈式數據庫前端代理層,它主要在應用層訪問MySQL的時候充當SQL路由功能,專一於分佈式數據庫代理層(Database Proxy)開發。座落與 Client、DB Server(s)之間,對客戶端透明。具備負載均衡、高可用性、SQL 過濾、讀寫分離、可路由相關的到目標數據庫、可併發請求多臺數據庫合併結果。經過Amoeba你可以完成多數據源的高可用、負載均衡、數據切片的功能,目前Amoeba已在不少企業的生產線上面使用mysql
Amoeba優勢:linux
1.下降費用,簡單易用算法
2.提升系統總體可用性sql
3.易於擴展處理能力和系統規模數據庫
4.能夠直接實現讀寫分離及負載均衡的效果,而不用修改代碼vim
Amoeba 缺點:後端
1.不支持事務與存儲過程
2.暫不支持分庫分表,amoeba目前只作到分數據庫實例
3.不適合從amoeba導入數據的場景或者對大數據量查詢的query並不合適(好比一次請求返回10w以上的甚至更多的數據場合)
MySQL GTID
Mysql 5.6的新特性之一,加入了全局事務性ID(GTID:GlobalTransactions Identifier)來強化數據庫的主備一致性,故障恢復,以及容錯能力;也使得複製功能的配置、監控及管理變得更加易於實現,且更加健壯
二.MySQL主從配置
1.環境介紹:
[root@master~]# 192.168.17.15 [root@slave~]# 192.168.17.32
2.安裝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
3.slave服務器安裝mysql與master同樣 ,但在slave服務器的/etc/my.cnf配置文件中有倆個參數須要更改一下與
master服務器不一樣
server-id = 20 report-host = 192.168.17.32
4.在master服務器上建立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 #成功鏈接
5.啓動從節點的複製線程
[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表明啓動成功####
6.在master服務器建立數據庫查看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 | +----+-------------+-----------+------+---------+---------+-----------------------------------------------------------------------------+------------------+
三.讀寫分離配置
1.基於前面作的mysql主從架構,而後在前端加一臺服務器,用於實現mysql的讀分離,
2.安裝jdk
[root@amoeba ~]# chmod +xjdk-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) 3.安裝amoeba [root@amoeba ~]# mkdir /usr/local/amoeba [root@amoeba ~]# tar xfamoeba-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 #出現下邊信息表明安裝成功 amoeba start|stop
4.受權MySQL用戶,用於實現前端amoeba鏈接
mysql> grant all on *.* to'amoeba'@'192.168.%.%' identified by 'amoebapass'; mysql> flush privileges;
5.配置amoeba
[root@amoeba ~]# cd /usr/local/amoeba/conf/ amoeba.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</property> #鏈接後端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服務器的節點 name能夠自定義 <factoryConfig> <!-- mysql ip --> <propertyname="ipAddress">192.168.17.15</property> #定義master服務器的IP地址 </factoryConfig> </dbServer> <dbServer name="slave" parent="abstractServer"> #定義slave服務器的節點 <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 --> #定義數據庫池,用於實現負載均衡,「slave「爲自定義的數據庫節點,能夠寫多個用」,」隔開 <property name="poolNames">slave</property </poolConfig> </dbServer> </amoeba:dbServers> ---------------------------------------------------------------------------------------------------------------- [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代理服務器對外監聽的端口 <!-- bind ipAddress--> <!-- <propertyname="ipAddress">192.168.17.11</property> #定義amoeba代理服務器對外鏈接的監聽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> ###把 <!-- -->註釋去掉使其配置生效#### #定義默認池,默認會在此服務器上執行 <property name="writePool">master</property> #定義只寫服務器 <propertyname="readPool">slave</property> #定義只讀服務器,也能夠在dbServer.xml中定義數據池的名稱,實現負載均衡 <propertyname="needParse">true</property> </queryRouter> </amoeba:configuration>
6.啓動amoeba服務並測試
[
root@amoeba conf]# amoeba start & #後臺啓動amoeba [root@amoeba conf]# ss -tunlp | grep 3306 #啓動正常 tcp LISTEN 0 128 :::3306 :::* users:(("java",1796,52))
7.鏈接amoeba代理服務器,執行插入和查詢操做,分別在後端倆臺服務器進行抓包,查看是否實現讀寫分離
mysql> create database bds2; mysql> use bds2 mysql> create table tb2 (id int ) ; mysql> select * from tb2;
8.tcmdump測試
[root@master ~]# tcpdump -i eth0 -s0 -nn -Atcp 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服務器上執行 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服務器上執行 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~} 由上圖可知抓包實現了讀寫分離的效果