前言
前面已經(jīng)講到了 MySQL 8 主從復(fù)制的設(shè)置灶平,另一種 MySQL 高可用的架構(gòu)是主-主的架構(gòu)。這種結(jié)構(gòu)的幾個(gè)數(shù)據(jù)庫(kù)都是主數(shù)據(jù)庫(kù)箍土,每個(gè)數(shù)據(jù)庫(kù)數(shù)據(jù)的更新都會(huì)同步到其他的數(shù)據(jù)庫(kù)中逢享。所以每個(gè)數(shù)據(jù)庫(kù)都會(huì)保持最新的數(shù)據(jù),而且每個(gè)數(shù)據(jù)庫(kù)也能同時(shí)做讀寫(xiě)操作涮帘。其中雙主結(jié)構(gòu)的是比較簡(jiǎn)單的拼苍。 本文以《MySQL 8 主從復(fù)制設(shè)置》 一文中的設(shè)置為基礎(chǔ),完成雙主架構(gòu)的 MySQL 的設(shè)置调缨。
原理概述
在《MySQL 8 主從復(fù)制設(shè)置》 一文中疮鲫,我們已經(jīng)演示了設(shè)置一主一從架構(gòu)的 MySQL 集群。我們也知道了從庫(kù)和主庫(kù)保持同步是從庫(kù)通過(guò)監(jiān)控主庫(kù)的 bin 日志獲得主庫(kù)上的數(shù)據(jù)的變化弦叶,并且做出同步的改變而完成的俊犯。主從復(fù)制的邏輯架構(gòu)如圖所示
雙主的結(jié)構(gòu)就是兩個(gè)庫(kù)都分別互為主-從,互相監(jiān)控對(duì)方數(shù)據(jù)的變化伤哺,并且做出同樣響應(yīng)的改變燕侠,從而保證兩個(gè)數(shù)據(jù)庫(kù)的變化都會(huì)同步到對(duì)方的數(shù)據(jù)庫(kù)中。他的結(jié)構(gòu)如下圖所示
這里可以看到立莉,和主從結(jié)構(gòu)相比绢彤,雙主結(jié)構(gòu)多了一條從數(shù)據(jù)庫(kù) B 到數(shù)據(jù)庫(kù) A 的連接線,這條連接線是 A 庫(kù)用來(lái)監(jiān)控?cái)?shù)據(jù) B 的 bin 日志的變化蜓耻,從而保證 A 庫(kù)和 B 庫(kù)中的變化的數(shù)據(jù)保持一致茫舶。
大家可能會(huì)有一個(gè)疑問(wèn),在雙主結(jié)構(gòu)中刹淌,如果 A 庫(kù)數(shù)據(jù)變化了饶氏,同步到 B 庫(kù)后,B 庫(kù)數(shù)據(jù)也發(fā)生了變化有勾,會(huì)在 B 庫(kù)也會(huì)產(chǎn)生 bin 日志記錄疹启,那么 A 庫(kù)監(jiān)控到了后,又會(huì)根據(jù)邏輯蔼卡,改變 A 庫(kù)數(shù)據(jù)喊崖,產(chǎn)生新的 A 庫(kù) bin 日志,這樣導(dǎo)致了兩個(gè)庫(kù)的死循環(huán)雇逞。
實(shí)際上并不會(huì)荤懂。如果查看 bin 日志的內(nèi)容,我們會(huì)發(fā)現(xiàn)喝峦,bin 日志每一條都記錄了這條日志產(chǎn)生的 server id 势誊,系統(tǒng)監(jiān)控到對(duì)方數(shù)據(jù)變化的 bin 日志的時(shí)候呜达,如果發(fā)現(xiàn)這條日志的原始的 servier id 是自己谣蠢,就不會(huì)做任何操作。所以在這種 MySQL 集群中,必須設(shè)置 server id 眉踱,并且不能相同挤忙。這個(gè)在《MySQL 8 主從復(fù)制設(shè)置》 一文中的配置信息中也有所體現(xiàn)。
安裝準(zhǔn)備
按照 《MySQL 8 二進(jìn)制方式安裝到 CentOS 7 中》 一文中的步驟在兩臺(tái)服務(wù)器 10.110.2.71 和 10.110.2.72 上分別安裝 MySQL 8 谈喳。兩個(gè)機(jī)器 MysQL 的配置粉筆如下所示
[mysqld]
server-id=71
port=38965
character-set-server=utf8mb4
default-time_zone='+8:00'
lower_case_table_names=1
max_connections=3000
max_connect_errors=100000
default_authentication_plugin=mysql_native_password
datadir=/data/mysql/data
socket=/data/mysql/mysql.sock
log-error=/data/mysql/logs/mysqld.log
pid-file=/data/mysql/mysqld.pid
binlog_format=ROW
log_bin=/data/mysql/data/mysql-bin-71.log
expire_logs_days=30
long_query_time=1
slow_query_log = 1
slow_query_log_file=/data/mysql/logs/slow.log
[client]
port=38965
default-character-set=utf8mb4
socket=/data/mysql/mysql.sock
[mysql]
no-auto-rehash
default-character-set=utf8mb4
[mysqld]
server-id=72
port=38965
character-set-server=utf8mb4
default-time_zone='+8:00'
lower_case_table_names=1
max_connections=3000
max_connect_errors=100000
default_authentication_plugin=mysql_native_password
datadir=/data/mysql/data
socket=/data/mysql/mysql.sock
log-error=/data/mysql/logs/mysqld.log
pid-file=/data/mysql/mysqld.pid
binlog_format=ROW
log_bin=/data/mysql/data/mysql-bin-72.log
expire_logs_days=30
long_query_time=1
slow_query_log = 1
slow_query_log_file=/data/mysql/logs/slow.log
[client]
port=38965
default-character-set=utf8mb4
socket=/data/mysql/mysql.sock
[mysql]
no-auto-rehash
default-character-set=utf8mb4
以上配置中需要注意的有兩點(diǎn)册烈,第一點(diǎn)是兩個(gè) MySQL 的 server-id 值不能相同,第二個(gè)是我們?cè)黾恿讼旅娴呐渲?/p>
binlog_format=ROW
log_bin=/data/mysql/data/mysql-bin-71.log
expire_logs_days=30
這個(gè)配置第一行指定了 MySQL bin 日志的格式是原始格式婿禽。這個(gè)是 MySQL 8 的默認(rèn)值赏僧,但是以前的版本不是,所有這里明確指出了扭倾。配置的第三行指定了 bin 日志過(guò)期的時(shí)間是 30 天淀零,也就是只保存最近 30 天的 bin 日志。第二行不是很有必要膛壹,只是為了自定義一下 bin 日志文件的前綴驾中。
然后分別啟動(dòng)兩個(gè)數(shù)據(jù)庫(kù),按照提示修改數(shù)據(jù)庫(kù)初始的 root 用戶密碼模聋,就可以使用這兩個(gè)單機(jī)的 MySQL 了肩民。
雙主配置
創(chuàng)建復(fù)制用戶
上面的步驟完成后,我們得到了兩個(gè)單獨(dú)的 MySQL链方,他們之間還沒(méi)有聯(lián)系持痰,現(xiàn)在我們要將這兩臺(tái)服務(wù)器配置成為 雙主結(jié)構(gòu)。
首先用 root 用戶連接上兩個(gè) MySQL 的控制臺(tái)侄柔,然后在兩臺(tái)機(jī)器上分別設(shè)置一個(gè)用來(lái)復(fù)制數(shù)據(jù)的用戶共啃。
mysql>create user 'repl'@'10.110.2.%' identified by 'reple_password';
mysql>grant replication slave on *.* to 'repl'@'10.110.2.%';
mysql>
這里第一個(gè)語(yǔ)句創(chuàng)建一個(gè)密碼為 'reple_password' 在網(wǎng)段 10.110.2.% 上能夠訪問(wèn)的數(shù)據(jù)庫(kù)用戶 repl 。第二句給這個(gè)用戶授予到主從復(fù)制的權(quán)限
10.110.2.72 從庫(kù)設(shè)置
首先在 10.110.2.71 上查看當(dāng)前 bin 日志狀態(tài)暂题。
mysql> show master status;
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| mysql-bin-71.000002 | 962 | | | |
+---------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
在 10.110.2.72 上設(shè)置從庫(kù)移剪,并啟動(dòng)主從復(fù)制
mysql> change master to
-> master_host='10.110.2.71',
-> master_port=38965,
-> master_user='repl',
-> master_password='replpassword',
-> master_log_file='mysql-bin-71.000002',
-> master_log_pos=962 ;
mysql>start slave;
mysql>
在 10.110.2.72 上查看從庫(kù)狀態(tài)
ysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.110.2.71
Master_User: repl
Master_Port: 38965
Connect_Retry: 60
Master_Log_File: mysql-bin-71.000002
Read_Master_Log_Pos: 962
Relay_Log_File: localhost-relay-bin.000001
Relay_Log_Pos: 319
Relay_Master_Log_File: mysql-bin-71.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 4035
Relay_Log_Space: 1431
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 71
Master_UUID: 2980729e-23c6-11e9-aec6-005056881ba9
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
1 row in set (0.00 sec)
ERROR:
No query specified
這說(shuō)明10.110.2.72 作為從庫(kù)已經(jīng)準(zhǔn)備好接受主庫(kù) 10.110.2.71 的變化并同步數(shù)據(jù)了。
10.110.2.71 從庫(kù)設(shè)置
首先在 10.110.2.72 上查看當(dāng)前 bin 日志狀態(tài)薪者。
mysql> show master status;
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| mysql-bin-72.000002 | 962 | | | |
+---------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
在 10.110.2.71 上設(shè)置從庫(kù)纵苛,并啟動(dòng)主從復(fù)制
mysql> change master to
-> master_host='10.110.2.72',
-> master_port=38965,
-> master_user='repl',
-> master_password='replpassword',
-> master_log_file='mysql-bin-72.000002',
-> master_log_pos=962 ;
mysql>start slave;
mysql>
在 10.110.2.71 上查看從庫(kù)狀態(tài)
ysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.110.2.72
Master_User: repl
Master_Port: 38965
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 962
Relay_Log_File: localhost-relay-bin.000001
Relay_Log_Pos: 319
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 4035
Relay_Log_Space: 1431
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 71
Master_UUID: 2980729e-23c6-11e9-aec6-005056881ba9
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
1 row in set (0.00 sec)
ERROR:
No query specified
這說(shuō)明10.110.2.71 作為從庫(kù)已經(jīng)準(zhǔn)備好接受主庫(kù) 10.110.2.72 的變化并同步數(shù)據(jù)了。
驗(yàn)證
72 同步 71 驗(yàn)證
首先言津,在 71 上做如下的操作
mysql> create database test1;
mysql> create user 'test1'@'%' identified by 'test1_paswd';
mysql> grant all privileges on test1.* to 'test1'@'%';
mysql> crea table test (id bigint not null,name varchar(16),PRIMARY KEY(id));
mysql>user test1;
mysql>insert into test values(1,'name1');
mysql>insert into test values(2,'name2');
mysql>select * from test;
+----+---------+
| id | name |
+----+---------+
| 1 | name1 |
| 2 | name2 |
+----+------+
2 rows in set (0.00 sec)
mysql>
然后在 10.110.2.72 上執(zhí)行如下操作
mysql>user test1;
mysql>select * from test;
+----+---------+
| id | name |
+----+---------+
| 1 | name1 |
| 2 | name2 |
+----+------+
2 rows in set (0.00 sec)
mysql> select user,host from mysql.user;
+------------------+-------------+
| user | host |
+------------------+-------------+
| test1 | % |
| repl | 10.110.2.% |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-------------+
6 rows in set (0.00 sec)
可以看到在 10.110.2.71 服務(wù)器上創(chuàng)建用戶攻人,數(shù)據(jù)庫(kù),表悬槽,數(shù)據(jù)怀吻,以及用戶權(quán)限都被同步到 72 數(shù)據(jù)庫(kù)上了。
71 同步 72 驗(yàn)證
首先在 10.110.2.72 上執(zhí)行如下操作
mysql>user test1;
mysql>insert into test values(3,'name1');
mysql>insert into test values(4,'name2');
mysql>select * from test;
+----+---------+
| id | name |
+----+---------+
| 1 | name1 |
| 2 | name2 |
| 3 | name3 |
| 4 | name4 |
+----+------+
4 rows in set (0.00 sec)
mysql> create database test2;
mysql> create user 'test2'@'%' identified by 'test2_paswd';
mysql> grant all privileges on test2.* to 'test2'@'%';
mysql> use test2';
mysql> crea table test (id bigint not null,name varchar(16), sex int,PRIMARY KEY(id));
mysql>insert into test values(1,'name1',0);
mysql>insert into test values(2,'name2',1);
mysql>select * from test;
+----+-------+------+
| id | name | sex |
+----+-------+------+
| 1 | name1 | 0 |
| 2 | name2 | 1 |
+----+-------+------+
2 rows in set (0.00 sec)
然后在 10.110.2.71 上執(zhí)行如下操作
mysql>user test1;
mysql>select * from test;
+----+---------+
| id | name |
+----+---------+
| 1 | name1 |
| 2 | name2 |
| 3 | name3 |
| 4 | name4 |
+----+------+
4 rows in set (0.00 sec)
mysql> select user,host from mysql.user;
+------------------+-------------+
| user | host |
+------------------+-------------+
| test1 | % |
| test2 | % |
| repl | 10.110.2.% |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-------------+
7 rows in set (0.00 sec)
mysql>user test2;
mysql>select * from test;
+----+-------+------+
| id | name | sex |
+----+-------+------+
| 1 | name1 | 0 |
| 2 | name2 | 1 |
+----+-------+------+
2 rows in set (0.00 sec)
從這里可以看到初婆,10.110.2.72 數(shù)據(jù)庫(kù)上指定的增加用戶蓬坡、用戶賦權(quán)猿棉、創(chuàng)建數(shù)據(jù)庫(kù),創(chuàng)建表屑咳,增加數(shù)據(jù)等操作都同步到 71 數(shù)據(jù)庫(kù)上了萨赁。
后記
上面詳細(xì)的說(shuō)明了雙主結(jié)構(gòu) MySQL 集群的設(shè)置,這種結(jié)構(gòu)不需要區(qū)分主從兆龙,客戶端可以隨便連接任何一個(gè)數(shù)據(jù)進(jìn)行操作杖爽。唯一的一個(gè)問(wèn)題是在一個(gè)數(shù)據(jù)庫(kù)上插入了一條數(shù)據(jù),會(huì)有一個(gè)較小的延遲同步到另一個(gè)數(shù)據(jù)庫(kù)上紫皇,這個(gè)時(shí)候如果查詢落在第二個(gè)數(shù)據(jù)庫(kù)上慰安,則會(huì)找不到要查詢的數(shù)據(jù)。這個(gè)在插入數(shù)據(jù)后聪铺,保證這次操作時(shí)泻帮,查詢?cè)摂?shù)據(jù)的時(shí)候,數(shù)據(jù)查詢的請(qǐng)求發(fā)送給插入時(shí)的數(shù)據(jù)庫(kù)即可计寇。
同樣的锣杂,我們可以看到如果有多個(gè)數(shù)據(jù)庫(kù),將多個(gè)數(shù)據(jù)庫(kù)的主從關(guān)系設(shè)置成為一個(gè)首尾相連的環(huán)番宁,那么就可以設(shè)置成為多主結(jié)構(gòu)的 MySQL 集群元莫。當(dāng)然了,這種多主結(jié)構(gòu)隨著成員的增多蝶押,復(fù)制的鏈條變長(zhǎng)踱蠢,同時(shí)其中一個(gè)節(jié)點(diǎn)宕機(jī),會(huì)導(dǎo)致整個(gè)集群數(shù)據(jù)的問(wèn)題棋电。對(duì)運(yùn)維的壓力是比較大的茎截。這個(gè)不在這里討論了。