6. MySQL 主從架構(gòu)

7 MySQL 集群Cluster

7.1 主從復(fù)制

主從架構(gòu)屬于負(fù)載均衡集群
可以實(shí)現(xiàn)讀寫(xiě)分離, 將讀操作調(diào)度到多個(gè)節(jié)點(diǎn)
而負(fù)責(zé)寫(xiě)操作的主服務(wù)器是存在單點(diǎn)失敗的
高可用集群是為了解決單點(diǎn)失敗問(wèn)題

7.1.1 主從復(fù)制原理

image.png

主從復(fù)制過(guò)程:

  1. 主節(jié)點(diǎn)收到用戶請(qǐng)求, 進(jìn)行數(shù)據(jù)更新
  2. 主節(jié)點(diǎn)將更新的操作寫(xiě)入二進(jìn)制日志, bin log
  3. 主節(jié)點(diǎn)開(kāi)啟專門的dump線程, 負(fù)責(zé)把新生成的二進(jìn)制日志, 發(fā)給從節(jié)點(diǎn)
  4. 從節(jié)點(diǎn)的io thread負(fù)責(zé)接收主節(jié)點(diǎn)dump線程發(fā)過(guò)來(lái)的數(shù)據(jù)
  5. 接收過(guò)來(lái)的數(shù)據(jù)寫(xiě)入中繼日志relay log
  6. SQL thread把中繼日志中的新的內(nèi)容, 寫(xiě)入從節(jié)點(diǎn)數(shù)據(jù)庫(kù), 實(shí)現(xiàn)主從數(shù)據(jù)的同步

主從復(fù)制相關(guān)線程:

主節(jié)點(diǎn):

  • dump thread: 為每個(gè)Slave的IO thread啟動(dòng)一個(gè)dump線程, 用于向其發(fā)送二進(jìn)制日志事件

從節(jié)點(diǎn):

  • IO thread: 向master請(qǐng)求二進(jìn)制日志事件, 并保存于中繼日志中, relay log
  • SQL thread: 從中繼日志中讀取日志事件, 在本地完成重放
  • dump線程與io thread通信走的是mysql協(xié)議, 主節(jié)點(diǎn)開(kāi)啟3306, 從節(jié)點(diǎn)會(huì)打開(kāi)隨機(jī)端口接收數(shù)據(jù)

7.1.2 主從復(fù)制相關(guān)配置

主從復(fù)制配置要求:

  • 主從節(jié)點(diǎn)分別啟用二進(jìn)制日志

      log-bin
    

主節(jié)點(diǎn)必須啟用二進(jìn)制, 因?yàn)橐涗浫罩? 然后同步給從節(jié)點(diǎn)
從節(jié)點(diǎn)看情況啟用, 不過(guò)一般都是要直接啟用的, 因?yàn)橐坏┲鞴?jié)點(diǎn)故障, 從節(jié)點(diǎn)需要提升為主節(jié)點(diǎn)

此外, 如果需要利用從節(jié)點(diǎn)進(jìn)行備份和還原, 那么從節(jié)點(diǎn)必須啟用二進(jìn)制, 并且添加log-slave-updates選項(xiàng), 把從主節(jié)點(diǎn)接收的二進(jìn)制寫(xiě)到本地二進(jìn)制日志里

  • 為當(dāng)前所有節(jié)點(diǎn)設(shè)置一個(gè)全局唯一的server id號(hào), 在二進(jìn)制日志中用來(lái)表示當(dāng)前的日志事件是來(lái)自哪個(gè)主機(jī)的, 以免混淆不同的日志來(lái)源, 因此, 要給每個(gè)節(jié)點(diǎn), 配置一個(gè)與眾不同的server id

      server-id=#  默認(rèn)為1, 只需要確保不同節(jié)點(diǎn), id不同即可, 一般用服務(wù)器ip的最后一位即可
    
  • 主節(jié)點(diǎn)給每個(gè)從節(jié)點(diǎn)創(chuàng)建一個(gè)具有復(fù)制權(quán)限的賬號(hào), 專門用于從節(jié)點(diǎn)從主節(jié)點(diǎn)復(fù)制二進(jìn)制日志

      grant replication slave on *.* to 'repluser'@'HOST' identified by 'replpass';
    
  • 從節(jié)點(diǎn)啟用中繼日志

      [mysqld]
      server_id=# #為當(dāng)前節(jié)點(diǎn)設(shè)置一個(gè)全局唯一的ID號(hào), 推薦用ip地址最后一位, 可以保證不沖突
      log-bin=/data/mysql/mysql-bin  #從節(jié)點(diǎn)也要啟用二進(jìn)制日志, 首先, 從節(jié)點(diǎn)以后有提升為主節(jié)點(diǎn)的可能, 同時(shí), 數(shù)據(jù)備份時(shí), 也可以利用從節(jié)點(diǎn)備份, 減少主節(jié)點(diǎn)壓力
      read_only=ON #設(shè)置數(shù)據(jù)庫(kù)只讀, 針對(duì)supper user無(wú)效, 非必須選項(xiàng). 用來(lái)防止普通用戶連接到從數(shù)據(jù)庫(kù)進(jìn)行修改拌牲, 但是從節(jié)點(diǎn)的更新是不會(huì)復(fù)制到主節(jié)點(diǎn)的,就會(huì)造成數(shù)據(jù)不一致. 不過(guò)蚁滋, 該選項(xiàng)對(duì)root無(wú)效. 
      relay_log=relay-log #relay log的文件路徑, 默認(rèn)值HOSTNAME-relay-bin, 非必須選項(xiàng)
      relay_log_index=relay-log.index #默認(rèn)值HOSTNAME-relay-bin.index, 非必須選項(xiàng)
    
  • 從節(jié)點(diǎn)命令

      change master to master_host='MASETHOSTIP', #在從節(jié)點(diǎn)指定主節(jié)點(diǎn)的ip
      master_user='repluser', # 從節(jié)點(diǎn)復(fù)制用戶
      master_password='replpass', # 從節(jié)點(diǎn)復(fù)制密碼
      master_log_file='mysql-bin.xxxxxx',  #指明從主節(jié)點(diǎn)的哪個(gè)二進(jìn)制日志開(kāi)始復(fù)制
      masterlog_pos=#; #指明二進(jìn)制日志文件的位置
    
  • 從節(jié)點(diǎn)開(kāi)啟io thread和sql thread線程

      start slave; #默認(rèn)是不開(kāi)啟的
    
  • 如何確定從主節(jié)點(diǎn)哪個(gè)日志哪個(gè)位置開(kāi)始復(fù)制

      show master logs;
    

7.1.3 主從復(fù)制案例-1

從0搭建主從, 主從服務(wù)器都是新的服務(wù)器, 之前沒(méi)有任何數(shù)據(jù)

環(huán)境:

圖片.png

CentOS 7
MySQL 5.7.31
master: 10.0.0.237
slave: 10.0.0.227

配置過(guò)程:

  1. 修改主節(jié)點(diǎn)配置文件
[mysqld]
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
log-bin=/data/mysql/mysql-bin                                                                                                                       
server-id=237
[client]
socket=/data/mysql/mysql.sock
  1. 創(chuàng)建二進(jìn)制日志存放路徑, 和權(quán)限
mkdir /data/mysql -pv
[root@master ~]#chown -R mysql.mysql /data/mysql
service mysqld restart
  1. 記錄當(dāng)前二進(jìn)制日志的位置, 此步驟要在創(chuàng)建復(fù)制賬號(hào)之前記錄, 因?yàn)閯?chuàng)建賬號(hào)后, 二進(jìn)制會(huì)被修改. 先記錄二進(jìn)制位置, 再創(chuàng)建賬號(hào), 這樣創(chuàng)建的復(fù)制賬號(hào)信息也會(huì)被記錄到二進(jìn)制日志里, 一同復(fù)制給從節(jié)點(diǎn), 以防之后主機(jī)點(diǎn)down了, 將從節(jié)點(diǎn)提升為主節(jié)點(diǎn)時(shí)還要手動(dòng)創(chuàng)建賬號(hào)
[14:07:14 root@master ~]#ll /data/mysql/mysql-bin*
-rw-r----- 1 mysql mysql 154 Nov 25 14:07 /data/mysql/mysql-bin.000001
-rw-r----- 1 mysql mysql  29 Nov 25 14:07 /data/mysql/mysql-bin.index
mysql> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       154 | #從00001文件的154開(kāi)始后, 都是需要復(fù)制的信息
+------------------+-----------+
1 row in set (0.00 sec)
  1. 主節(jié)點(diǎn)創(chuàng)建復(fù)制授權(quán)賬號(hào)
#授權(quán)賬號(hào)的host信息要寫(xiě)成一個(gè)網(wǎng)段, 因?yàn)? 從節(jié)點(diǎn)有可能有多個(gè), 不能只寫(xiě)單個(gè)ip
mysql> grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by '000000';
Query OK, 0 rows affected, 1 warning (0.01 sec)

  1. 從節(jié)點(diǎn)配置文件修改
[mysqld]
server-id=227     
log-bin=/data/mysql/mysql-bin            
read-only=ON                                                                                                                                                         
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
chown -R mysql.mysql /data/mysql
service mysqld restart
  1. 從節(jié)點(diǎn)配置復(fù)制命令
mysql> CHANGE MASTER TO
    ->   MASTER_HOST='10.0.0.237',
    ->   MASTER_USER='repluser',
    ->   MASTER_PASSWORD='000000',
    ->   MASTER_PORT=3306,
    ->   MASTER_LOG_FILE='mysql-bin.000001',
    ->   MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
  1. 從節(jié)點(diǎn)執(zhí)行了change master to后會(huì)在MySQL數(shù)據(jù)目錄生成新的文件
-rw-r----- 1 mysql mysql      154 Nov 25 14:23 slave-relay-bin.000001 #從節(jié)點(diǎn)中繼日志
-rw-r----- 1 mysql mysql       25 Nov 25 14:23 slave-relay-bin.index #從節(jié)點(diǎn)中繼日志文件信息
-rw-r----- 1 mysql mysql       57 Nov 25 14:23 relay-log.info #中繼日志信息, 存放中繼日志和主節(jié)點(diǎn)二進(jìn)制日志的對(duì)應(yīng)關(guān)系
-rw-r----- 1 mysql mysql       90 Nov 25 14:23 master.info #復(fù)制信息, 存放chang master to命令的參數(shù)信息,
[03:38:41 root@slave ~]#cat /data/mysql/master.info 
25
mysql-bin.000001
154
10.0.0.237
repluser
000000
3306
60
0





0
30.000

0

86400


0

[03:39:44 root@slave ~]#cat /data/mysql/relay-log.info 
7
./slave-relay-bin.000001 # 中繼日志的POS=4對(duì)應(yīng)主節(jié)點(diǎn)二進(jìn)制日志的POS=154
4
mysql-bin.000001 
154
0
0
1

  1. 觀察從節(jié)點(diǎn)的信息
#執(zhí)行change master to命令后, 可以在從節(jié)點(diǎn)觀察狀態(tài), 尤其要注意Slave_IO_Running: No
和Slave_SQL_Running: No, 兩個(gè)值, 如果出現(xiàn)NO, 就說(shuō)明主從復(fù)制出現(xiàn)問(wèn)題, 該值需要做監(jiān)控, 這里為NO, 是因?yàn)闀簳r(shí)還沒(méi)有開(kāi)啟兩個(gè)線程
mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 10.0.0.237
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 154
               Relay_Log_File: slave-relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: No
            Slave_SQL_Running: No
