主從複製以及主從複製的作用:
在實際的生產環境中,對數據庫的讀和寫都在同一個數據庫服務器中,是不能滿足實際需求的,通過主從複製的方式來同步數據,再通過讀寫分離來提升數據庫的併發負載能力
.
mysql主從複製
mysq支持的複製類型
-
基於語句的複製。在服務器上執行sql語句,在從服務器上執行同樣的語句,mysql默認採用基於語句的複製,執行效率高。
-
基於行的複製。把改變的內容複製過去,而不是把命令在從服務器上執行一遍。
- 混合類型的複製。默認採用基於語句的複製,一旦發現基於語句無法精確複製時,就會採用基於行的複製。
.
複製的工作過程
.
*在每個事務更新數據完成之前,master在二進制日誌記錄這些改變。寫入二進制日誌完成後,master通知存儲引擎提交事務。
-
Slave將master的binary log複製到其中繼日誌。首先slave開始一個工作線程(I/O),I/O線程在master上打開一個普通的連接,然後開始binlog dump process。binlog dump process從master的二進制日誌中讀取事件,如果已經跟上master,它會睡眠並等待master產生新的事件,I/O線程將這些事件寫入中繼日誌。
- Sql slave thread(sql從線程)處理該過程的最後一步,sql線程從中繼日誌讀取事件,並重放其中的事件而更新slave數據,使其與master中的數據一致,只要該線程與I/O線程保持一致,中繼日誌通常會位於os緩存中,所以中繼日誌的開銷很小。
.
MySQL讀寫分離原理
讀寫分離就是在主服務器上修改,數據會同步到從服務器,從服務器只能提供讀取數據,不能寫入,實現備份的同時也實現了數據庫性能的優化,以及提升了服務器安全。
前較爲常見的Mysql讀寫分離分爲以下兩種:
.
-
基於程序代碼內部實現
在代碼中根據select 、insert進行路由分類,這類方法也是目前生產環境下應用最廣泛的。優點是性能較好,因爲程序在代碼中實現,不需要增加額外的硬件開支,缺點是需要開發人員來實現,運維人員無從下手。
. -
基於中間代理層實現
代理一般介於應用服務器和數據庫服務器之間,代理數據庫服務器接收到應用服務器的請求後根據判斷後轉發到,後端數據庫,有以下代表性的程序。
.
環境介紹;
安裝mysql過程不做解釋
(mysql。主)
[root@centos1 ]# mount /dev/cdrom /media/
[root@centos1 ]# yum -y install ntp
.
[root@centos1 ]# vim /etc/ntp.conf
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
server 127.127.1.0 /添加
fudge 127.127.1.0 stratum 8 /添加
.
重啓ntpd服務
[root@centos1 ]# service ntpd restart
.
防火牆開例外
[root@centos1 ]# iptables -I INPUT -p udp --dport 123 -j ACCEPT
[root@centos1 ]# iptables -I INPUT -p udp --dport 3306 -j ACCEPT
在(節點A)進行時間同步
[root@centos1 ]# yum -y install ntpdate
[root@centos1 ]# /usr/sbin/ntpdate 192.168.1.30
在(節點B)進行時間同步
[root@centos1 ]# yum -y install ntpdate
[root@centos1 ]# /usr/sbin/ntpdate 192.168.1.30
.
(mysql。主)
修改/etc/my.cnf配置文件
[root@centos1 ]# vim /etc/my.cnf
server-id = 11 //mysql數據的唯一標示(不能重複)
log-slave-updates=true //允許連級複製 (增加)
log-bin=master-bin //二進制文件名(修改)
.
重啓mysql服務
[root@centos1 ]# service mysqld restart
.
登陸mysql給從服務器授權
[root@centos1 ]# mysql -u root -p
.
mysql> GRANT REPLICATION SLAVE ON *.* TO 'lijialiang'@'192.168.1.%' IDENTIFIED BY '123456';
.
mysql> FLUSH PRIVILEGES;
.
mysql> show master status;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000001 | 558 | | |
+-------------------+----------+--------------+------------------+
1 row in set (0.03 sec)
.
(節點B,C)
在/etc/my.cnf中修改以下內容
[root@centos3 ~]# vim /etc/my.cnf
server-id = 22 //不能與其他實例重複
log-bin=mysql-bin //二進制日誌文件名 修改
relay-log=relay-log-bin //複製過來的二進制文件名,增加
relay-log-index=slave-relay-bin.index //中繼日誌存放的文件名稱,增加
.
重啓mysql服務
[root@centos1 ]# service mysql restart
.
登錄mysql 配置同步
[root@centos1 ]# mysql -u root -p
mysql> change master to
master_host='192.168.1.30',master_user='lijialiang',master_password='123456',master_log_file='master-bin.000001',master_log_pos=558;
IP地址、用戶、密碼都master的數據庫信息
.
啓動同步
mysql> start slave;
.
查看slave狀態確保以下兩個值爲YES
.
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.30
Master_User: lijialiang
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 558
Relay_Log_File: relay-log-bin.609531
Relay_Log_Pos: 254
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.
(mysql。主)
.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.11 sec)
.
mysql> create datebase IT;
.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| IT |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.11 sec)
.
(節點B,C)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| IT |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.27 sec)
.
讀寫分離
(amoeba)
讀寫分離安裝java環境(amoeba軟件基於java平臺運行)
運行jdk
[root@centos1 ]# umount /dev/cdrom /media/
[root@centos1 ]# mount /dev/cdrom /media/
[root@centos1 ]# cp jdk-6u14-linux-x64.bin /usr/local/
[root@centos1 ]# cd /usr/local/
[root@centos1 ]# chmod +x jdk-6u14-linux-x64.bin
[root@centos1 ]# ./jdk-6u14-linux-x64.bin
安裝過程中提示(yes/no),我們要選擇yes安裝
.
修改/etc/profile配置文件,增加以下配置
[root@centos1 ]# mv jdk1.6.0_14/ /usr/local/jdk1.6
[root@centos1 ]# vim /etc/profile
.
export JAVA_HOME=/usr/local/jdk1.6 //設置jdk的根目錄
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib //將jdk的程序文件賦予CLASSPATH變量
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin:$PATH:$HOME/bin //將jdk的程序文件賦予PATH變量
export AMOEBA_HOME=/usr/local/amoeba/ //定義AMOEBA的根目錄
export PATH=$PATH:$AMOEBA_HOME/bin //將amoeba的程序文件複製給PATH變量
.
執行腳本
[root@centos1 ]# source /etc/profile
[root@centos1 ]# java -version
.
安裝並配置Amoeba軟件
安裝
[root@centos1 ]# mkdir /usr/local/amoeba
[root@centos1 ]# cd /media/
[root@centos1 ]# ls
[root@centos1 ]# tar zxf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
[root@centos1 ]# chmod -R 755 /usr/local/amoeba/
.
出現以下內容說明安裝成功了
[root@centos1 ]# /usr/local/amoeba/bin/amoeba
amoeba start|stop
.
配置amoeba讀寫分離,兩個從節點讀負載均衡
在主從服務器上開放權限給amoeba(三臺服務器上都做相同設置,這裏以一臺爲例)
mysql> grant all on *.* to liang@'192.168.1.%' identified by '123456';
.
修改amoeba.xml文件
注意:所有配置文件註釋都是以 <!-- 內容 -->,再刪除註釋時請將內容也一併刪除,最好是刪除正行,但是有些時候只需要刪除頭和尾即可,裏面的配置項是可以直接使用的。這個配置文件需要定義兩個配置,第一是應用程序使用什麼用戶連接amoeba訪問到後端的mysql數據庫,第二個是定義默認寫池以及讀池。
[root@centos1 ]# cd /usr/local/amoeba/
[root@centos1 ]# vim conf/amoeba.xml
<bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">
<property
name="user">amoeba</property> //這裏的帳戶名和密碼在後面鏈接amoeba使用
<property
name="password">123456</property>
<property name="filter">
.......................................................................
<property name="LRUMapSize">1500</property>
<property name="defaultPool">master</property> //修改爲master
//注意:這裏原有註釋,需要刪除
<property name="writePool">master</property> //修改爲master
<property name="readPool">slaves</property> //修改爲slaves
<property name="needParse">true</property>
.
編輯dbServers.xml
[root@centos1 ]# vim conf/dbServers.xml
<!-- mysql schema -->
<property name="user">liang</property> //之前設置開放權限的用戶名和密碼
//注意刪掉此位置的註釋
<property name="password">123456</property>
//注意刪掉此位置的註釋
</factoryConfig>
.............................................................................
<dbServer name="master" parent="abstractServer"> //修改爲master
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.1.30</property> //修改IP
</factoryConfig>
</dbServer>
<dbServer name="slave1" parent="abstractServer"> //修改爲slave1
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.1.40</property> //修改IP
</factoryConfig>
</dbServer>
<dbServer name="slave2" parent="abstractServer"> //複製一份,修改爲slave2
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.1.50</property> //修改IP
</factoryConfig>
</dbServer>
<dbServer name="slaves" virtual="true"> //修改爲slaves
<poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
<!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
<property name="loadbalance">1</property>
<!-- Separated by commas,such as: server1,server2,server1 -->
<property name="poolNames">slave1,slave2</property> //修改爲slave1,slave2
</poolConfig>
</dbServer>
</amoeba:dbServers>
.
.
啓動amoeba軟件
[root@centos1 ]# bin/amoeba start&
[root@centos1 ]# netstat -anpt | grep java
.
測試讀寫分離
打開一臺客戶端192.168.1.10,也需要安裝mysql,作爲測試機,可以使用yum -y install mysql安裝。
.
建立防火牆規則
[root@centos1 /]# iptables -I INPUT -p tcp --dport 8066 -j ACCEPT
.
amoeba,主服務器和兩個從節點,都需要開放3306端口入站
[root@centos1 /]# iptables -I INPUT -p tcp --dport 3306 -j ACCEPT
[root@centos1 /]# service iptables save
.
也可修改amoeba的amoeba.xml配置文件的第一個8066改爲3306之後建立一條防火牆規則爲允許3306端口入站並且重新啓動amoeba服務
<property name="port">3306</property> //在11行
這樣一來測試機訪問的時候後方就不用跟 P 8066 了
.
重啓服務
[root@centos1 ]# bin/amoeba restart&
測試階段
(客戶端)
[root@centos1 ]# mysql -u amoeba -p 123456 -h 192.168.1.20 P 8066
密碼123456,爲:之前登陸amoeba設置的密碼
在主服務器master上創建一個數據庫WLZS,同步到各從服務器上,然後關掉從服務器的slave功能,再插入數據。
(主服務器)
mysql> create database WLGCSZS;
Query OK, 1 row affected (0.84 sec)
mysql> use WLGCSZS;
Database changed
mysql> create table student(id int,name char(10));
Query OK, 0 rows affected (1.39 sec)
.
(從服務器查看同步)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| WLGCSZS |
| IT |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.27 sec)
.
(主服務器寫入數據)
mysql> insert into student values(1,'li');
Query OK, 1 row affected (0.48 sec)
.
(從服務器也同步了)
mysql> use WLGCSZS;
Database changed
mysql> select * from student;
+------+------+
| id | name |
+------+------+
| 1 | li |
+------+------+
1 row in set (0.45 sec)
.
在兩臺從服務器執行stop slave
分別在兩臺從服務器寫入不同數據
(節點A)
mysql> stop slave;
Query OK, 0 rows affected (0.05 sec)
mysql> use WLGCSZS;
Database changed
mysql> insert into student values(5,'jia');
Query OK, 1 row affected (0.07 sec)
.
(節點B)
mysql> stop slave;
Query OK, 0 rows affected (0.05 sec)
mysql> use WLGCSZS;
Database changed
mysql> insert into student values(6,'liang');
Query OK, 1 row affected (0.07 sec)
(客戶端查詢)
mysql> use WLGCSZS;
Database changed
mysql> select * from student; //第一次查詢顯示第一臺從服務器的用戶
+------+------+
| id | name |
+------+------+
| 1 | li |
| 4 | jia |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from student; //第一次查詢顯示第二臺從服務器的用戶,說明負載均衡成功
+------+----------+
| id | name |
+------+----------+
| 1 | li |
| 5 | liang |
+------+----------+
2 rows in set (0.00 sec)
(客戶端寫入一條語句)
mysql> insert into student values(6,'asdf');
Query OK, 1 row affected (0.05 sec)
.
查詢不到剛寫入的語句,只有在主服務器可以查到因爲寫操作只有master有另外兩臺負責讀取數據
mysql> select * from student;
+------+------+
| id | name |
+------+------+
| 1 | jia |
| 4 | abcd |
+------+------+
2 rows in set (0.00 sec)
(客戶端查詢)
mysql> use WLGCSZS;
mysql> select * from student;
+------+-------+
| id | name |
+------+-------+
| 1 | li |
| 5 | jia |
| 6 | liang |
+------+-------+
4 rows in set (0.00 sec)