mysql主從之半同步復制和lossless無損復制


一 MySQL 的三種復制方式

1.1 簡介

asynchronous 異步復制

fully synchronous 全同步復制

Semisynchronous 半同步復制

從MySQL5.5 開始,MySQL 以插件的形式支持半同步復制。

 

1.2 異步復制(Asynchronous replication)

 

MySQL 默認的復制是異步的,主庫在執行完客戶端提交的事務后會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理,這樣就會有一個問題,主如果crash 掉了,此時主上已經提交的事務可能並沒有傳到從上,如果此時,將從提升為主,可能導致新主上的數據不完整。

原理:在異步復制中,master 寫數據到binlog 且sync,slave request binlog 后寫入relay‐log 並flush disk

優點:復制的性能最好

缺點:master 掛掉后,slave 可能會丟失數據

1.3 全同步復制(Fully synchronous replication)

指當主庫執行完一個事務,所有的從庫都執行了該事務才返回給客戶端。因為需要等待所有從庫執行完該事務才能返回,所以全同步復制的性能必然會收到嚴重的影響。

優點:數據不會丟失

缺點:會阻塞master session,性能太差,非常依賴網絡

1.4 半同步復制(Semisynchronous replication)

介於異步復制和全同步復制之間,主庫在執行完客戶端提交的事務后不是立刻返回給客戶端,而是等待至少一個從庫接收到並寫到relay log 中才返回給客戶端。相對於異步復制,半同步復制提高了數據的安全性,同時它也造成了一定程度的延遲,這個延遲最少是一個TCP/IP 往返的時間。所以,半同步復制最好在低延時的網絡中使用。

優點:會有數據丟失風險(低)

缺點:會阻塞master session,性能差,非常依賴網絡,由於master 是在三段提交的最后commit 階段完成后才等待,所以master 的其他session 是可以看到這個提交事務的,所以這時候master 上的數據和slave 不一致,master crash 后,slave 數據丟失。

1.5 增強版的半同步復制(lossless replication)

原理: 在半同步復制中,master 寫數據到binlog 且sync,然后一直等待ACK. 當至少一個slave request bilog 后寫入到relay‐log 並flush disk,就返回ack(不需要回放完日志)

優點:數據零丟失(前提是讓其一直是lossless replication),

性能好

缺點:會阻塞master session,非常依賴網絡由於master 是在三段提交的第二階段sync binlog 完成后才等待, 所以master 的其他session 是看不見這個提交事務的,所以這時候master 上的數據和slave 一致,master crash 后,slave 沒有丟失數據

二 實驗

2.1 查看plugins

mysql> show plugins;
+----------------------------+----------+--------------------+---------+---------+
| Name                       | Status   | Type               | Library | License |
+----------------------------+----------+--------------------+---------+---------+
| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL    | GPL     |
| sha256_password            | ACTIVE   | AUTHENTICATION     | NULL    | GPL     |
| CSV                        | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL    | GPL     |
| MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| MRG_MYISAM                 | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL    | GPL     |
| partition                  | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
| ngram                      | ACTIVE   | FTPARSER           | NULL    | GPL     |
+----------------------------+----------+--------------------+---------+---------+

或者查詢INFORMATION_SCHEMA.PLUGINS 表

[root@master1 ~]# cd /usr/lib64/mysql/plugin/

[root@master1 plugin]# ll

-rwxr-xr-x. 1 root root   103728 Apr 13 10:36 adt_null.so
-rwxr-xr-x. 1 root root   356976 Apr 13 10:36 authentication_ldap_sasl_client.so
-rwxr-xr-x. 1 root root    43552 Apr 13 10:36 auth_socket.so
-rwxr-xr-x. 1 root root   940312 Apr 13 10:36 connection_control.so
drwxr-xr-x. 2 root root     4096 Jul  3 11:31 debug
-rwxr-xr-x. 1 root root 21640312 Apr 13 10:36 group_replication.so
-rwxr-xr-x. 1 root root   483520 Apr 13 10:36 ha_example.so
-rwxr-xr-x. 1 root root   968432 Apr 13 10:36 innodb_engine.so
-rwxr-xr-x. 1 root root   957088 Apr 13 10:36 keyring_file.so
-rwxr-xr-x. 1 root root   460064 Apr 13 10:36 keyring_udf.so
-rwxr-xr-x. 1 root root  1184680 Apr 13 10:36 libmemcached.so
-rwxr-xr-x. 1 root root  8973984 Apr 13 10:36 libpluginmecab.so
-rwxr-xr-x. 1 root root    21424 Apr 13 10:36 locking_service.so
-rwxr-xr-x. 1 root root    53928 Apr 13 10:36 mypluglib.so
-rwxr-xr-x. 1 root root    41088 Apr 13 10:36 mysql_no_login.so
-rwxr-xr-x. 1 root root 22243648 Apr 13 10:37 mysqlx.so
-rwxr-xr-x. 1 root root    49504 Apr 13 10:36 rewrite_example.so
-rwxr-xr-x. 1 root root   590936 Apr 13 10:36 rewriter.so
-rwxr-xr-x. 1 root root   933904 Apr 13 10:36 semisync_master.so    #主庫安裝
-rwxr-xr-x. 1 root root   159928 Apr 13 10:36 semisync_slave.so     #備庫安裝
-rwxr-xr-x. 1 root root   209520 Apr 13 10:36 validate_password.so
-rwxr-xr-x. 1 root root   506320 Apr 13 10:36 version_token.so

2.2 主庫配置

查看是否支持動態加載的MySQL 服務器