...
        Seconds_Behind_Master: NULL #這里表示了主從復(fù)制的延遲時(shí)間, 也需要進(jìn)行監(jiān)控

  1. 從節(jié)點(diǎn)啟動(dòng)SQL和IO線程
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
  1. 開(kāi)啟兩個(gè)線程后, 會(huì)在主從節(jié)點(diǎn)生成用來(lái)進(jìn)行復(fù)制同步的tcp連接
#主節(jié)點(diǎn)
[03:38:35 root@master ~]#ss -nt
State      Recv-Q Send-Q      Local Address:Port                     Peer Address:Port                           
ESTAB      0      0         [::ffff:10.0.0.237]:3306                  [::ffff:10.0.0.227]:50336  
#從節(jié)點(diǎn)
[03:40:13 root@slave ~]#ss -nt
State      Recv-Q Send-Q      Local Address:Port                     Peer Address:Port                    
ESTAB      0      0              10.0.0.227:50336                      10.0.0.237:3306               
  1. 開(kāi)啟后, 主節(jié)點(diǎn)會(huì)生成dump線程, 從節(jié)點(diǎn)生成sql和io線程
mysql> show processlist;
+----+----------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+
| Id | User     | Host             | db   | Command     | Time | State                                                         | Info             |
+----+----------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+
|  4 | repluser | 10.0.0.227:43156 | NULL | Binlog Dump(主節(jié)點(diǎn)dump線程) |   34 | Master has sent all binlog to slave; waiting for more updates | NULL             |
|  5 | root     | localhost        | NULL | Query       |    0 | starting                                                      | show processlist |
+----+----------+------------------+------+-------------+------+---------------------------------------------------------------+------------------+
2 rows in set (0.00 sec)

mysql> show processlist;
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------+
| Id | User        | Host      | db   | Command | Time | State                                                  | Info                                                                                                 |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------+
|  2 | root        | localhost | NULL | Query   |    0 | starting                                               | show processlist                                                                                     |
|  3 | system user |           | NULL | Connect(從節(jié)點(diǎn)io線程) |   58 | Waiting for master to send event                       | NULL                                                                                                 |
|  4 | system user |           | NULL | Connect(從節(jié)點(diǎn)sql線程) |  716 | Slave has read all relay log; waiting for more updates | GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'10.0.0.%' IDENTIFIED WITH 'mysql_native_password' AS ' |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.237
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 448
               Relay_Log_File: slave-relay-bin.000002
                Relay_Log_Pos: 614
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

測(cè)試同步是否成功:

  1. 檢查從節(jié)點(diǎn)是否有repluser賬號(hào)
mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| repluser      | 10.0.0.%  |
  1. 觀察slave狀態(tài)
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
          Exec_Master_Log_Pos: 448 #主節(jié)點(diǎn)最新的二進(jìn)制位置, 目前和主節(jié)點(diǎn)的show master logs值是對(duì)應(yīng)的
        Seconds_Behind_Master: 0 #主從復(fù)制延遲為0
  1. 主節(jié)點(diǎn)導(dǎo)入hellodb數(shù)據(jù), 在從節(jié)點(diǎn)測(cè)試
[14:43:27 root@master ~]#mysql < hellodb_innodb.sql
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            | #數(shù)據(jù)庫(kù)成功復(fù)制
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

7.1.4 主從復(fù)制案例-2

單獨(dú)添加新的從節(jié)點(diǎn)

部署思路:

  1. 先在主節(jié)點(diǎn)做一次完全備份, 把現(xiàn)有數(shù)據(jù)都導(dǎo)出來(lái)
  2. 找到主節(jié)點(diǎn)完全備份時(shí)的二進(jìn)制位置
  3. 從節(jié)點(diǎn)導(dǎo)入完全備份數(shù)據(jù)
  4. 從節(jié)點(diǎn)開(kāi)啟二進(jìn)制, 位置指向主節(jié)點(diǎn)備份文件中的change master to位置

環(huán)境:

主節(jié)點(diǎn)還是10.0.0.237
新的從節(jié)點(diǎn)10.0.0.217

步驟:

  1. 主節(jié)點(diǎn)做完全備份
[14:43:38 root@master ~]#mysqldump -A -F --single-transaction --master-data=1 > /data/allbackup_`date +%F_%T`.sql
[03:49:10 root@master ~]#ll /data/allbackup_2021-06-16_03\:49\:05.sql 
-rw-r--r-- 1 root root 869712 Jun 16 03:49 /data/allbackup_2021-06-16_03:49:05.sql
  1. 將完全備份拷貝到從節(jié)點(diǎn)

[13:53:56 root@mysql-master ~]#scp /data/allbackup_2021-06-14_13\:52\:10.sql 10.0.0.217:/root

  1. 新的從節(jié)點(diǎn)配置MySQL
[mysqld]
server-id=217                                                                                                                                        
log-bin=/data/mysql/mysql-bin 

datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
service mysqld restart
  1. 開(kāi)啟從節(jié)點(diǎn)復(fù)制
#可以直接從完全備份文件中獲取主節(jié)點(diǎn)二進(jìn)制文件和記錄位置, 直接把change master to命令寫(xiě)到完全備份文件里, 統(tǒng)一導(dǎo)入到從節(jié)點(diǎn)
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;
# 因?yàn)樵趍aster節(jié)點(diǎn)執(zhí)行了備份浊猾,所以會(huì)刷新一次日志顿痪, 生成新的mysql-bin.000002
 CHANGE MASTER TO
 MASTER_HOST='10.0.0.237',
 MASTER_USER='repluser',
 MASTER_PASSWORD='000000',
 MASTER_PORT=3306,
 MASTER_LOG_FILE='mysql-bin.000002',
 MASTER_LOG_POS=154;
mysql> set sql_log_bin=off;
mysql> source /root/allbackup_2020-11-25_14\:52\:27.sql
mysql> set sql_log_bin=on;
  1. 導(dǎo)入完全備份文件后, 查看從節(jié)點(diǎn)狀態(tài)
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 10.0.0.237
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 154
               Relay_Log_File: slave-2-relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: mysql-bin.000002
             Slave_IO_Running: No #此時(shí)線程還是關(guān)閉的, 不過(guò)沒(méi)關(guān)系, 此時(shí)即使主節(jié)點(diǎn)還在寫(xiě)數(shù)據(jù), 從節(jié)點(diǎn)也是從change mater to定義好的主節(jié)點(diǎn)二進(jìn)制文件和位置開(kāi)始同步
            Slave_SQL_Running: No
  1. 主節(jié)點(diǎn)修改數(shù)據(jù)
mysql> use hellodb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> insert teachers (name,age,gender) value('zhao',18,'M');
Query OK, 1 row affected (0.00 sec)

mysql> insert teachers (name,age,gender) value('qian',18,'M');
Query OK, 1 row affected (0.01 sec)
  1. 驗(yàn)證從節(jié)點(diǎn)開(kāi)始線程后, 修改的數(shù)據(jù)能正常同步
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from hellodb.teachers;
+-----+---------------+-----+--------+
| TID | Name          | Age | Gender |
+-----+---------------+-----+--------+
|   1 | Song Jiang    |  45 | M      |
|   2 | Zhang Sanfeng |  94 | M      |
|   3 | Miejue Shitai |  77 | F      |
|   4 | Lin Chaoying  |  93 | F      |
|   5 | zhao          |  18 | M      | #主節(jié)點(diǎn)在從節(jié)點(diǎn)開(kāi)始線程前添加的數(shù)據(jù)也能正常復(fù)制
|   6 | qian          |  18 | M      |
+-----+---------------+-----+--------+
  1. 觀察主從節(jié)點(diǎn)各種的線程
#由于有兩個(gè)從節(jié)點(diǎn), 因此主節(jié)點(diǎn)會(huì)為每個(gè)從節(jié)點(diǎn)開(kāi)啟單獨(dú)的dump線程
mysql> show processlist;
+----+----------+-----------------+---------+-------------+------+---------------------------------------------------------------+------------------+
| Id | User     | Host            | db      | Command     | Time | State                                                         | Info             |
+----+----------+-----------------+---------+-------------+------+---------------------------------------------------------------+------------------+
|  3 | repluser | 10.0.0.52:33918 | NULL    | Binlog Dump | 8026 | Master has sent all binlog to slave; waiting for more updates | NULL             |
|  7 | root     | localhost       | hellodb | Query       |    0 | starting                                                      | show processlist |
|  8 | repluser | 10.0.0.53:57096 | NULL    | Binlog Dump |  147 | Master has sent all binlog to slave; waiting for more updates | NULL             |
+----+----------+-----------------+---------+-------------+------+---------------------------------------------------------------+------------------+
3 rows in set (0.00 sec)
#新添加的從節(jié)點(diǎn)也正常開(kāi)啟了復(fù)制線程
mysql> show processlist;
+----+-------------+-----------+--------------------+---------+------+--------------------------------------------------------+------------------+
| Id | User        | Host      | db                 | Command | Time | State                                                  | Info             |
+----+-------------+-----------+--------------------+---------+------+--------------------------------------------------------+------------------+
|  2 | root        | localhost | #mysql50#mysql-bin | Query   |    0 | starting                                               | show processlist |
|  3 | system user |           | NULL               | Connect |  197 | Waiting for master to send event                       | NULL             |
|  4 | system user |           | NULL               | Connect |  277 | Slave has read all relay log; waiting for more updates | NULL             |
+----+-------------+-----------+--------------------+---------+------+--------------------------------------------------------+------------------+
3 rows in set (0.00 sec)

7.1.5 主從復(fù)制案例-3

主節(jié)點(diǎn)宕機(jī), 如何提升從節(jié)點(diǎn)為主節(jié)點(diǎn)

  1. 確定哪個(gè)從節(jié)點(diǎn)對(duì)應(yīng)的主節(jié)點(diǎn)二進(jìn)制位置是更新的, 提升數(shù)據(jù)較新的那個(gè)從節(jié)點(diǎn)為主節(jié)點(diǎn). 因?yàn)閺墓?jié)點(diǎn)同步到的主節(jié)點(diǎn)的二進(jìn)制位置, 就決定了數(shù)據(jù)的新舊
方法1. 從節(jié)點(diǎn)使用show slave status;查看
方法2. 從節(jié)點(diǎn)查看relay-log.info
方法1:show slave status, 查看Master_Log_File和Read_Log_Pos
  • 10.0.0.227 slave-1
圖片.png
  • 10.0.0.217 slave-2


    圖片.png

方法2: 從節(jié)點(diǎn)查看relay-log.info文件

10.0.0.227 slave-1

[04:08:25 root@slave ~]#cat /data/mysql/relay-log.info 
7
./slave-relay-bin.000004
923
mysql-bin.000002
710
0
0
1


1

10.0.0.217 slave-2

