爲什麼需要主從複製?
-
在業務複雜的系統中,有這麼一個情景,有一句sql語句需要鎖表,導致暫時不能使用讀的服務,那麼就很影響運行中的業務,使用主從複製,讓主庫負責寫,從庫負責讀,這樣,即使主庫出現了鎖表的情景,通過讀從庫也可以保證業務的正常運作。
-
做數據的熱備
-
架構的擴展。業務量越來越大,I/O訪問頻率過高,單機無法滿足,此時做多庫的存儲,降低磁盤I/O訪問的頻率,提高單個機器的I/O性能。
什麼是mysql的主從複製?
MySQL 主從複製是指數據可以從一個MySQL數據庫服務器主節點複製到一個或多個從節點。MySQL 默認採用異步複製方式,這樣從節點不用一直訪問主服務器來更新自己的數據,數據的更新可以在遠程連接上進行,從節點可以複製主數據庫中的所有數據庫或者特定的數據庫,或者特定的表。
mysql複製原理
-
master服務器將數據的改變記錄二進制binlog日誌,當master上的數據發生改變時,則將其改變寫入二進制日誌中;
-
slave服務器會在一定時間間隔內對master二進制日誌進行探測其是否發生改變,如果發生改變,則開始一個I/OThread請求master二進制事件
-
同時主節點爲每個I/O線程啓動一個dump線程,用於向其發送二進制事件,並保存至從節點本地的中繼日誌中,從節點將啓動SQL線程從中繼日誌中讀取二進制日誌,在本地重放,使得其數據和主節點的保持一致,最後I/OThread和SQLThread將進入睡眠狀態,等待下一次被喚醒。
也就是說
- 從庫會生成兩個線程,一個I/O線程,一個SQL線程;
- I/O線程會去請求主庫的binlog,並將得到的binlog寫到本地的relay-log(中繼日誌)文件中;
- 主庫會生成一個log dump線程,用來給從庫I/O線程傳binlog;
- SQL線程,會讀取relay log文件中的日誌,並解析成sql語句逐一執行;
MySQL主從形式:
mysql主從同步延時分析
mysql的主從複製都是單線程的操作,主庫對所有DDL和DML產生的日誌寫進binlog,由於binlog是順序寫,所以效率很高,slave的sql thread線程將主庫的DDL和DML操作事件在slave中重放。DML和DDL的IO操作是隨機的,不是順序,所以成本要高很多,另一方面,由於sql thread也是單線程的,當主庫的併發較高時,產生的DML數量超過slave的SQL thread所能處理的速度,或者當slave中有大型query語句產生了鎖等待,那麼延時就產生了。
解決方案:
-
業務的持久化層的實現採用分庫架構,mysql服務可平行擴展,分散壓力。
-
單個庫讀寫分離,一主多從,主寫從讀,分散壓力。這樣從庫壓力比主庫高,保護主庫。
-
服務的基礎架構在業務和mysql之間加入memcache或者redis的cache層。降低mysql的讀壓力。
-
不同業務的mysql物理上放在不同機器,分散壓力。
-
使用比主庫更好的硬件設備作爲slave,mysql壓力小,延遲自然會變小。
-
使用更加強勁的硬件設備
參考原址:https://zhuanlan.zhihu.com/p/96212530
部署
-
Windows系統的 MySQL配置文件在:你安裝MySQL的目錄下的 my.ini 文件下
-
Linux系統的 MySQL配置文件在:/etc/my.cnf
-
Docker-MySQL鏡像的在:/etc/mysql/my.cnf
這裏我們使用 linux環境 和 Docker來實現主從複製 一主多從(也就一個從)
當然 你也可以在一臺服務器上部署多臺 MySQL
部署準備:
-
Linux 上安裝好 mysql
https://blog.csdn.net/weixin_44685869/article/details/103937654 -
docker拉取 MySQL鏡像 並 生成容器
docker pull mysql:5.7 docker run -p 3307:3306 --name mysql02 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 # -dit是啓動新的實例,這樣的話就沒法保存 使用它的目的就是爲了避免 剛啓動容器就以外的退出 # 我們還可以在後面加上 tail -f xxx.log /bin/bash 防止意外退出 docker start mysql02
正式開工
-
在主 數據庫配置
vim /etc/my.cnf [mysqld] server-id = 1 # 數據庫編號 binlog-do-db=mysql01 # 選擇備份的數據庫 這句也可以在 從機器上寫 # binlog-do-db=test1 log-bin=mysql-bin # 通過bin日誌 方式實現主從複製 binlog_format=maixed # 二進制日誌的格式,一共有三種 statement/row/mixed # binlog-ignore-db=mysql # 忽略主從 的數據庫
修改完重啓 MySQL
service mysqld restart
-
重啓後 進入MySQL查看是否生效
mysql> show variables like 'server_id'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 1 | +---------------+-------+ 1 row in set (0.00 sec)
-
Master數據庫創建數據同步用戶,授予用戶 slave REPLICATION SLAVE權限和REPLICATION CLIENT權限,用於在主從庫之間同步數據。 這裏的操作呢,其實就是像創建一個鑰匙,讓從服務器連接。
創建一個允許從服務器來訪問的用戶(主服務器):
mysql> create user 'slave'@'%' identified by 'mysql'; mysql> grant replication slave, replication client on *.* to 'slave'@'%'; mysql> flush privileges; or mysql> grant replication slave on *.* to 'slave'@'%' identified by 'mysql'; mysql> flush privileges;
說明:
slave: Slave 使用的帳號 用戶名 identified by 'mysql': Slave 使用的密碼 %: Slave 數據庫IP ,%代表所有的IP
如果你用的是兩臺服務器,那麼你的 從服務器 也需要開啓
最後我們也可以設置只讀模式,來實現 讀寫分離
-
master端,通過
show master status;
顯示信息。mysql> show master status\G *************************** 1. row *************************** File: mysql-bin.000002 Position: 154 Binlog_Do_DB: mysql01 Binlog_Ignore_DB: Executed_Gtid_Set: 1 row in set (0.00 sec) mysql> mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000002 | 154 | mysql01 | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)
兩種方法查看都是一個意思,只不過是查看的內容格式不一樣
參數 | 描述 |
---|---|
File | MySQL bin-log文件 |
Position | 因爲之前我們用過MySQL,所以 bin-log日誌是有內容呢。開啓同步需要用到 154行以後的內容 |
Binlog_Do_DB | 你的從數據庫 |
Binlog_Ignore_DB | 不被主從的 數據庫 |
Executed_Gtid_Set | 執行事務集合 |
使用Navicat 查看機器是否可以遠程連接。
主機器OK,下面開始配置從機器
-
進入dockerMySQL容器,也就是我們的 從機器
[root@izbp1izjo7pl5ccghnbdiuz ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 446d7cf1606c mysql:5.7 "docker-entrypoint.s…" 15 hours ago Up 15 hours 3306/tcp, 33060/tcp, 127.0.0.1:3307->3636/tcp mysql02 [root@izbp1izjo7pl5ccghnbdiuz ~]# [root@izbp1izjo7pl5ccghnbdiuz ~]# docker exec -it 446d7cf1606c bash
-
修改 配置文件
vim /etc/mysql/my.cnf
vim 異常 請 ↓
docker容器中 bash: vi: command not found,docker apt-get 異常 Temporary failure resolving[mysqld] # 設置server_id,注意要唯一 server-id=2 # 開啓二進制日誌功能,以備Slave作爲其它Slave的Master時使用 log-bin=mysql-slave-bin # mysql-bin # relay_log配置中繼日誌 relay_log=edu-mysql-relay-bin
配置完成後也需要重啓mysql服務和docker容器,
service mysqld restart docker restart mysql02
-
在Slave 中進入 mysql,執行
CHANGE master to master_host='47.96.158.77', master_user='slave', master_password='mysql', master_port=3306, master_log_file='mysql-bin.000001', master_log_pos= 154, master_connect_retry=60;
master_host | Master的地址,指的是容器的獨立ip,可以通過 docker inspect --format=’{{.NetworkSettings.IPAddress}}’ 容器名稱|容器id 查詢容器的ip |
---|---|
↑ 圖解 | |
master_port | Master的端口號,指的是容器的端口號 |
master_user | 用於數據同步的用戶 |
master_password | 用於同步的用戶的密碼 |
master_log_file | 指定 Slave 從哪個日誌文件開始複製數據,即上文中提到的 File 字段的值 |
master_log_pos | 從哪個 Position 開始讀,即上文中提到的 Position 字段的值 |
master_connect_retry | 如果連接失敗,重試的時間間隔,單位是秒,默認是60秒 |
-
進入 從機器的 mysql,開啓主從複製,查看同步信息
start slave # 開啓從機器 show slave status \G;
看見 yes就代表 一切ok了。 -
最後測試
測試主從複製方式就十分多了,最簡單的是在Master創建一個數據庫,然後檢查Slave是否存在此數據庫。
master:
slave:
當然我們也可以進行添加數據的測試,在主機器 上添加數據,從機器是 完全同步的。
但是,從機器上添加的數據 主機是不同步的
時間 | 主機 | 從機 |
---|---|---|
t1 | use test create table user(id int(4), name varchar(10)); insert user values (111,‘zhangsan’) select * from user; 結果:一條 |
此時數據完全同步 |
t2 | select * from user 結果:一條數據 |
|
t3 | insert user values (111,‘liis’) 結果:兩條數據 |
|
t4 | select * from user 結果:一條數據 |
-
所以爲了 避免此類的情況出現,我們要把 從機器設置成 只讀的權限
mysql> GRANT Select ON *.* TO reader@"%" INDENIFIED BY "123456"
這樣讀和寫就已經完全的 隔離開了。 這裏就不做演示了。
docker 部分參考 https://www.cnblogs.com/songwenjie/p/9371422.html