通過主從復制機制完成MySQL數據庫服務遷移
0x00 背景
業務所在機房裁撤,原業務機器也已經過保,通過MySQL主從復制機制完成MySQL數據服務的無縫遷移。
0x01 准備
1.環境:
原則上搭建mysql主從復制最好是操作系統版本、環境,MySQL版本、配置保持一致,這樣可以保證MySQL主從集群的穩定性,以及減少版本和環境造成的異常,便於排查和定位問題。
由於我們涉及遷移的機器往往是很久以前上線,而且也從未有相關系統和服務升級的機制,還好這次涉及的MySQL版本比較高,與MySQL 5.6的兼容性還是比較好的,謝天謝地,謝前任。
原機器環境:
IP:A(機器已回收)
系統版本:suse 11 linux x64
mysql版本:mysql 5.5.3
配置文件路徑:無
程序啟動方式:/bin/sh /usr/local/mysql/bin/mysqld_safe &
新機器環境:
IP:xxxxxx B
系統版本: tlinux 1.2 64bit(centos 6.2)
mysql版本:mysql-5.6.25
配置文件路徑: /etc/my.cnf
程序啟動方式: /etc/init.d/mysqld start
2.安裝包准備
源碼包下載:
cmake:yum install cmake (2.6.4) 即可 或 下載 https://cmake.org/files/v3.3/cmake-3.3.2.tar.gz
MySQL :http://dev.mysql.com/downloads/mysql/5.6.html#downloads
0x02 MySQL安裝與配置
1.安裝(這裡不是本文重點,如果出錯了,需要根據錯誤分析解決)
原則上,運營環境一般推薦通過源碼進行編譯安裝,這樣才能充分利用當前機器的特性,但是由於我們以前在相同系統環境下編譯安裝並制作了相關部署包,所以真實安裝過程就略過了。這裡的安裝過程是我們一般通用的安裝過程:
a. yum 安裝
yum install mysql mysql-server (推薦tlinux2.0,對應centos 7.0,fedora 20+)
很不幸,tilnux 1.2環境 yum安裝的版本為mysql-5.1.61,老掉牙了。
b. 源碼編譯安裝
cd mysql-5.6.25groupadd mysql
useradd -g mysql mysql -s /bin/false
mkdir -p /data/dbdata
chown mysql:mysql /data/dbdata
cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/data/dbdata -DSYSCONFDIR=/etc/
make&&make install
cp /usr/local/mysql/support-files/my-default.cnf /etc/my.cnf
cd /usr/local/
mv mysql mysql-5.6.25 && ln -s mysql-5.6.25 mysql
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chmod +x /etc/init.d/mysqld
chkconfig --add mysqld
chkconfig mysqld on
初始化mysql:
/usr/local/mysql/scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/data/dbdata
vi /etc/profile
增加:export PATH=$PATH:/usr/local/mysql/bin
/etc/init.d/mysqld start
2.配置
舊機器:
登錄 mysql服務終端:
設置server id:
set gloabl server_id=2;select @@server_id;
開啟binlog:
SET SQL_LOG_BIN=1;
SET GLOBAL binlog_format = 'MIXED'; ##表結構變更以statement模式來記錄,update或者delete等修改數據的語句是記錄所有行的變更。
mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 2 |
+-------------+
1 row in set (0.00 sec)
新機器:
vi /etc/my.cnf
log-bin = /data/dbdata/binlog/mysql-binbinlog_format = MIXED
binlog_cache_size = 4M
max_binlog_cache_size = 1024M
max_binlog_size = 1024M
expire_logs_days = 5log-slave-updates
server-id = 20151109
mysql> select @@server_id;+-------------+
| @@server_id |+-------------+
| 20151109 |
+-------------+1 row in set (0.00 sec)
0x03 數據的導出與導入
1.數據導出:
涉及的DB不多,DB的讀寫不頻繁,導出mysql數據我們選擇使用mysqldump。
因為要添加主從信息,所以需要添加-master-data=1,附帶鎖表操作,當表的存儲引擎為InnoDB時,加了 --single-transaction 可以減少鎖表的影響,准確的說只會有短時間的全局讀鎖,比MyISAM的鎖表情況要好得多。
mysqldump -u root --default-character-set=utf8 -Y -B --set-charset --single-transaction --master-data=1 hehehehhe > /data/backup/databases/hehehehhe20151109.sql
CHANGE MASTER
-Y, --all-tablespaces
Dump all the tablespaces.
-B, --databases Dump several databases. Note the difference in usage; in
if you dump many databases at once (using the option
--databases= or --all-databases), the logs will be
Locks all tables across all databases. This is achieved
--all-databases or --databases is given.
--master-data[=#] This causes the binary log position and filename to be
appended to the output. If equal to 1, will print it as a
CHANGE MASTER command; if equal to 2, that command will
be prefixed with a comment symbol. This option will turn
--lock-all-tables on, unless --single-transaction is
specified too (in which case a global read lock is only
taken a short time at the beginning of the dump; don't
forget to read about --single-transaction below). In all
cases, any action on logs will happen at the exact moment
of the dump. Option automatically turns --lock-tables
off.
--dump-slave[=#] This causes the binary log position and filename of the
master to be appended to the dumped data output. Setting
the value to 1, will printit as a CHANGE MASTER command
in the dumped data output; if equal to 2, that command
will be prefixed with a comment symbol. This option will
turn --lock-all-tables on, unless --single-transaction is
specified too (in which case a global read lock is only
taken a short time at the beginning of the dump - don't
forget to read about --single-transaction below). In all
cases any action on logs will happen at the exact moment
of the dump.Option automatically turns --lock-tables off.
--include-master-host-port
Adds 'MASTER_HOST=<host>, MASTER_PORT=<port>' to 'CHANGE
MASTER TO..' in dump produced with --dump-slave.
--single-transaction
Creates a consistent snapshot by dumping all tables in a
single transaction. Works ONLY for tables stored in
storage engines which support multiversioning (currently
only InnoDB does); the dump is NOT guaranteed to be
consistent for other storage engines. While a
--single-transaction dump is in process, to ensure a
valid dump file (correct table contents and binary log
position), no other connection should use the following
statements: ALTER TABLE, DROP TABLE, RENAME TABLE,
TRUNCATE TABLE, as consistent snapshot is not isolated
from them. Option automatically turns off --lock-tables.
--set-charset Add 'SET NAMES default_character_set' to the output.
(Defaults to on; use --skip-set-charset to disable.)
查看主從信息:
[root@WEBAPP_B_IP_HOST /data/backup/databases]#
自帶切換主從同步點命令,需要注意的是添加此命令時需要將所有主從同步狀態的數據庫數據一同導出。
grep CHANGE /data/backup/databases/hehehehhe20151109.sql
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=120;
2.數據導入:
新機器:
CREATE DATABASE `hehehehhe` /*!40100 DEFAULT CHARACTER SET utf8 */;
搭建主從同步後stop slave,直接通過mysql 直接導入數據,然後在start slave即可。
0x04 主從復制配置與數據的同步
1. MySQL binlog
binlog是MySQL主從復制的基礎,MySQL通過binlog來記錄數據庫數據的變更,可用來搭建主從復制集群,也可以用mysqlbinlog來通過binlog恢復部分數據異常。
如果遇到災難事件,應該用最近一次制作的完整備份恢復數據庫,然後使用備份之後的日志文件把數據庫恢復到最接近現在的可用狀態。使用日志進行恢復時需要依次進行,即最早生成的日志文件要最先恢復。
常用binlog日志操作命令
1.查看所有binlog日志列表
mysql> show master logs;(新機器作為主時,binlog的信息)
[root@WEBAPP_B_IP_HOST /data/dbdata/binlog]# pwd/data/dbdata/binlog
[root@WEBAPP_B_IP_HOST /data/dbdata/binlog]# lltotal 884156-rw-rw---- 1 mysql admin 27317 Nov 9 12:41 mysql-bin.000001-rw-rw---- 1 mysql admin 1034478 Nov 9 12:41 mysql-bin.000002-rw-rw---- 1 mysql admin 531 Nov 9 12:42 mysql-bin.000003-rw-rw---- 1 mysql admin 903407219 Nov 12 00:10 mysql-bin.000004-rw-rw---- 1 mysql admin 148 Nov 9 15:08 mysql-bin.index
[root@WEBAPP_B_IP_HOST /data/dbdata/binlog]# mysql -e "show master logs;"+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 27317 |
| mysql-bin.000002 | 1034478 |
| mysql-bin.000003 | 531 |
| mysql-bin.000004 | 903407219 |
+------------------+-----------+
2.查看master狀態,即最後(最新)一個binlog日志的編號名稱,及其最後一個操作事件pos結束點(Position)值
mysql> show master status;(新機器作為從時,主服務器最新binlog的位置信息)
[root@WEBAPP_B_IP_HOST /data/dbdata/binlog]# mysql -e "show master status;"+------------------+-----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+-----------+--------------+------------------+-------------------+
| mysql-bin.000004 | 903407219 | | | |
+------------------+-----------+--------------+------------------+-------------------+
3.刷新log日志,自此刻開始產生一個新編號的binlog日志文件
mysql> flush logs;
mysql> flush logs;
Query OK, 0 rows affected (0.00 sec)
mysql> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 27317 |
| mysql-bin.000002 | 1034478 |
| mysql-bin.000003 | 531 |
| mysql-bin.000004 | 903407266 |
| mysql-bin.000005 | 120 |
+------------------+-----------+5 rows in set (0.00 sec)
注:每當mysqld服務重啟時,會自動執行此命令,刷新binlog日志;在mysqldump備份數據時加 -F 選項也會刷新binlog日志;
4.重置(清空)所有binlog日志
mysql> reset master;
mysql> reset master;
Query OK, 0 rows affected (0.08 sec)
mysql> show master logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 120 |
+------------------+-----------+1 row in set (0.00 sec)
清空當前機器的binlog。
5.清理
清除binlog
PURGE {MASTER|BINARY} LOGS TO 'log_name' //log_name不會被清除
PURGE {MASTER|BINARY} LOGS BEFORE 'date' //date不會被清除
2. 主從復制配置
1)舊機器(主A_IP)上創建主從同步帳號:
grant replication slave on *.* to 'rep'@'B_IP' identified by 'heheheh';
2)查看當前舊機器(主A_IP)的binlog狀態
mysql> show master status;+------------------+----------+--------------+------------------+-------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 120 | | | |
+------------------+----------+--------------+------------------+-------------------+1 row in set (0.00 sec)
3)在新機器(B_IP)上創建主從同步
mysql> change master to master_host='A_IP',
master_user='rep',
master_password='heheheh',
master_port=3306,
master_log_file='mysql-bin.000001',
master_log_pos=120,
master_connect_retry=10;
參數詳解:
master_host:主服務器的IP。
master_user:配置主服務器時建立的用戶名
master_password:用戶密碼
master_port:主服務器mysql端口,如果未曾修改,默認即可。
master_log_file:日志文件名稱,填寫查看master狀態時顯示的Filemaster_log_pos:日志位置,填寫查看master狀態時顯示的Positionmaster_connect_retry:重連次數
4)啟動進程
mysql> start slave;
查看主從同步情況:
主要需要關注Slave_IO_Running: YES; Slave_SQL_Running: YES;Seconds_Behind_Master: 0
mysql> show slave status \G;*************************** 1. row ***************************
Slave_IO_State:
Master_Host: A_IPMaster_User: rep
Master_Port: 3306Connect_Retry: 60Master_Log_File: Tencent64-bin.000164Read_Master_Log_Pos: 107Relay_Log_File: WEBAPP_B_IP_HOST-relay-bin.000006Relay_Log_Pos: 270Relay_Master_Log_File: Tencent64-bin.000164Slave_IO_Running: YES
Slave_SQL_Running: YES
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0Last_Error:
Skip_Counter: 0Exec_Master_Log_Pos: 107Relay_Log_Space: 786Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
主從信息查看的命令:
show slave hosts \G;主機上查看從機信息
show master status\G;主機上查看狀態信息
show slave status \G;從機上查看主從狀態信息
0x05 存儲過程與權限的導入
1.存儲過程和函數的導出
由於存儲過程和數據庫權限信息存儲在mysql庫中,通過mysqldump普通參數是不會導出的。
導出存儲過程: mysqldump 加 -R (或 --routines)參數即可。
-R, --routines Dump stored routines (functions and procedures).
Add 'SET @@GLOBAL.GTID_PURGED' to the output. Possible @@GLOBAL.GTID_PURGED' is added to the output. If GTIDs
statements: ALTER TABLE, DROP TABLE, RENAME TABLE,
TRUNCATE TABLE, as consistent snapshot is not isolated
單獨導出存儲過程等內容:
mysqldump -uroot -n -d -t -R hehehehhe > procedure_name.sql
-- MySQL dump 10.10--
-- Host: localhost Database: hehehehhe
-- ------------------------------------------------------
-- Server version 5.5.3-m3-log
後期也發現,如果在導出時mysqldump指定 --databases 會自動將原DB的創建語句添加進去,但是有的時候我們希望自己指定DB創建語句,比如要指定默認字符集為utf8,而原來的用的是latin1,這個時候我們就不需要加這個參數了。
2.數據庫權限的導出與導入
數據庫的權限有針對全局的也有針對特定庫和表的權限,無法直接導出再導入。
主要通過查出舊機器授權過的帳號和機器IP,在通過show grants語句來獲取相應權限。
mysql> SELECT CONCAT("show grants for ",user,"@",host,";") from mysql.user;
+----------------------------------------------+
| CONCAT("show grants for ",user,"@",host,";") |
+----------------------------------------------+
| show grants for
[email protected]; || show grants for
[email protected]; || show grants for
[email protected]; || show grants for
[email protected]; || show grants for
[email protected]; || show grants for
[email protected]; || show grants for root@::1; || show grants for
[email protected]; || show grants for root@localhost; |+----------------------------------------------+9 rows in set (0.00 sec)
然後將show grants語句放到腳本中,運行腳本獲取到舊機器上相關授權信息。
最後,在新機器上運行之前獲得的授權信息腳本,即可導入相關權限。
注意,這裡可能出現報錯,數據庫不存在的情況下將相關權限導入,所以在導入前需要過濾下。
0x06 數據校驗與業務驗證
數據校驗和業務驗證不是我們要講的重點,但是是數據庫遷移不可缺少的一部分。
驗證數據的方式有兩種:
1.查看數據記錄與主從同步狀態,可以簡單快速判斷,但是不是最准確的。
2.通過跑腳本,校驗數據庫下每個表的checksum值,准確,可能會有些慢。
3.通過Percona Toolkit for MySQL 工具中pt-table-checksum來進行主從校驗.
0x07 常見問題分析與解決
1. MyIsam存儲引擎 鎖表導致服務中斷,影響到業務。
之前與互娛的兄弟在RTX溝通,備份數據時MyISAM鎖表時間過久導致服務出現異常,所以我們一般建議搭建專門的備機進行備份數據,以及盡量用INNODB存儲引擎。
2.數據校驗時,用percona的工具發現數據不一致,處理數據時發現自增ID發生變化,通過自增ID查不到指定的業務數據
數據不一致時優先使用pt-table-sync進行修復,但是這個修復方式是缺少時插入,沖突時replace,自增ID會發生變化。
建議自增ID不要作為業務屬性使用。
3.占坑,未完待續,歡迎一起續寫。
0x08 其他
一切皆有可能,在實驗環境多去實踐會降低出問題時空手無策的幾率。
還好這次遷移MySQL版本比較高,要是碰到5.0或5.1那就坑死了。
感謝Percona,讓一個二把手也可以保障mysql服務的穩定性。
感謝國家,感謝父母。
感謝一起討論問題的你們。