[04:08:47 root@slave-2 ~]#cat /data/mysql/relay-log.info 
7
./slave-2-relay-bin.000002
876
mysql-bin.000002
710
0
0
1


  1. 實(shí)際生產(chǎn)中, 可以借助軟件, 實(shí)現(xiàn)對(duì)從節(jié)點(diǎn)的監(jiān)控溜宽,自動(dòng)監(jiān)控哪個(gè)從節(jié)點(diǎn)的日志更新碰凶, 然后提升為主節(jié)點(diǎn)

案例: 假設(shè)10.0.0.227-slave-1的從節(jié)點(diǎn)的二進(jìn)制是更新的故俐,關(guān)閉主節(jié)點(diǎn)服務(wù)器分瘾, 提升slave-1為主節(jié)點(diǎn)

  1. 先關(guān)閉主節(jié)點(diǎn)服務(wù)器胎围, 或者停止mysql服務(wù)也可, 之后從節(jié)點(diǎn)會(huì)立即報(bào)錯(cuò)
                Last_IO_Error: error reconnecting to master 'repluser@10.0.0.237:3306' - retry-time: 60  retries: 2
  1. 提升10.0.0.227-slave-1為主節(jié)點(diǎn)德召, 修改配置文件白魂, 關(guān)閉read-only配置
需要先記錄新的主節(jié)點(diǎn)復(fù)制到了舊的主節(jié)點(diǎn)的那個(gè)二進(jìn)制位置, 之后基于這個(gè)位置上岗, 從舊的主節(jié)點(diǎn)利用mysqlbinlog把未導(dǎo)入的數(shù)據(jù)同步給新的主節(jié)點(diǎn)
因?yàn)橹鞴?jié)點(diǎn)宕機(jī)時(shí), 可以還存在一部分未同步給從節(jié)點(diǎn)的數(shù)據(jù)
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Reconnecting after a failed master event read
                  Master_Host: 10.0.0.237
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 710 # 當(dāng)前復(fù)制到了主節(jié)點(diǎn)的710位置


[04:08:30 root@slave ~]#vim /etc/my.cnf

[mysqld]

server-id=227
log-bin=/data/mysql/mysql-bin
read-only=OFF      

[04:11:19 root@slave ~]#service mysqld restart

# 也可以臨時(shí)關(guān)閉read_only
set  global read_only=off;
  1. 清除舊的主節(jié)點(diǎn)信息
10.0.0.227-slave-1


mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> reset slave all;
Query OK, 0 rows affected (0.00 sec)
# reset slave all后, 從節(jié)點(diǎn)原本的master.info, relay-log.info和已經(jīng)產(chǎn)生的中繼日志文件都會(huì)被清除, 只留一個(gè)slave-relay-bin.000001, 表示開(kāi)始新的relay-log
  1. 在新的主節(jié)點(diǎn)進(jìn)行完全備份
[04:14:47 root@slave ~]#mysqldump  -A --single-transaction --master-data=1 -F > backup.sql

  1. 分析舊的master日志福荸, 根據(jù)新的master此前記錄的同步到的二進(jìn)制位置, 利用mysqlbinlog把未同步的數(shù)據(jù)導(dǎo)出來(lái)

  2. 將導(dǎo)出來(lái)的數(shù)據(jù)肴掷, 導(dǎo)入給新的master敬锐, 由于新的master是開(kāi)啟了二進(jìn)制的, 因此呆瞻, 導(dǎo)入過(guò)程會(huì)被記錄到二進(jìn)制

  3. 此時(shí)台夺, 新的master理想情況下, 就有了全部的數(shù)據(jù)痴脾, 之后修改新的master的完全備份文件颤介, 添加change master to, 然后導(dǎo)入到其他從節(jié)點(diǎn)赞赖, 這樣其他從節(jié)點(diǎn)就可以有全部的數(shù)據(jù)

  4. 首先滚朵, 其余從節(jié)點(diǎn)因?yàn)閺?fù)制的內(nèi)容少于新的master, 因此前域, 需要利用新的master的完全備份辕近, 同步到和新的master一樣的數(shù)據(jù), 然后因?yàn)樾碌膍aster會(huì)導(dǎo)入舊的master未同步的數(shù)據(jù)匿垄, 并且記錄到本地二進(jìn)制移宅,這樣在完全備份中指定二進(jìn)制位置是新的master還未導(dǎo)入舊的master未同步的數(shù)據(jù)的時(shí)刻,因此剩下的slave也會(huì)把未同步的信息同步

  5. 修改backup.sql年堆,指定新的master節(jié)點(diǎn)


 CHANGE MASTER TO
  MASTER_HOST='10.0.0.227',                                                                                                                                                                                      
  MASTER_USER='repluser',
  MASTER_PASSWORD='000000',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=154;

[04:17:12 root@slave ~]#scp backup.sql 10.0.0.217:/root

  1. 其余slave重新指定master
mysql> stop slave;
mysql> reset slave all;
mysql> set sql_log_bin=off;
mysql> source backup.sql;
mysql> set sql_log_bin=on;
mysql> start slave;

  1. 驗(yàn)證主從同步
10.0.0.227-新的master

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

10.0.0.217-slave-2



mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.0.0.227
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 154
               Relay_Log_File: slave-2-relay-bin.000002
                Relay_Log_Pos: 320
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

mysql> create database master_slave;
Query OK, 1 row affected (0.00 sec)


mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| master_slave       |
| mysql              |
| performance_schema |
| sys                |
| testdb             |
| testdb2            |
+--------------------+
8 rows in set (0.01 sec)

  1. 之后故障的master需要重新添加到主從,需要新的master做完全備份盏浇, 然后修改change master to. 然后变丧,故障主節(jié)點(diǎn)清除主從信息, 重新添加主從

主從總結(jié):

1. 主從架構(gòu)绢掰, 從節(jié)點(diǎn)即使開(kāi)啟了二進(jìn)制痒蓬,默認(rèn)也是不會(huì)記錄新的童擎, 數(shù)據(jù)從主節(jié)點(diǎn)同步到中繼日志,然后直接寫(xiě)入到數(shù)據(jù)庫(kù)
2. 如果需要利用從節(jié)點(diǎn)做備份的話攻晒, 那么可以在從節(jié)點(diǎn)做完全備份顾复, 至于二進(jìn)制日志,需要在從節(jié)點(diǎn)配置文件指定log-slave-updates, 這樣從節(jié)點(diǎn)也會(huì)記錄二進(jìn)制日志到本地鲁捏, 之后就可以直接在從節(jié)點(diǎn)做備份了
3. 主從故障芯砸, 會(huì)造成主節(jié)點(diǎn)無(wú)法寫(xiě)入數(shù)據(jù),業(yè)務(wù)中斷给梅, 讀業(yè)務(wù)暫時(shí)不受影響
4. 不過(guò)假丧, 如果是手動(dòng)切換,因?yàn)橐馁M(fèi)時(shí)間去判斷故障主節(jié)點(diǎn)還有那些數(shù)據(jù)沒(méi)有同步給提升的主節(jié)點(diǎn)动羽, 之后導(dǎo)入數(shù)據(jù)包帚, 因此會(huì)有業(yè)務(wù)中斷. 并且程序代碼也要切換主從節(jié)點(diǎn)
5. 因此,主從需要配合程序完成自動(dòng)切換运吓,否則手動(dòng)切換不建議使用

7.1.6 主從復(fù)制相關(guān)

7.1.6.1 清除從節(jié)點(diǎn)主從復(fù)制信息

當(dāng)主服務(wù)器宕機(jī), 提升了一個(gè)從節(jié)點(diǎn)為主節(jié)點(diǎn)后, 其他從節(jié)點(diǎn)需要重新指到新的主節(jié)點(diǎn), 此時(shí)需要先停止其他從節(jié)點(diǎn)的slave, 然后清除slave信息.

清除slave信息有兩個(gè)方法, 不過(guò)都要先停止slave

mysql> stop slave;
方法1:
mysql> reset slave all; #清除所有從服務(wù)器上設(shè)置的主服務(wù)器同步信息, 如: HOST, PORT, USER和PASSWORD等, 這種方式清除的更徹底
方法2:
mysql> reset slave; #從服務(wù)器清除master.info, relay-log.info, relay log, 開(kāi)始新的relay log
#執(zhí)行reset slave all后, 所有關(guān)于主從復(fù)制的文件都被刪除, 生成新的relay-log文件slave-relay-bin.000001
[17:17:41 root@slave ~]#ll /data/mysql
total 123008
-rw-r----- 1 mysql mysql       56 Nov 25 00:05 auto.cnf
-rw------- 1 mysql mysql     1680 Nov 25 00:05 ca-key.pem
-rw-r--r-- 1 mysql mysql     1112 Nov 25 00:05 ca.pem
-rw-r--r-- 1 mysql mysql     1112 Nov 25 00:05 client-cert.pem
-rw------- 1 mysql mysql     1676 Nov 25 00:05 client-key.pem
drwxr-x--- 2 mysql mysql      272 Nov 25 14:43 hellodb
-rw-r----- 1 mysql mysql      293 Nov 25 14:18 ib_buffer_pool
-rw-r----- 1 mysql mysql 12582912 Nov 25 16:45 ibdata1
-rw-r----- 1 mysql mysql 50331648 Nov 25 16:45 ib_logfile0
-rw-r----- 1 mysql mysql 50331648 Nov 25 00:05 ib_logfile1
-rw-r----- 1 mysql mysql 12582912 Nov 25 14:18 ibtmp1
drwxr-x--- 2 mysql mysql     4096 Nov 25 00:05 mysql
-rw-r----- 1 mysql mysql      154 Nov 25 14:18 mysql-bin.000001
-rw-r----- 1 mysql mysql       29 Nov 25 14:18 mysql-bin.index
-rw-r----- 1 mysql mysql    36039 Nov 25 17:15 mysql.log
-rw-r----- 1 mysql mysql        5 Nov 25 14:18 mysql.pid
srwxrwxrwx 1 mysql mysql        0 Nov 25 14:18 mysql.sock
-rw------- 1 mysql mysql        5 Nov 25 14:18 mysql.sock.lock
drwxr-x--- 2 mysql mysql     8192 Nov 25 00:05 performance_schema
-rw------- 1 mysql mysql     1676 Nov 25 00:05 private_key.pem
-rw-r--r-- 1 mysql mysql      452 Nov 25 00:05 public_key.pem
-rw-r--r-- 1 mysql mysql     1112 Nov 25 00:05 server-cert.pem
-rw------- 1 mysql mysql     1680 Nov 25 00:05 server-key.pem
-rw-r----- 1 mysql mysql      177 Nov 25 17:15 slave-relay-bin.000001
-rw-r----- 1 mysql mysql       25 Nov 25 17:15 slave-relay-bin.index
drwxr-x--- 2 mysql mysql     8192 Nov 25 00:05 sys
#slave信息也被刪除
mysql> show slave status \G
Empty set (0.00 sec)

7.1.6.2 主從復(fù)制沖突, 造成數(shù)據(jù)無(wú)法同步的問(wèn)題和解決方法

由于從節(jié)點(diǎn)沒(méi)有設(shè)置read_only=on, 只讀, 造成從節(jié)點(diǎn)也可以修改數(shù)據(jù), 此時(shí)比如從節(jié)點(diǎn)增加了一行數(shù)據(jù), 然后如果主節(jié)點(diǎn)也增了一行數(shù)據(jù), 并且存在主鍵沖突時(shí), 那么這時(shí)數(shù)據(jù)同步就會(huì)失敗