mysql> show variables like '%dynamic%';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| have_dynamic_loading | YES   |
+----------------------+-------+
1 row in set (0.00 sec)

mysql> install plugin rpl_semi_sync_master  soname 'semisync_master.so';   #安裝庫
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%rpl_semi%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | OFF        |     #修改為on狀態
| rpl_semi_sync_master_timeout              | 10000      |     #修改為1s
| 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 |
+-------------------------------------------+------------+

修改my.cnf

[root@master1 ~]# vim /etc/my.cnf

rpl_semi_sync_master_enabled = 1
rpl_semi_sync_master_timeout = 1000

[root@master1 ~]# systemctl restart mysqld

mysql> show variables like '%rpl_semi%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 1000       |
| 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 |
+-------------------------------------------+------------+
mysql> show status like '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 0     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 0     |
| Rpl_semi_sync_master_no_times              | 0     |
| Rpl_semi_sync_master_no_tx                 | 0     |
| Rpl_semi_sync_master_status                | ON    |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     |
| Rpl_semi_sync_master_tx_waits              | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 0     |
+--------------------------------------------+-------+

rpl_semi_sync_master_timeout

一個以毫秒為單位的值,用於控制主服務器等待來自從服務器的確認提交並恢復到異步復制的時間,超過這個值就是超時。 默認值是10000(10 秒)。超時之后,就從半同步復制,返回到異步復制。

Rpl_semi_sync_master_yes_tx:從庫成功確認的提交數量。

Rpl_semi_sync_master_no_tx:從庫未成功確認的提交數量。

2.3 備份服務器配置

mysql> show variables like '%dynamic%';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| have_dynamic_loading | YES   |
+----------------------+-------+
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
mysql> show variables like '%rpl_semi%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | OFF   |     #打開為on
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+

修改my.cnf

[root@slave ~]# vim  /etc/my.cnf

rpl_semi_sync_slave_enabled = 1

[root@slave ~]# systemctl restart mysqld

mysql> show variables like '%rpl_semi%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled     | ON    |
| rpl_semi_sync_slave_trace_level | 32    |
+---------------------------------+-------+
mysql> show status like '%semi%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+

2.4 主庫驗證

mysql> show status like '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 2     |
| Rpl_semi_sync_master_no_times              | 1     |
| Rpl_semi_sync_master_no_tx                 | 1     |
| Rpl_semi_sync_master_status                | ON    |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     |
| Rpl_semi_sync_master_tx_waits              | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 0     |
+--------------------------------------------+-------+
mysql> insert   into  test values (2);
mysql> insert   into  test values (2);
mysql> insert   into  test values (2);
mysql> show status like '%semi%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 1     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 5     |
| Rpl_semi_sync_master_no_times              | 1     |
| Rpl_semi_sync_master_no_tx                 | 1     |
| Rpl_semi_sync_master_status                | ON    |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 1013  |
| Rpl_semi_sync_master_tx_wait_time          | 3041  |
| Rpl_semi_sync_master_tx_waits              | 3     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 3     |    #增加數據.這個之會增加
+--------------------------------------------+-------+

從端數據已經同步

mysql> select * from master1.test;
+------+
| id   |
+------+
|    1 |
|    2 |
|    2 |
|    2 |
+------+

2.5 測試AFTER_SYNC 和AFTER_COMMIT

主庫設置超時時間為1000 秒,備庫停掉復制,模擬timeout

mysql> set global rpl_semi_sync_master_timeout=1000000;
mysql> stop slave;
mysql> insert   into  test values (11);   #會一直卡住

mysql> select * from master1.test;
+------+
| id   |
+------+
|    1 |
|    2 |
|    2 |
|    2 |
+------+

重啟主庫數據庫,模擬主庫宕機,從看數據記錄

[root@master1 ~]# systemctl start mysqld
[root@master1 ~]# mysql -uroot -p123456
mysql> select * from master1.test;
+------+
| id   |
+------+
|    1 |
|    2 |
|    2 |
|    2 |
|   11 |   #主庫有記錄
+------+

備庫開啟slave

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

mysql> select * from master1.test;
+------+
| id   |
+------+
|    1 |
|    2 |
|    2 |
|    2 |
|   11 |     #數據已經同步,沒有丟失
+------+

無損的半同步復制是在write binlog 之后。需要得到備庫的確認。所以這時候主庫宕機,不會發生丟數據。當主庫啟動后,插入的數據重新可見。

將rpl_semi_sync_master_wait_point 設置為AFTER_COMMIT,

再次測試:

主庫設置超時時間為1000 秒,備庫停掉復制,模擬timeout

mysql> set global rpl_semi_sync_master_wait_point=AFTER_COMMIT;
mysql> set global rpl_semi_sync_master_timeout=1000000;
mysql> show variables like '%semi%';
+-------------------------------------------+--------------+
| Variable_name                             | Value        |
+-------------------------------------------+--------------+
| rpl_semi_sync_master_enabled              | ON           |
| rpl_semi_sync_master_timeout              | 1000000      |
| 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_COMMIT |
+-------------------------------------------+--------------+
mysql> insert into master1.test values (12); #一直卡住
[root@master1 ~]# mysql -uroot -p123456 #另開一個窗口,發現已經有12這個數據 mysql> select * from master1.test; +------+ | id | +------+ | 1 | | 2 | | 2 | | 2 | | 11 | | 12 | +------+

這樣當從庫起來之后,數據已經提交,從庫就會缺少這個數據

再開一個窗口查詢這條數據,發現可以查詢到。這時候主庫宕機,會發生數據丟失。

主庫重新啟動,備庫啟動slave 會同步到備庫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM