目前我們使用的是主從+分庫分表的系統架構,主庫有N個分庫,從庫為多個slave做負載均衡,所以數據庫端的架構是下面這樣的:

因為差不多有一年半沒有專門搞技術為主了,順帶回顧下。
這就涉及到多個主庫數據同步到不分庫分表的從庫共查詢和管理類系統使用。在mysql 5.6以及之前的版本中,沒有原生的解決方法,除非使用mariadb分支,在mysql 5.7之后支持多源復制,除了使用原生的多源復制之外,還有一個選擇,就是使用案例開源的otter/canal。如果只是N個庫合並到一個庫的,我們使用mysql原生的復制,因為無論從穩定性還是運維成本、系統要求的角度,mysql復制都合理的多。對於需要特殊處理比較多的或者目標庫為oracle的,我們使用otter/canal。文本講述mysql多源的搭建。下一文中,我們會講述完整的otter環境搭建並進行簡單的性能測試。
首先安裝mysql 5.7,推薦使用percona server,相關參數優化推薦等請參考mysql安裝以及配置參數優化。
因為環境限制,兩個主節點在同一台機器,從節點另外一台機器。
172.28.1.97 3307 主1
172.28.1.97 3308 主2
10.20.24.89 3308 從
同時172.28.1.97 3308 主2有三個database,ta_1,ta_2,ta_base,均同步到從庫的ta庫。
和mysql一主一從復制相比,多源復制加入了一個叫做Channel的概念, 每一個Channel都是一個獨立的Slave,都有一個IO_THREAD和SQL_THREAD。原理和普通復制一樣。我們只需要對每一個Master執行Change Master 語句,只需要在每個語句最后使用For Channel來進行區分。多源復制和正常主從其他的配置都一樣,基本上主庫開下binlog、server-id不一樣就可以了,只有下列額外限制:
- master-info-repository必須為TABLE
- relay-log-info-repository必須為TABLE
- 以FOR CHANNEL 'CHANNEL_NAME'區分不同的master。
首先參考mysql單機版安裝mysql 5.7安裝與參數優化,下列為slave直接相關的參數,在/etc/my.cnf中額外或者修改下列參數:
master-info-repository=TABLE relay-log-info-repository=TABLE # replicate-rewrite-db 多庫同步到單庫,庫名重寫,其他的replicate-*會在replicate-rewrite-db評估后執行,多個映射的話,配置文件中包含多行即可,這個設計好傻,為啥不逗號或者分號分隔呢。如果同時有多個replicate*過濾器,先評估數據庫級別的、然后表級別的;先評估do,后評估ignore(也就是在白名單或者不在黑名單的模式)。比如,主庫多個分庫合並到從庫一個庫 replicate-rewrite-db=ta_base->ta replicate-rewrite-db=ta_1->ta replicate-rewrite-db=ta_2->ta sync_relay_log=1 relay_log_recovery=1 slave-parallel-type=LOGICAL_CLOCK slave-parallel-workers=16 #具體值多少合適需要性能測試得到,一般cpu數量即可 server-id = 2 replicate-do-db # 如果只要同步某些庫 replicate-ignore-db #如果只需要不同步某些庫 slave-skip-errors=ddl_exist_errors + 1022 #建議不要同步ddl(1007,1008,1050,1051,1054,1060,1061,1068,1094,1146,1022) log_slave_updates=ON(GTID模式必須開始log_slave_updates,對性能有一定影響,Mysql 5.7之后從節點可以不開啟binlog) skip-slave-start=false #默認false,也就是server重啟的時候會自動啟動slave,不建議修改
啟動mysql服務器。
MySQL [(none)]> SET GLOBAL master_info_repository = 'TABLE'; Query OK, 0 rows affected (0.00 sec) MySQL [(none)]> SET GLOBAL relay_log_info_repository = 'TABLE'; Query OK, 0 rows affected (0.00 sec) -- 注:不同於設置全局變量,所有這些通過change master修改的信息都有存儲在performance_schema的replication相關表中,重啟后不會失效,復制連接信息存儲在performance_schema庫的replication_connection_configuration表中,IO線程當前狀態在replication_connection_status。SQL線程的配置和狀態分別在replication_applier_configuration和replication_applier_status表。 所有這些通過change/replication修改的信息都有存儲在performance_schema的replication相關表中,重啟后會失效,一定要同時保存到配置文件中 MySQL [(none)]> CHANGE MASTER TO MASTER_HOST='172.18.1.97',MASTER_PORT=3307,MASTER_USER='repl', MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=1834 FOR CHANNEL 'Master_3307'; Query OK, 0 rows affected, 2 warnings (0.03 sec) MySQL [(none)]> CHANGE MASTER TO MASTER_HOST='172.18.1.97',MASTER_PORT=3308,MASTER_USER='repl', MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000002',MASTER_LOG_POS=7484 FOR CHANNEL 'Master_3308'; Query OK, 0 rows affected, 2 warnings (0.01 sec) MySQL [(none)]> start slave for channel 'Master_3307'; Query OK, 0 rows affected (0.00 sec) MySQL [(none)]> start slave for channel 'Master_3308'; Query OK, 0 rows affected (0.01 sec) MySQL [(none)]> show slave status for channel 'Master_3307'\G; *************************** 1. row *************************** Slave_IO_State: Connecting to master Master_Host: 172.18.1.97 Master_User: repl Master_Port: 3307 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 1834 Relay_Log_File: slave-relay-bin-master_3307.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Connecting Slave_SQL_Running: Yes Replicate_Do_DB: ta 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: 1834 Relay_Log_Space: 154 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: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 2003 Last_IO_Error: error connecting to master 'repl@172.18.1.97:3307' - retry-time: 60 retries: 1 Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 0 Master_UUID: 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: 180703 08:23:54 Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: (ta_base,ta),(ta_1,ta),(ta_2,ta) Channel_Name: master_3307 Master_TLS_Version: 1 row in set (0.00 sec) ERROR: No query specified MySQL [(none)]> show slave status for channel 'Master_3308'\G; *************************** 1. row *************************** Slave_IO_State: Connecting to master Master_Host: 172.18.1.97 Master_User: repl Master_Port: 3308 Connect_Retry: 60 Master_Log_File: mysql-bin.000002 Read_Master_Log_Pos: 7484 Relay_Log_File: slave-relay-bin-master_3308.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000002 Slave_IO_Running: Connecting Slave_SQL_Running: Yes Replicate_Do_DB: ta 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: 7484 Relay_Log_Space: 154 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: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 2003 Last_IO_Error: error connecting to master 'repl@172.18.1.97:3308' - retry-time: 60 retries: 1 #這里是因為后來網斷了,前面忘了截圖下來 Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 0 Master_UUID: 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: 180703 08:23:58 Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: (ta_base,ta),(ta_1,ta),(ta_2,ta) Channel_Name: master_3308 Master_TLS_Version: 1 row in set (0.00 sec) ERROR: No query specified MySQL [(none)]> exit Bye
其他注意點
- mysql僅支持實例級別設置計數器的步長,通過auto_increment_increment參數控制,這樣分庫分表的時候,自增表的auto_increment就需要區分開從1還是2開始。
- 在mysql 8.0之前,global參數在重啟之后就會失效,所以對於可以動態修改的全局參數,需要同時修改my.cnf配置文件確保重啟后保持一致。
- 如果主庫是雙節點,還需要有個監控程序監控主庫,便於宕機后自動切換到另外一個節點,具體實現根據基於日志點位、GTID的不同而不同(有需求可留站內信,可提供同時監控並自動重啟rabbitmq、es、tomcat、spring boot、mysql復制、redis、zk、otter manager的守護程序)。
參考
https://blog.csdn.net/qustdjx/article/details/26937325/
http://yoshinorimatsunobu.blogspot.com/2013/10/making-full-table-scan-10x-faster-in.html
https://www.cnblogs.com/zhoujinyi/p/5704567.html
MySQL 5.7並行復制實現原理與調優
https://www.oschina.net/translate/showdown-mysql-8-vs-postgresql-10
https://aws.amazon.com/cn/about-aws/whats-new/2017/12/amazon-aurora-with-mysql-compatibility-speeds-query-processing-with-hash-join-and-batched-scans/
https://blog.csdn.net/chenhaifeng2016/article/details/77530569