案例演示

  1. 從節(jié)點(diǎn)增加一行數(shù)據(jù), 10.0.0.217
mysql> use hellodb;
mysql> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name          | Age | Gender |
+-----+---------------+-----+--------+
|   1 | Song Jiang    |  45 | M      |
|   2 | Zhang Sanfeng |  94 | M      |
|   3 | Miejue Shitai |  77 | F      |
|   4 | Lin Chaoying  |  93 | F      |
|   5 | zhao          |  18 | M      |
|   6 | qian          |  18 | M      |
+-----+---------------+-----+--------+
6 rows in set (0.00 sec)

mysql> insert teachers (name,age,gender) value ('haha',19,'M');
Query OK, 1 row affected (0.01 sec)
  1. 主節(jié)點(diǎn)增加數(shù)據(jù), 10.0.0.227
mysql> use hellodb;
mysql> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name          | Age | Gender |
+-----+---------------+-----+--------+
|   1 | Song Jiang    |  45 | M      |
|   2 | Zhang Sanfeng |  94 | M      |
|   3 | Miejue Shitai |  77 | F      |
|   4 | Lin Chaoying  |  93 | F      |
|   5 | zhao          |  18 | M      |
|   6 | qian          |  18 | M      |
+-----+---------------+-----+--------+
6 rows in set (0.00 sec)

mysql> insert teachers (name,age,gender) value ('lala',19,'M');
Query OK, 1 row affected (0.00 sec)

此時(shí), 雖然主從節(jié)點(diǎn)增加的數(shù)據(jù)不同, 但是從節(jié)點(diǎn)增加的數(shù)據(jù)主鍵位為7, 主節(jié)點(diǎn)增加的數(shù)據(jù)主鍵位也為7, 那么主節(jié)點(diǎn)向從節(jié)點(diǎn)同步自己增加的主鍵為7的數(shù)據(jù)時(shí)就會(huì)沖突, 因?yàn)橹麈I7在從節(jié)點(diǎn)已經(jīng)有了

#從節(jié)點(diǎn)觀察show slave status;信息
               Last_SQL_Error: Could not execute Write_rows event on table hellodb.teachers; Duplicate entry '7' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000002, end_log_pos 1513
#這時(shí)產(chǎn)生的錯(cuò)誤是SQL線程錯(cuò)誤, 也就是把數(shù)據(jù)從中繼日志寫(xiě)到從節(jié)點(diǎn)數(shù)據(jù)庫(kù)時(shí)產(chǎn)生的錯(cuò)誤
  1. 一旦發(fā)生數(shù)據(jù)沖突, 往后的所有數(shù)據(jù)都不會(huì)同步了

解決方法

  • 可以在從服務(wù)器忽略主服務(wù)器的復(fù)制事件個(gè)數(shù), 此為global變量, 或指定跳過(guò)事件的ID
#系統(tǒng)變量, 指定跳過(guò)復(fù)制事件的個(gè)數(shù)
#在出現(xiàn)問(wèn)題的從節(jié)點(diǎn)上執(zhí)行
mysql> set global sql_slave_skip_counter=1; # 出現(xiàn)幾個(gè)sql錯(cuò)誤渴邦, 就跳過(guò)幾次
Query OK, 0 rows affected (0.00 sec)
mysql> stop slave; #關(guān)閉slave
mysql> start slave; #再開(kāi)啟slave
#驗(yàn)證SQL錯(cuò)誤消失即可

此時(shí), 觀察從節(jié)點(diǎn)復(fù)制到的位置id

              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 615

驗(yàn)證主節(jié)點(diǎn)二進(jìn)制位置, 兩個(gè)id相等, 就說(shuō)明同步正常了, 此時(shí)在出現(xiàn)沖突后主節(jié)點(diǎn)寫(xiě)入的數(shù)據(jù), 都會(huì)同步給從節(jié)點(diǎn)

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |      615 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

但是, 這種情況下, 那條沖突的數(shù)據(jù), 由于在從節(jié)點(diǎn)已經(jīng)被忽略, 因此主節(jié)點(diǎn)不會(huì)再向從節(jié)點(diǎn)同步那條數(shù)據(jù), 這時(shí)主從節(jié)點(diǎn)是不一樣的, 如果只有一條, 那么只需在從節(jié)點(diǎn)修改, 按照主節(jié)點(diǎn)數(shù)據(jù)修改即可, 如果多的話就要再分析了

對(duì)于錯(cuò)誤沖突數(shù)據(jù)很多的情況下, 可以直接在從節(jié)點(diǎn)配置文件中指定, 略過(guò)所有的沖突, 之后重啟服務(wù)

[mysqld]
slave_skip_errors=ALL #也可以單獨(dú)指定SQL ERROR ID, 該ID就是從show slave status;報(bào)錯(cuò)得來(lái)的, Last_SQL_ERROR值

7.1.6.3 從節(jié)點(diǎn)服務(wù)器如果重啟, 那么從節(jié)點(diǎn)的兩個(gè)復(fù)制線程會(huì)默認(rèn)自動(dòng)開(kāi)啟

從節(jié)點(diǎn)服務(wù)器選項(xiàng)

skip-slave-start=ON #服務(wù)重啟后不自動(dòng)開(kāi)啟兩個(gè)IO和SQL線程

7.1.6.4 保證主從復(fù)制的事務(wù)安全

  • 在master節(jié)點(diǎn)啟用參數(shù)
sync_binlog=1 #每次寫(xiě)數(shù)據(jù)拘哨, 立即同步二進(jìn)制日志到磁盤谋梭, 性能差, 但是安全
# InnoDB引擎參數(shù)
innodb_flush_log_at_trx_commit=1 # 每次提交事務(wù)宅静, 立即同步日志寫(xiě)磁盤
sync_master_info=# # 多少次事件后master.info同步到磁盤
  • 在slave節(jié)點(diǎn)啟用參數(shù)
sync_relay_log=# 多少次寫(xiě)后同步relay log到磁盤
sync_relay_log_info=# 多少次事務(wù)后章蚣,同步relay-log.info到磁盤

7.2 級(jí)聯(lián)復(fù)制

級(jí)聯(lián)復(fù)制可以用來(lái)減少主服務(wù)器的壓力, 正常的一主多從, 要求主服務(wù)器負(fù)責(zé)寫(xiě)數(shù)據(jù), 還要根據(jù)后端不同數(shù)量的從服務(wù)器開(kāi)啟不同的復(fù)制線程, 每個(gè)線程都會(huì)消耗資源,

有了中間節(jié)點(diǎn), 主節(jié)點(diǎn)只需要開(kāi)啟一個(gè)dump線程把數(shù)據(jù)同步給中間節(jié)點(diǎn), 其余從節(jié)點(diǎn)由中間節(jié)點(diǎn)去負(fù)責(zé)同步

7.2.1 實(shí)現(xiàn)級(jí)聯(lián)復(fù)制要求

  • 中間節(jié)點(diǎn)開(kāi)啟二進(jìn)制, 這樣另一個(gè)從節(jié)點(diǎn)才能從中間節(jié)點(diǎn)復(fù)制數(shù)據(jù)
  • 中間節(jié)點(diǎn)開(kāi)啟log-slave-updates 中間節(jié)點(diǎn)必配置, 啟用后從節(jié)點(diǎn)會(huì)把從主節(jié)點(diǎn)接收到的數(shù)據(jù)也寫(xiě)入自己的二進(jìn)制日志中, 這樣才能把數(shù)據(jù)再?gòu)?fù)制給其他從節(jié)點(diǎn)

MySQL工作時(shí),每個(gè)二進(jìn)制日志只記錄當(dāng)前自己這臺(tái)服務(wù)器的操作,從節(jié)點(diǎn)從主節(jié)點(diǎn)獲得的二進(jìn)制會(huì)寫(xiě)到數(shù)據(jù)庫(kù)里, 但是不會(huì)寫(xiě)到二進(jìn)制日志, 但是其他從節(jié)點(diǎn)是要從中間節(jié)點(diǎn)的二進(jìn)制日志獲取數(shù)據(jù)的, 這就要求中間節(jié)點(diǎn)從主節(jié)點(diǎn)獲取的二進(jìn)制信息也要寫(xiě)入自己的二進(jìn)制日志里, 同時(shí)自身發(fā)生的操作也寫(xiě)到二進(jìn)制日志里

實(shí)現(xiàn)級(jí)聯(lián)復(fù)制

10.0.0.237-主節(jié)點(diǎn)
10.0.0.227-作為中間節(jié)點(diǎn)
10.0.0.217作為從節(jié)點(diǎn), 建議找一個(gè)干凈的mysql環(huán)境. 因?yàn)閺墓?jié)點(diǎn)一旦有多于中間節(jié)點(diǎn)和主節(jié)點(diǎn)的數(shù)據(jù), 那么會(huì)保留姨夹, 造成數(shù)據(jù)不一致

步驟:

  1. 三臺(tái)服務(wù)器安裝mysql
  2. 配置主節(jié)點(diǎn)
server-id=237
log-bin=/data/mysql/mysql-bin    

service mysqld restart

mysql> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       154 |
+------------------+-----------+
1 row in set (0.00 sec)
 grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by '000000';

3 . 配置中間節(jié)點(diǎn)

[mysqld]
log-slave-updates
log-bin=/data/mysql/mysql-bin
server-id=227  

service mysqld restart
mysql> CHANGE MASTER TO
    -> MASTER_HOST='10.0.0.237',
    ->  MASTER_USER='repluser',
    -> MASTER_PASSWORD='000000',
    ->  MASTER_PORT=3306,
    ->   MASTER_LOG_FILE='mysql-bin.000001',
    -> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
  1. 確保中間節(jié)點(diǎn)有復(fù)制賬號(hào)
mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| repluser      | 10.0.0.%  |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+
4 rows in set (0.00 sec)
  1. 主節(jié)點(diǎn)導(dǎo)入hellodb數(shù)據(jù)庫(kù)纤垂, 確保能同步給中間節(jié)點(diǎn), 并且中間節(jié)點(diǎn)會(huì)記錄二進(jìn)制日志到本地
[12:02:48 root@master ~]#mysql < hellodb_innodb.sql

- 中間節(jié)點(diǎn)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

- 查看中間節(jié)點(diǎn)二進(jìn)制

[12:03:51 root@mid ~]#ll /data/mysql/mysql-bin.000001 
-rw-r----- 1 mysql mysql 10147 Jun 15 12:02 /data/mysql/mysql-bin.000001 # 已經(jīng)更新

  1. 在中間節(jié)點(diǎn)做數(shù)據(jù)完全備份, 需要先確保中間節(jié)點(diǎn)和主節(jié)點(diǎn)是同步的, 查看POS ID
mysql> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |     10219 |
+------------------+-----------+
1 row in set (0.00 sec)

              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 10219


[12:05:01 root@mid ~]#mysqldump -A -F --master-data=1 --single-transaction > /data/new_all.sql

[12:05:13 root@mid ~]#ll /data/
total 8
-rw-r--r--  1 root  root   203 Jun 15 12:05 new_all.sql
  1. 復(fù)制到從節(jié)點(diǎn)
[12:05:16 root@mid ~]#scp /data/new_all.sql 10.0.0.217:/root

  1. 從節(jié)點(diǎn)配置文件
[mysqld]
server-id=217 #server-id不能沖突
log-bin=/data/mysql/mysql-bin                                                                                                                                                       
datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
  1. 創(chuàng)建二進(jìn)制路徑
[18:21:56 root@slave ~]#mkdir -pv /data/mysql/
[18:22:01 root@slave ~]#chown -R mysql.mysql /data/mysql
[12:13:15 root@slave ~]#service mysqld restart
  1. 導(dǎo)入完全備份
CHANGE MASTER TO 
MASTER_HOST='10.0.0.227',
MASTER_USER='repluser',
MASTER_PASSWORD='000000',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;                                                                                

[12:18:55 root@slave ~]#mysql  < new_all.sql

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

  1. 確保三臺(tái)服務(wù)器主從復(fù)制位置一致磷账, 數(shù)據(jù)一致
從服務(wù)器的二進(jìn)制位置要和中間節(jié)點(diǎn)一致
中間節(jié)點(diǎn)要和主服務(wù)器一致
mysql> create database db1;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| hellodb            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
6 rows in set (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| hellodb            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
6 rows in set (0.00 sec)


  • 總結(jié)
單純的主從峭沦, 需要根據(jù)從節(jié)點(diǎn)的個(gè)數(shù)建立對(duì)應(yīng)的dump線程,對(duì)主節(jié)點(diǎn)壓力很大
級(jí)聯(lián)復(fù)制可以減輕主節(jié)點(diǎn)壓力, 但從節(jié)點(diǎn)的復(fù)制效率不如單純的主從
如果是多機(jī)房情況下逃糟,可以考慮級(jí)聯(lián)復(fù)制吼鱼, 每個(gè)機(jī)房找一個(gè)節(jié)點(diǎn),和主服務(wù)器進(jìn)行同步

7.3 雙主復(fù)制

雙主復(fù)制: 兩個(gè)節(jié)點(diǎn), 都可以更新數(shù)據(jù), 并且互為主從

容易產(chǎn)生的問(wèn)題: 數(shù)據(jù)不一致, 因此慎用, 如果兩臺(tái)服務(wù)器同時(shí)寫(xiě)入數(shù)據(jù), 并且數(shù)據(jù)的主鍵相等, 就會(huì)出現(xiàn)沖突

雙主的好處: 配合讀寫(xiě)分離器, 實(shí)現(xiàn)寫(xiě)操作只調(diào)度到一個(gè)主節(jié)點(diǎn), 讀操作調(diào)度到另一節(jié)點(diǎn), 類似主從. 不過(guò), 因?yàn)楸旧砼涞亩际侵鞴?jié)點(diǎn), 因此, 一旦負(fù)責(zé)寫(xiě)操作的主節(jié)點(diǎn)宕機(jī), 可以直接把請(qǐng)求調(diào)度到另一個(gè)主節(jié)點(diǎn), 省去了主從手動(dòng)切換的過(guò)程

考慮要點(diǎn): 自動(dòng)增長(zhǎng)id

解決方法:

  1. 搭建雙主, 通過(guò)前端分離器實(shí)現(xiàn)寫(xiě)操作往一個(gè)服務(wù)器調(diào)度, 讀操作往另一個(gè)服務(wù)器調(diào)度, 這樣就不會(huì)出現(xiàn)同時(shí)寫(xiě)操作的情況, 可以避免主鍵id沖突

  2. 兩個(gè)節(jié)點(diǎn)分別使用不同的主鍵id增長(zhǎng)策略, 一個(gè)節(jié)點(diǎn)配置奇數(shù)增長(zhǎng), 一個(gè)節(jié)點(diǎn)配置偶數(shù)增長(zhǎng)

節(jié)點(diǎn)1:

auto_increment_offset=1 #開(kāi)始點(diǎn)
auto_increment_increment=2 #增長(zhǎng)幅度, 實(shí)現(xiàn)奇數(shù)增長(zhǎng)

節(jié)點(diǎn)2:

auto_increment_offset=2 #開(kāi)始點(diǎn)
auto_increment_increment2 #增長(zhǎng)幅度, 實(shí)現(xiàn)偶數(shù)增長(zhǎng)

7.3.1 雙主復(fù)制的配置步驟

各節(jié)點(diǎn)使用一個(gè)唯一的server-id
都啟用binary log和relay log
創(chuàng)建擁有復(fù)制權(quán)限的用戶賬號(hào)
定義自動(dòng)增長(zhǎng)id字段的數(shù)字范圍各為奇偶
均把對(duì)方指定為主節(jié)點(diǎn), 并啟動(dòng)復(fù)制線程

7.3.2 配置案例

雙主:
CentOS 7
MySQL 5.7.31
10.0.0.237
10.0.0.227

10.0.0.237配置


[12:44:37 root@master-1 ~]#vim /etc/my.cnf


[mysqld]

server-id=237
log-bin=/data/mysql/mysql-bin
auto_increment_offset=1
auto_increment_increment=2  

10.0.0.227配置


[12:40:36 root@master-2 ~]#vim /etc/my.cnf
server-id=227                                                                                                                          
log-bin=/data/mysql/mysql-bin
auto_increment_offset=2
auto_increment_increment=2  

10.0.0.237

配置后重啟服務(wù), 生成二進(jìn)制日志

[12:44:37 root@master-1 ~]#service mysqld restart
[12:48:20 root@master-1 ~]#ll /data/mysql/mysql-bin*
-rw-r----- 1 mysql mysql 154 Jun 15 12:48 /data/mysql/mysql-bin.000001
-rw-r----- 1 mysql mysql  29 Jun 15 12:48 /data/mysql/mysql-bin.index

查看二進(jìn)制日志位置

[12:48:41 root@master-1 ~]#mysql -e 'show master logs;'
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       154 |
+------------------+-----------+

創(chuàng)建復(fù)制賬號(hào)

mysql> grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by '000000';
Query OK, 0 rows affected, 1 warning (0.00 sec)

10.0.0.227

配置后重啟服務(wù), 生成二進(jìn)制日志

[12:49:24 root@master-2 ~]#service mysqld restart
[12:49:31 root@master-2 ~]#ll /data/mysql/mysql-bin*
-rw-r----- 1 mysql mysql 154 Jun 15 12:49 /data/mysql/mysql-bin.000001
-rw-r----- 1 mysql mysql  29 Jun 15 12:49 /data/mysql/mysql-bin.index

查看二進(jìn)制日志位置

[12:49:44 root@master-2 ~]#mysql -e 'show master logs'
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       154 |
+------------------+-----------+


先把10.0.0.227作為10.0.0.237的從節(jié)點(diǎn)

10.0.0.227
mysql> CHANGE MASTER TO
    ->   MASTER_HOST='10.0.0.237',
    ->   MASTER_USER='repluser',
    ->   MASTER_PASSWORD='000000',
    ->   MASTER_PORT=3306,
    ->   MASTER_LOG_FILE='mysql-bin.000001',
    ->   MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.02 sec)

由于復(fù)制的位置是主節(jié)點(diǎn)創(chuàng)建賬號(hào)之前的位置, 因此從節(jié)點(diǎn)無(wú)需再創(chuàng)建復(fù)制賬號(hào)

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| repluser      | 10.0.0.%  |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+
4 rows in set (0.00 sec)

此時(shí)從節(jié)點(diǎn)同步數(shù)據(jù), 但是不會(huì)生成二進(jìn)制日志. 因?yàn)闆](méi)有開(kāi)啟log-slave-updates

mysql> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       154 |
+------------------+-----------+
1 row in set (0.00 sec)

再把10.0.0.237作為10.0.0.227的從節(jié)點(diǎn)

10.0.0.237
mysql> CHANGE MASTER TO
    ->  MASTER_HOST='10.0.0.227',
    -> MASTER_USER='repluser',
    -> MASTER_PASSWORD='000000',
    -> MASTER_PORT=3306,
    -> MASTER_LOG_FILE='mysql-bin.000001',
    ->  MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

測(cè)試雙向同步

10.0.0.237 創(chuàng)建數(shù)據(jù)庫(kù) db1

mysql> create database db1;
Query OK, 1 row affected (0.01 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

查看10.0.0.227同步情況

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

10.0.0.227 創(chuàng)建數(shù)據(jù)庫(kù) db2

mysql> create database db2;
Query OK, 1 row affected (0.00 sec)

查看10.0.0.237同步情況

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| db2                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
6 rows in set (0.00 sec)
  • 測(cè)試兩個(gè)節(jié)點(diǎn)同時(shí)創(chuàng)建數(shù)據(jù)庫(kù)db3是否沖突

利用Xshell同時(shí)向多個(gè)窗口發(fā)送指令, create database db3;

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| db2                |
| db3                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
7 rows in set (0.00 sec)
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| db2                |
| db3                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
7 rows in set (0.00 sec)

可以看到同時(shí)創(chuàng)建同名的數(shù)據(jù)庫(kù)不會(huì)沖突, 不過(guò)會(huì)產(chǎn)生復(fù)制錯(cuò)誤, 導(dǎo)致后續(xù)創(chuàng)建的數(shù)據(jù)不會(huì)同步

master-1
                   Last_Errno: 1007
                   Last_Error: Error 'Can't create database 'db3'; database exists' on query. Default database: 'db3'. Query: 'create database db3'

master-2
               Last_SQL_Errno: 1007
               Last_SQL_Error: Error 'Can't create database 'db3'; database exists' on query. Default database: 'db3'. Query: 'create database db3'

跳過(guò)沖突:

[mysqld]
slave_skip_errors=ALL
[05:32:02 root@master-1 ~]#service mysqld restart

[mysqld]
slave_skip_errors=ALL
[05:32:02 root@master-2 ~]#service mysqld restart
  • 測(cè)試同時(shí)在兩個(gè)節(jié)點(diǎn)創(chuàng)建相同的表是否沖突

在db3創(chuàng)建table1表, use db3;

mysql> create table table1(id int auto_increment primary key, name char(10));
Query OK, 0 rows affected (0.02 sec)
mysql> create table table1(id int auto_increment primary key, name char(10));
Query OK, 0 rows affected (0.02 sec)

結(jié)果顯示建表可以創(chuàng)建, 但是還會(huì)出現(xiàn)沖突

               Last_SQL_Errno: 1050
               Last_SQL_Error: Error 'Table 'table1' already exists' on query. Default database: 'db3'. Query: 'create table table1(id int auto_increment primary key, name char(10))'

               Last_SQL_Errno: 1050
               Last_SQL_Error: Error 'Table 'table1' already exists' on query. Default database: 'db3'. Query: 'create table table1(id int auto_increment primary key, name char(10))'

按照上面相同步驟, 跳過(guò)沖突

測(cè)試在db3.table1表創(chuàng)建記錄是否沖突

mysql> insert table1(name) value ('b');
Query OK, 1 row affected (0.10 sec)
mysql> insert table1(name) value ('b');
Query OK, 1 row affected (0.11 sec)
mysql> select * from table1;
+----+------+
| id | name |
+----+------+
|  1 | b    |
|  2 | b    |
+----+------+
2 rows in set (0.00 sec)

mysql> select * from table1;
+----+------+
| id | name |
+----+------+
|  1 | b    |
|  2 | b    |
+----+------+
2 rows in set (0.00 sec)

結(jié)果顯示創(chuàng)建數(shù)據(jù)不會(huì)沖突, 因?yàn)槲覀冡槍?duì)兩個(gè)節(jié)點(diǎn)設(shè)定了不同的主鍵id自動(dòng)增長(zhǎng)

補(bǔ)充:

  • 即使數(shù)據(jù)庫(kù)沒(méi)配置成不同的自動(dòng)增長(zhǎng)步長(zhǎng), 只要是表開(kāi)啟了自動(dòng)增長(zhǎng), 那么即使同時(shí)插入相同的數(shù)據(jù), 也不會(huì)沖突, MySQL會(huì)自動(dòng)調(diào)整表的自增步長(zhǎng)

  • 如果插入數(shù)據(jù)時(shí), 人為指定了主鍵, 那么同時(shí)插入數(shù)據(jù)就會(huì)沖突

建議:

  • 可以搭雙主架構(gòu), 但是按照一主一從使用, 利用分離器實(shí)現(xiàn)寫(xiě)數(shù)據(jù)往一個(gè)主節(jié)點(diǎn)調(diào)度, 讀數(shù)據(jù)往另一個(gè)主節(jié)點(diǎn)調(diào)度, 數(shù)據(jù)由一個(gè)主節(jié)點(diǎn)復(fù)制到另一個(gè)主節(jié)點(diǎn), 這樣就不會(huì)沖突, 同時(shí), 一旦負(fù)責(zé)寫(xiě)輸入的主節(jié)點(diǎn)down了, 把寫(xiě)數(shù)據(jù)往另一個(gè)主節(jié)點(diǎn)調(diào)度即可, 因?yàn)榱硪粋€(gè)主節(jié)點(diǎn)都是配置好了的, 可以直接寫(xiě)數(shù)據(jù)

跳過(guò)復(fù)制錯(cuò)誤方法-指定具體編號(hào)

構(gòu)建錯(cuò)誤

               Last_SQL_Errno: 1007
               Last_SQL_Error: Error 'Can't create database 'db3'; database exists' on query. Default database: 'db3'. Query: 'create database db3'

分別修改兩個(gè)節(jié)點(diǎn)的配置文件

10.0.0.237

[23:09:43 root@master-1 ~]#vim /etc/my.cnf

[mysqld]
slave_skip_errors=1007  # 該選項(xiàng)無(wú)法動(dòng)態(tài)修改,而slave_skip_counter是可以動(dòng)態(tài)修改的

重啟mysql

[23:11:26 root@master-1 ~]#service mysqld restart
Shutting down MySQL............                            [  OK  ]
Starting MySQL.                                            [  OK  ]

觀察錯(cuò)誤消失即可, 10.0.0.227上也做相同的操作就可以恢復(fù)數(shù)據(jù)同步了

7.4 半同步復(fù)制

默認(rèn)情況下, MySQL的主從復(fù)制是異步復(fù)制, 用戶發(fā)送DML請(qǐng)求到達(dá)MySQL讀寫(xiě)分離器, 讀寫(xiě)分離器會(huì)把請(qǐng)求調(diào)度到主節(jié)點(diǎn)進(jìn)行寫(xiě)操作, 主節(jié)點(diǎn)完成數(shù)據(jù)庫(kù)更新會(huì)立即返回更新成功結(jié)果給分離器, 分離器會(huì)返回用戶更新成功消息, 主節(jié)點(diǎn)同時(shí)將二進(jìn)制更新同步給從節(jié)點(diǎn)

如果主從復(fù)制延遲較大時(shí), 主節(jié)點(diǎn)的二進(jìn)制更新還沒(méi)有復(fù)制給從節(jié)點(diǎn)時(shí), 一旦主節(jié)點(diǎn)故障, 二進(jìn)制日志也無(wú)法恢復(fù), 那么這時(shí)用戶更新的數(shù)據(jù)就會(huì)丟失, 因?yàn)閺墓?jié)點(diǎn)還沒(méi)來(lái)得及更新自己的數(shù)據(jù). 但是分離器已經(jīng)返回給用戶更新成功通知.

同步復(fù)制:

主節(jié)點(diǎn)更新數(shù)據(jù)后, 必須要確保全部從節(jié)點(diǎn)已經(jīng)完全接收了二進(jìn)制的更新, 更新成功后, 才會(huì)返回給分離器更新成功了. 否則用戶看不到更新成功消息. 這就會(huì)造成用戶等待, 因?yàn)樗袕墓?jié)點(diǎn)完成同步會(huì)有延遲

解決方法: 半同步復(fù)制

必須確保任意一個(gè)從節(jié)點(diǎn)同步成功, 返回同步成功結(jié)果給主節(jié)點(diǎn), 主節(jié)點(diǎn)才會(huì)通知分離器更新成功, 否則不會(huì)返回

這樣半同步就確保了即使主節(jié)點(diǎn)宕機(jī), 至少有一個(gè)從節(jié)點(diǎn)是有更新的數(shù)據(jù)的

然而, 如果所有節(jié)點(diǎn)的復(fù)制都很慢, 主節(jié)點(diǎn)需要設(shè)置超時(shí)時(shí)長(zhǎng), 規(guī)定時(shí)間內(nèi)如果無(wú)法同步到任何一個(gè)從節(jié)點(diǎn), 就會(huì)返回更新失敗. 雖然此時(shí)也有風(fēng)險(xiǎn), 比如等待時(shí)間設(shè)置過(guò)長(zhǎng), 如果等待期間內(nèi)主服務(wù)器宕機(jī), 仍然會(huì)丟失數(shù)據(jù). 半同步只是盡肯能照顧了數(shù)據(jù)安全, 也保證了效率.

主從和半同步復(fù)制需要搭配使用

實(shí)驗(yàn)環(huán)境:

10.0.0.237 主節(jié)點(diǎn)
10.0.0.227 從節(jié)點(diǎn)

步驟1: 兩個(gè)節(jié)點(diǎn)部署mysql

步驟2: 主節(jié)點(diǎn)10.0.0.237開(kāi)啟半同步

#MySQL 5.7版本需要在mysql里安裝半同步插件, 不同版本配置不同, 高本版的MySQL和MariaDB是在配置文件里直接加載
#install這一步需要在修改配置文件, 重啟mysqld之前做, 要不然會(huì)報(bào)錯(cuò), 系統(tǒng)未知的變量"rpl_semi_sync_master_enabled"
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';
Query OK, 0 rows affected (0.01 sec)
vim /etc/my.cnf
rpl_semi_sync_master_enabled=ON #開(kāi)啟半同步復(fù)制功能
rpl_semi_sync_master_timeout=3000 #設(shè)置超時(shí)時(shí)間, 3s內(nèi)無(wú)法同步, 會(huì)返回更新失敗消息, 默認(rèn)是10s
server-id=237
log-bin=/data/mysql/mysql-bin 
[09:54:03 root@master ~]#service mysqld restart
Shutting down MySQL..                                      [  OK  ]
Starting MySQL.                                            [  OK  ]
mysql> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       154 |
+------------------+-----------+
1 row in set (0.00 sec)

mysql> grant replication slave on *.* to 'repluser'@'10.0.0.%' identified by '000000';
Query OK, 0 rows affected, 1 warning (3.00 sec)

步驟3: 修改從節(jié)點(diǎn)配置文件

mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
Query OK, 0 rows affected (0.01 sec)
rpl_semi_sync_slave_enabled=ON  #從節(jié)點(diǎn)啟用半同步復(fù)制
server-id=227
log-bin=/data/mysql/mysql-bin 
[09:54:03 root@slave ~]#service mysqld restart

從節(jié)點(diǎn)指定復(fù)制位置

mysql> CHANGE MASTER TO
    -> MASTER_HOST='10.0.0.237',
    -> MASTER_USER='repluser',
    -> MASTER_PASSWORD='000000',
    -> MASTER_PORT=3306,
    -> MASTER_LOG_FILE='mysql-bin.000001',
    -> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%semi%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | ON    |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
2 rows in set (0.00 sec)

查看主節(jié)點(diǎn)半同步狀態(tài)

mysql> show global status like '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     | #這里可以看到已經(jīng)有了一個(gè)從節(jié)點(diǎn)
mysql> show variables like '%semi%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 3000       |
| rpl_semi_sync_master_trace_level          | 32         |
| rpl_semi_sync_master_wait_for_slave_count | 1          |
| rpl_semi_sync_master_wait_no_slave        | ON         |
| rpl_semi_sync_master_wait_point           | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.00 sec)

步驟4: 驗(yàn)證同步情況

主節(jié)點(diǎn)導(dǎo)入測(cè)試存儲(chǔ)過(guò)程和hellodb數(shù)據(jù)庫(kù)

[09:54:03 root@master ~]#cat testlog.sql 
create table testlog (id int auto_increment primary key,name char(10),age int default 20);

delimiter $$

create procedure  sp_testlog() 
begin  
declare i int;
set i = 1; 
while i <= 100000 
do  insert into testlog(name,age) values (concat('wang',i),i); 
set i = i +1; 
end while; 
end$$

delimiter ;
[09:56:19 root@master ~]#mysql < hellodb_innodb.sql
[09:56:26 root@master ~]#mysql hellodb < testlog.sql

mysql> use hellodb;
mysql> call sp_testlog;

同時(shí)觀察從節(jié)點(diǎn)同步情況, 確保同步正常

mysql> select count(*) from hellodb.testlog;
+----------+
| count(*) |
+----------+
|   100000 |
+----------+
1 row in set (0.01 sec)

步驟5: 再搭建一個(gè)從節(jié)點(diǎn)10.0.0.217實(shí)現(xiàn)一主兩從架構(gòu)

mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)
[14:31:46 root@slave-2 ~]#vim /etc/my.cnf

[mysqld]
server-id=217
log-bin=/data/mysql/mysql-log
rpl_semi_sync_slave_enabled=ON  
                                                                                                                   

datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
[10:46:01 root@slave-2 ~]#service mysqld restart

Shutting down MySQL..                                      [  OK  ]
Starting MySQL.                                            [  OK  ]

將主節(jié)點(diǎn)數(shù)據(jù)做完全備份

[10:47:29 root@master ~]#mysqldump -A -F --single-transaction --master-data=1 > /data/allbackup.sql

將完全備份拷貝到10.0.0.53第二個(gè)從節(jié)點(diǎn)

[10:47:30 root@master ~]#scp /data/allbackup.sql 10.0.0.217:/root

從節(jié)點(diǎn)設(shè)置change master to

#查看完全備份日志位置, 修改完全備份文件
CHANGE MASTER TO 
MASTER_HOST='10.0.0.237',
MASTER_USER='repluser',
MASTER_PASSWORD='000000',
MASTER_PORT=3306,                                                                                                                                                                                                
MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;

從節(jié)點(diǎn)導(dǎo)入完全備份

mysql> set sql_log_bin=off;
mysql> source /root/allbackup.sql
mysql> set sql_log_bin=on;

從節(jié)點(diǎn)開(kāi)啟slave

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

驗(yàn)證同步

             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

步驟6: 驗(yàn)證主節(jié)點(diǎn)上半同步客戶端為2

mysql> show global status like '%semi%';
+--------------------------------------------+----------+
| Variable_name                              | Value    |
+--------------------------------------------+----------+
| Rpl_semi_sync_master_clients               | 2        |

步驟7: 關(guān)閉10.0.0.217上的slave功能, 驗(yàn)證主節(jié)點(diǎn)可以正常寫(xiě)數(shù)據(jù)

10.0.0.217

mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)

主節(jié)點(diǎn)創(chuàng)建數(shù)據(jù)庫(kù)

mysql> create database testdb;
Query OK, 1 row affected (0.01 sec)

可以看到此時(shí)主節(jié)點(diǎn)還是可以正常修改, 因?yàn)閽炝艘粋€(gè)從節(jié)點(diǎn), 另一個(gè)從節(jié)點(diǎn)還是正常工作可以同步的, 而且因?yàn)榄h(huán)境簡(jiǎn)單, 同步時(shí)間沒(méi)有超過(guò)3秒, 所以同步成功

驗(yàn)證10.0.0.227上同步成功

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| mysql              |
| performance_schema |
| sys                |
| testdb             |
+--------------------+

步驟8: 關(guān)掉10.0.0.227上的從節(jié)點(diǎn)服務(wù), 構(gòu)建無(wú)法同步的環(huán)境, 測(cè)試主節(jié)點(diǎn)能否修改數(shù)據(jù)

10.0.0.52

mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)

此時(shí)主節(jié)點(diǎn)的mysql日志會(huì)提示同步關(guān)閉

2020-11-25T17:03:48.034172Z 0 [ERROR] /usr/local/mysql/bin/mysqld: Got an error reading communication packets
2020-11-25T17:04:30.781849Z 13 [ERROR] Semi-sync master failed on net_flush() before waiting for slave reply
2020-11-25T17:04:30.781888Z 13 [Note] Stop semi-sync binlog_dump to slave (server_id: 53)
2020-11-25T17:04:30.782041Z 13 [Note] Aborted connection 13 to db: 'unconnected' user: 'repluser' host: '10.0.0.53' (Found net error)
2020-11-25T17:08:37.501641Z 0 [ERROR] /usr/local/mysql/bin/mysqld: Got an error reading communication packets
2020-11-25T17:09:30.803252Z 2 [Note] Stop semi-sync binlog_dump to slave (server_id: 52)
2020-11-25T17:09:30.803377Z 2 [Note] Aborted connection 2 to db: 'unconnected' user: 'repluser' host: '10.0.0.52' (failed on flush_net())
2020-11-25T17:10:35.383468Z 14 [Warning] Timeout waiting for reply of binlog (file: mysql-bin.000003, pos: 487), semi-sync up to file mysql-bin.000003, position 319.
2020-11-25T17:10:35.383562Z 14 [Note] Semi-sync replication switched OFF.

確保主節(jié)點(diǎn)和從節(jié)點(diǎn)復(fù)制關(guān)系消失后, 主節(jié)點(diǎn)創(chuàng)建數(shù)據(jù)庫(kù)

mysql> show global status like '%semi%';
+--------------------------------------------+----------+
| Variable_name                              | Value    |
+--------------------------------------------+----------+
| Rpl_semi_sync_master_clients               | 0        | #確保client為0
#此時(shí)主節(jié)點(diǎn)會(huì)等待超時(shí)時(shí)間到期后再返回信息, 這里顯示成功是因?yàn)榧词乖谥鞴?jié)點(diǎn)成功了, 但是信息也沒(méi)有復(fù)制到從節(jié)點(diǎn)上. 根據(jù)半同步原理, 此時(shí)會(huì)返回給用戶端更新失敗消息.
mysql> create database testdb2;
Query OK, 1 row affected (3.00 sec)

這時(shí), 需要恢復(fù)主從同步關(guān)系用戶才能正常寫(xiě)數(shù)據(jù)并且得到更新成功的消息

兩個(gè)從節(jié)點(diǎn)啟動(dòng)復(fù)制, 為下個(gè)實(shí)驗(yàn)做準(zhǔn)備, 開(kāi)啟復(fù)制后, 之前創(chuàng)建的testdb2會(huì)繼續(xù)復(fù)制到兩個(gè)從節(jié)點(diǎn)

start slave;

7.5 復(fù)制過(guò)濾器

讓從節(jié)點(diǎn)僅復(fù)制指定的數(shù)據(jù)庫(kù), 或指定數(shù)據(jù)庫(kù)的指定表

復(fù)制過(guò)濾器的兩種實(shí)現(xiàn)方式

(1) 服務(wù)器選項(xiàng): 在主服務(wù)器配置文件中指定哪些數(shù)據(jù)庫(kù)會(huì)復(fù)制, 哪些不會(huì)復(fù)制

此方法問(wèn)題: 基于二進(jìn)制還原將無(wú)法實(shí)現(xiàn), 不建議使用

vim /etc/my.cnf
binlog-do-db=DB_NAME #數(shù)據(jù)庫(kù)白名單, 不支持同時(shí)指定多個(gè)值, 如果想實(shí)現(xiàn)多個(gè)數(shù)據(jù)庫(kù)需要寫(xiě)多行
binlog-ignore-db=DB_NAME #數(shù)據(jù)庫(kù)黑名單, 不支持同時(shí)指定多個(gè)值, 如果想實(shí)現(xiàn)多個(gè)數(shù)據(jù)庫(kù)需要寫(xiě)多行

案例:

  1. 先查看主服務(wù)器上數(shù)據(jù)庫(kù)信息
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| mysql              |
| performance_schema |
| sys                |
| testdb             |
| testdb2            |
+--------------------+
7 rows in set (0.01 sec)
  1. 修改主節(jié)點(diǎn)配置文件, 添加復(fù)制規(guī)則
[15:08:20 root@master-1 ~]#vim /etc/my.cnf

[mysqld]

binlog-do-db=testdb2                                                                                  
binlog-do-db=hellodb                                                                                                                                                                                            

rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=3000

server-id=237
log-bin=/data/mysql/mysql-bin

datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock
~                                 
[10:54:37 root@master ~]#service mysqld restart

  1. 驗(yàn)證配置
# Binlog_Do_DB表示只同步哪個(gè)數(shù)據(jù)庫(kù)給從節(jié)點(diǎn)
mysql> show master status;
+------------------+----------+-----------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB    | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+-----------------+------------------+-------------------+
| mysql-bin.000003 |      154 | testdb2,hellodb |                  |                   |
+------------------+----------+-----------------+------------------+-------------------+
1 row in set (0.00 sec)


# 主節(jié)點(diǎn)在testdb2創(chuàng)建表, 驗(yàn)證可以同步到從節(jié)點(diǎn)
mysql> use testdb2;
Database changed

mysql> create table test (id int);
Query OK, 0 rows affected (0.01 sec)


# 驗(yàn)證從節(jié)點(diǎn)可以同步


mysql> show tables from testdb2;
+-------------------+
| Tables_in_testdb2 |
+-------------------+
| test              |
+-------------------+
1 row in set (0.00 sec)
# 主節(jié)點(diǎn)在testdb創(chuàng)建t1表, 驗(yàn)證不會(huì)同步

mysql> use  testdb;


Database changed
mysql> create table t1(id int);
Query OK, 0 rows affected (0.00 sec)


mysql> show tables;
+------------------+
| Tables_in_testdb |
+------------------+
| t1               |
+------------------+
1 row in set (0.00 sec)

從節(jié)點(diǎn)
mysql> show tables from testdb;
Empty set (0.00 sec)

  1. 使用服務(wù)器選項(xiàng)方法, 在跨越數(shù)據(jù)庫(kù)創(chuàng)建數(shù)據(jù)時(shí), 是不會(huì)同步的. 創(chuàng)建數(shù)據(jù), 必須在會(huì)被同步的庫(kù)里創(chuàng)建
主節(jié)點(diǎn)
mysql> use testdb;
mysql> create table testdb2.db_test(id int);
Query OK, 0 rows affected (0.01 sec)



mysql>  show tables from testdb2;
+-------------------+
| Tables_in_testdb2 |
+-------------------+
| db_test           |
| test              |
+-------------------+
2 rows in set (0.00 sec)


從節(jié)點(diǎn)不會(huì)同步db_test表, 因?yàn)楸硎侵鞴?jié)點(diǎn)在testdb里創(chuàng)建的


mysql>  show tables from testdb2;
+-------------------+
| Tables_in_testdb2 |
+-------------------+
| test              |
+-------------------+
1 row in set (0.00 sec)


  1. 此外, 使用服務(wù)器選項(xiàng)方式, 對(duì)于那些不會(huì)同步的數(shù)據(jù)庫(kù), 主節(jié)點(diǎn)即使開(kāi)啟了二進(jìn)制日志, 也不會(huì)記錄數(shù)據(jù), 這樣之后就無(wú)法利用二進(jìn)制對(duì)于那些沒(méi)有同步的數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)恢復(fù)了, 因此該方法不推薦使用

(2) 從服務(wù)器SQL_THREAD在讀取relay log中的事件時(shí), 僅讀取與特定數(shù)據(jù)庫(kù)(特定表)相關(guān)的時(shí)間, 并應(yīng)用與本地

此方法存在的問(wèn)題: 會(huì)造成網(wǎng)絡(luò)及磁盤IO浪費(fèi), 因?yàn)橹鞴?jié)點(diǎn)會(huì)把二進(jìn)制都復(fù)制給從節(jié)點(diǎn), 而從節(jié)點(diǎn)不會(huì)接收全部的數(shù)據(jù), 就會(huì)造成資源浪費(fèi)

從服務(wù)器上的復(fù)制過(guò)濾器相關(guān)變量

replicate_do_db=db1,db2,db3        #指定復(fù)制庫(kù)的白名單绰咽,變量可以指定逗號(hào)分隔的多個(gè)值菇肃,選項(xiàng)不支持多值
replicate_ignore_db=            #指定復(fù)制庫(kù)黑名單
replicate_do_table=             #指定復(fù)制表的白名單
replicate_ignore_table=         #指定復(fù)制表的黑名單
replicate_wild_do_table= foo%.bar%    #支持通配符
replicate_wild_ignore_table=
  • MySQL中, 只能在命令行或者配置文件定義服務(wù)器選項(xiàng). 這些變量在MySQL中不存在

案例:

  1. 取消主節(jié)點(diǎn)的復(fù)制過(guò)濾配置
[11:03:01 root@master ~]#vim /etc/my.cnf

[mysqld]

rpl_semi_sync_master_enabled=ON
rpl_semi_sync_master_timeout=3000
server-id=237
log-bin=/data/mysql/mysql-bin


                                                                                                      

datadir=/data/mysql
skip_name_resolve=1
socket=/data/mysql/mysql.sock
log-error=/data/mysql/mysql.log
pid-file=/data/mysql/mysql.pid
[client]
socket=/data/mysql/mysql.sock

[11:03:28 root@master ~]#service mysqld restart
  1. 兩個(gè)從節(jié)點(diǎn)配置復(fù)制過(guò)濾
[17:03:43 root@slave-1 ~]#vim /etc/my.cnf
replicate-do-db=testdb2                                                                               
replicate-do-db=hellodb  

[17:04:07 root@slave-1 ~]#service mysqld restart
[17:28:05 root@slave-2 ~]#vim /etc/my.cnf
replicate-do-db=testdb2                                                                               
replicate-do-db=hellodb  
# 這里如果重啟失敗, 需要先把半同步復(fù)制注釋, 重啟mysql, 然后進(jìn)到mysql安裝半同步復(fù)制插件, 之后啟用半同步, 重啟mysql即可
[17:28:05 root@slave-2 ~]#service mysqld restart
  1. 主節(jié)點(diǎn)在db1和hellodb做修改, 驗(yàn)證可以正常同步給從節(jié)點(diǎn)即可
  • 總結(jié): 定義了復(fù)制過(guò)濾后, 主節(jié)點(diǎn)新創(chuàng)建的數(shù)據(jù)庫(kù)是不會(huì)復(fù)制給從節(jié)點(diǎn)的, 需要從節(jié)點(diǎn)把新的數(shù)據(jù)庫(kù)添加到配置文件指定. 這種方法主節(jié)點(diǎn)會(huì)對(duì)所有數(shù)據(jù)庫(kù)記錄二進(jìn)制, 可用來(lái)做還原

7.6 GTID復(fù)制

GTID復(fù)制: (Global Transaction ID全局事務(wù)標(biāo)識(shí)符), MySQL5.6版本開(kāi)始支持, GTID復(fù)制不像傳統(tǒng)的復(fù)制方式(異步復(fù)制, 半同步復(fù)制)需要找到binlog文件名和POS點(diǎn)
GTID復(fù)制只需要知道m(xù)aster節(jié)點(diǎn)的ip, 端口, 賬號(hào), 密碼即可. 
開(kāi)始GTID后, 執(zhí)行change master to master_auto_position=1即可, 它會(huì)自動(dòng)尋找到相應(yīng)的位置開(kāi)始同步
GTID = server_uuid:transaction_id, 在一組復(fù)制中, 全局唯一
server_uuid 來(lái)源于 /var/lib/mysql/auto.cnf

GTID服務(wù)器相關(guān)選項(xiàng)

gtid_mode # gitd模式
enforce_gtid_consistency # 保證GTID安全的參數(shù)

配置案例

  1. 主服務(wù)器 - 10.0.0.237
[02:05:17 root@master-1 ~]#vim /etc/my.cnf

[mysqld]
server-id=237
log-bin=/data/mysql/mysql-bin
gtid_mode=ON
enforce_gtid_consistency                                                                              

[02:17:04 root@master-1 ~]#service mysqld restart
  1. 從服務(wù)器 - 10.0.0.227
取消slave

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> reset slave all;
Query OK, 0 rows affected (0.01 sec)

[02:19:54 root@slave-2 ~]#vim /etc/my.cnf

[mysqld]
server-id=217
log-bin=/data/mysql/mysql-bin
gtid_mode=ON
enforce_gtid_consistency                                                                              

[02:20:44 root@slave-2 ~]#service mysqld restart
mysql> change master to master_host='10.0.0.237',
    -> master_user="repluser",
    -> master_password="000000",
    -> master_port=3306,
    -> master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.03 sec)

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

7.7 復(fù)制的監(jiān)控和維護(hù)

(1): 清理日志

purge { binary | master } logs { to 'log_name' | before datetime_expr }
reset slave [all]

(2): 復(fù)制監(jiān)控

show master status
show binary logs
show binglog events
show slave status
show processlist

(3): 從服務(wù)器是否落后于主服務(wù)

Seconds_Behind_Master: 0

(4): 如果確定主從節(jié)點(diǎn)數(shù)據(jù)是否一致

percona-toolkit
pt-table-checksum  #檢查主從數(shù)據(jù)是否一致,
pt-table-sync #把主庫(kù)數(shù)據(jù)同步到從庫(kù)

(5): 數(shù)據(jù)不一致如何修復(fù)

刪除從數(shù)據(jù)庫(kù), 重新復(fù)制

7.8 復(fù)制的問(wèn)題和解決方案

7.8.1 數(shù)據(jù)損壞或丟失

1. master損壞: MHA+半同步復(fù)制,
mha會(huì)自動(dòng)提升一個(gè)較新的從節(jié)點(diǎn)為主節(jié)點(diǎn), 無(wú)需手動(dòng)切換
配合半同步復(fù)制, 確保至少有一個(gè)從節(jié)點(diǎn)已經(jīng)同步了數(shù)據(jù), 一旦主節(jié)點(diǎn)宕機(jī), 會(huì)提升該同步了數(shù)據(jù)的從節(jié)點(diǎn)為主節(jié)點(diǎn), 保證數(shù)據(jù)不丟失
2: slave損壞: 刪除數(shù)據(jù), 主節(jié)點(diǎn)做完全備份, 重新復(fù)制

7.8.2 不唯一的server id

重新復(fù)制

7.8.3 復(fù)制延遲

需要額外的監(jiān)控工具的輔助
一從多主: MariaDB10版本后支持
多線程復(fù)制: 對(duì)多個(gè)數(shù)據(jù)庫(kù)并行復(fù)制, MySQL支持客戶端并行訪問(wèn), 但是復(fù)制是串行的. 5.7以后可以根據(jù)數(shù)據(jù)庫(kù)的數(shù)量開(kāi)啟對(duì)應(yīng)線程進(jìn)行復(fù)制.

7.8.4 MySQL主從數(shù)據(jù)不一致

  1. 造成主從不一致的原因

    主庫(kù)binlog格式為Statement取募,同步到從庫(kù)執(zhí)行后可能造成主從不一致琐谤。
    主庫(kù)執(zhí)行更改前有執(zhí)行set sql_log_bin=0,會(huì)使主庫(kù)不記錄binlog玩敏,從庫(kù)也無(wú)法變更這部分?jǐn)?shù)據(jù)斗忌。
    從節(jié)點(diǎn)未設(shè)置只讀质礼,誤操作寫(xiě)入數(shù)據(jù)
    主庫(kù)或從庫(kù)意外宕機(jī),宕機(jī)可能會(huì)造成binlog或者relaylog文件出現(xiàn)損壞织阳,導(dǎo)致主從不一致
    主從實(shí)例版本不一致眶蕉,特別是高版本是主,低版本為從的情況下唧躲,主數(shù)據(jù)庫(kù)上面支持的功能造挽,從數(shù)據(jù)庫(kù)上面可能不支持該功能
    MySQL自身bug導(dǎo)致

  1. 主從不一致修復(fù)方法
  • 將從庫(kù)重新實(shí)現(xiàn)
雖然這也是一種解決方法,但是這個(gè)方案恢復(fù)時(shí)間比較慢惊窖,而且有時(shí)候從庫(kù)也是承擔(dān)一部分的查詢操作的刽宪,不能貿(mào)然重建。
  • 使用percona-toolkit工具輔助
PT工具包中包含pt-table-checksum和pt-table-sync兩個(gè)工具界酒,主要用于檢測(cè)主從是否一致以及修復(fù)數(shù)據(jù)不一致情況圣拄。
這種方案優(yōu)點(diǎn)是修復(fù)速度快,不需要停止主從輔助毁欣,缺點(diǎn)是需要知識(shí)積累庇谆,需要時(shí)間去學(xué)習(xí),去測(cè)試凭疮,特別是在生產(chǎn)環(huán)境饭耳,還是要小心使用
  • 手動(dòng)重建不一致的表
在從庫(kù)發(fā)現(xiàn)某幾張表與主庫(kù)數(shù)據(jù)不一致,而這幾張表數(shù)據(jù)量也比較大执解,手工比對(duì)數(shù)據(jù)不現(xiàn)實(shí)寞肖,并且重做整個(gè)庫(kù)也比較慢,這個(gè)時(shí)候可以只重做這幾張表來(lái)修復(fù)主從不一致

這種方案缺點(diǎn)是在執(zhí)行導(dǎo)入期間需要暫時(shí)停止從庫(kù)復(fù)制衰腌,不過(guò)也是可以接受的
范例:A,B,C這三張表主從數(shù)據(jù)不一致

1新蟆、從庫(kù)停止Slave復(fù)制
mysql>stop slave;

2、在主庫(kù)上dump這三張表右蕊,并記錄下同步的binlog和POS點(diǎn)
mysqldump -uroot -pmagedu -q --single-transaction --master-data=2 testdb A B C >/backup/A_B_C.sql

3琼稻、查看A_B_C.sql文件,找出記錄的binlog和POS點(diǎn)
head A_B_C.sql
例如:MASTERLOGFILE='mysql-bin.888888', MASTERLOGPOS=66666666;

4饶囚、把A_B_C.sql拷貝到Slave機(jī)器上帕翻,并做Change master to指向新位置
mysql>start slave until MASTERLOGFILE='mysql-bin.888888', MASTERLOGPOS=66666666;

#以上指令是為了保障其他表的數(shù)據(jù)不丟失,一直同步萝风,直到同步完那個(gè)點(diǎn)結(jié)束嘀掸,A,B,C表的數(shù)據(jù)在之前的備份已經(jīng)生成了一份快照,只需要導(dǎo)入進(jìn)入规惰,然后開(kāi)啟同步即可

5睬塌、在Slave機(jī)器上導(dǎo)入A_B_C.sql 
mysql -uroot -pmagedu  testdb 
mysql>set sql_log_bin=0;
mysql>source  /backup/A_B_C.sql
mysql>set sql_log_bin=1;

6、導(dǎo)入完畢后,從庫(kù)開(kāi)啟同步即可衫仑。
mysql>start slave;
  • 如何避免主從不一致

    主庫(kù)binlog采用ROW格式
    主從實(shí)例數(shù)據(jù)庫(kù)版本保持一致
    主庫(kù)做好賬號(hào)權(quán)限把控,不可以執(zhí)行set sql_log_bin=0
    從庫(kù)開(kāi)啟只讀堕花,不允許人為寫(xiě)入
    定期進(jìn)行主從一致性檢驗(yàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末文狱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缘挽,更是在濱河造成了極大的恐慌瞄崇,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壕曼,死亡現(xiàn)場(chǎng)離奇詭異苏研,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)腮郊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門摹蘑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人轧飞,你說(shuō)我怎么就攤上這事衅鹿。” “怎么了过咬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵大渤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我掸绞,道長(zhǎng)泵三,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任衔掸,我火速辦了婚禮烫幕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘具篇。我一直安慰自己纬霞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布驱显。 她就那樣靜靜地躺著诗芜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埃疫。 梳的紋絲不亂的頭發(fā)上伏恐,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音栓霜,去河邊找鬼翠桦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的销凑。 我是一名探鬼主播丛晌,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼斗幼!你這毒婦竟也來(lái)了澎蛛?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蜕窿,失蹤者是張志新(化名)和其女友劉穎谋逻,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體桐经,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡毁兆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阴挣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片气堕。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖畔咧,靈堂內(nèi)的尸體忽然破棺而出送巡,到底是詐尸還是另有隱情,我是刑警寧澤盒卸,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布骗爆,位于F島的核電站,受9級(jí)特大地震影響蔽介,放射性物質(zhì)發(fā)生泄漏摘投。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一虹蓄、第九天 我趴在偏房一處隱蔽的房頂上張望犀呼。 院中可真熱鬧,春花似錦薇组、人聲如沸外臂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)宋光。三九已至,卻和暖如春炭菌,著一層夾襖步出監(jiān)牢的瞬間罪佳,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工黑低, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赘艳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蕾管,于是被迫代替她去往敵國(guó)和親枷踏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容