Như chúng ta đã thấy trước đó, có thể là một thách thức đối với các công ty khi chuyển dữ liệu của họ ra khỏi RDS cho MySQL. Trong phần đầu tiên của blog này, chúng tôi đã hướng dẫn bạn cách thiết lập môi trường đích của bạn trên EC2 và chèn một lớp proxy (ProxySQL) giữa các ứng dụng của bạn và RDS. Trong phần thứ hai này, chúng tôi sẽ chỉ cho bạn cách thực hiện việc di chuyển dữ liệu thực tế sang máy chủ của riêng bạn, sau đó chuyển hướng các ứng dụng của bạn đến phiên bản cơ sở dữ liệu mới mà không cần thời gian chết.
Sao chép dữ liệu ra khỏi RDS
Khi chúng ta có lưu lượng truy cập cơ sở dữ liệu của mình chạy qua ProxySQL, chúng ta có thể bắt đầu chuẩn bị sao chép dữ liệu của mình ra khỏi RDS. Chúng ta cần làm điều này để thiết lập bản sao giữa RDS và phiên bản MySQL của chúng ta đang chạy trên EC2. Khi điều này được thực hiện xong, chúng tôi sẽ định cấu hình ProxySQL để chuyển hướng lưu lượng truy cập từ RDS sang MySQL / EC2 của chúng tôi.
Như chúng ta đã thảo luận trong bài đăng blog đầu tiên của loạt bài này, cách duy nhất bạn có thể lấy dữ liệu ra khỏi RDS là thông qua kết xuất logic. Nếu không có quyền truy cập vào phiên bản, chúng tôi không thể sử dụng bất kỳ công cụ sao lưu vật lý nóng nào như xtrabackup. Chúng tôi cũng không thể sử dụng ảnh chụp nhanh vì không có cách nào để tạo bất kỳ thứ gì khác ngoài phiên bản RDS mới từ ảnh chụp nhanh.
Chúng tôi bị giới hạn ở các công cụ kết xuất hợp lý, do đó tùy chọn hợp lý sẽ là sử dụng mydumper / myloader để xử lý dữ liệu. May mắn thay, mydumper có thể tạo các bản sao lưu nhất quán để chúng tôi có thể dựa vào đó để cung cấp tọa độ binlog cho nô lệ mới của chúng tôi kết nối. Vấn đề chính trong khi tạo bản sao RDS là chính sách xoay vòng binlog - kết xuất và tải hợp lý có thể mất nhiều ngày thậm chí trên các tập dữ liệu lớn hơn (hàng trăm gigabyte) và bạn cần giữ các binlog trên phiên bản RDS trong suốt thời gian của toàn bộ quá trình này. Chắc chắn, bạn có thể tăng tỷ lệ lưu giữ luân phiên binlog trên RDS (gọi mysql.rds_set_configuration ('số giờ lưu giữ binlog', 24); - bạn có thể giữ chúng lên đến 7 ngày) nhưng làm theo cách khác sẽ an toàn hơn nhiều.
Trước khi tiến hành xử lý kết xuất, chúng tôi sẽ thêm một bản sao vào phiên bản RDS của mình.
Trang tổng quan Amazon RDS Tạo Replica DB trong RDSKhi chúng tôi nhấp vào nút “Tạo bản sao đã đọc”, một ảnh chụp nhanh sẽ được bắt đầu trên bản sao RDS “chính”. Nó sẽ được sử dụng để cung cấp nô lệ mới. Quá trình này có thể mất hàng giờ, tất cả phụ thuộc vào kích thước ổ đĩa, lần cuối cùng chụp ảnh nhanh là khi nào và hiệu suất của ổ đĩa (io1 / gp2? Magnetic? Một ổ đĩa có bao nhiêu pIOPS?).
Bản sao RDS chínhKhi nô lệ đã sẵn sàng (trạng thái của nó đã thay đổi thành “khả dụng”), chúng tôi có thể đăng nhập vào nó bằng cách sử dụng điểm cuối RDS của nó.
RDS SlaveSau khi đăng nhập, chúng tôi sẽ ngừng sao chép trên máy nô lệ của mình - điều này sẽ đảm bảo máy chủ RDS sẽ không xóa nhật ký nhị phân và chúng sẽ vẫn có sẵn cho máy chủ EC2 của chúng tôi sau khi chúng tôi hoàn tất quá trình kết xuất / tải lại.
mysql> CALL mysql.rds_stop_replication;
+---------------------------+
| Message |
+---------------------------+
| Slave is down or disabled |
+---------------------------+
1 row in set (1.02 sec)
Query OK, 0 rows affected (1.02 sec)
Bây giờ, cuối cùng đã đến lúc sao chép dữ liệu sang EC2. Đầu tiên, chúng ta cần cài đặt mydumper. Bạn có thể tải xuống từ github:https://github.com/maxbube/mydumper. Quá trình cài đặt khá đơn giản và được mô tả độc đáo trong tệp readme, vì vậy chúng tôi sẽ không trình bày ở đây. Nhiều khả năng bạn sẽ phải cài đặt một vài gói (được liệt kê trong readme) và phần khó hơn là xác định gói nào chứa mysql_config - nó phụ thuộc vào hương vị MySQL (và đôi khi cả phiên bản MySQL).
Khi bạn đã biên dịch mydumper và sẵn sàng hoạt động, bạn có thể thực thi nó:
[email protected]:~/mydumper# mkdir /tmp/rdsdump
[email protected]:~/mydumper# ./mydumper -h rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com -p tpccpass -u tpcc -o /tmp/rdsdump --lock-all-tables --chunk-filesize 100 --events --routines --triggers
.
Xin lưu ý - khóa-tất cả các bảng đảm bảo rằng ảnh chụp nhanh của dữ liệu sẽ nhất quán và có thể sử dụng nó để tạo nô lệ. Bây giờ, chúng ta phải đợi cho đến khi mydumper hoàn thành nhiệm vụ của nó.
Cần thực hiện thêm một bước nữa - chúng tôi không muốn khôi phục giản đồ mysql nhưng chúng tôi cần sao chép người dùng và các khoản tài trợ của họ. Chúng tôi có thể sử dụng pt-show-grants cho việc đó:
[email protected]:~# wget http://percona.com/get/pt-show-grants
[email protected]:~# chmod u+x ./pt-show-grants
[email protected]:~# ./pt-show-grants -h rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com -u tpcc -p tpccpass > grants.sql
Mẫu pt-show-grants có thể giống như sau:
-- Grants for 'sbtest'@'%'
CREATE USER IF NOT EXISTS 'sbtest'@'%';
ALTER USER 'sbtest'@'%' IDENTIFIED WITH 'mysql_native_password' AS '*2AFD99E79E4AA23DE141540F4179F64FFB3AC521' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK;
GRANT ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE USER, CREATE VIEW, DELETE, DROP, EVENT, EXECUTE, INDEX, INSERT, LOCK TABLES, PROCESS, REFERENCES, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SELECT, SHOW DATABASES, SHOW VIEW, TRIGGER, UPDATE ON *.* TO 'sbtest'@'%';
Bạn có quyền chọn những gì người dùng được yêu cầu để sao chép vào phiên bản MySQL / EC2 của bạn. Không có ý nghĩa gì nếu làm điều đó cho tất cả chúng. Ví dụ:người dùng root không có đặc quyền 'SUPER' trên RDS, vì vậy tốt hơn hết bạn nên tạo lại chúng từ đầu. Những gì bạn cần sao chép là các khoản trợ cấp cho người dùng ứng dụng của bạn. Chúng tôi cũng cần sao chép những người dùng được sử dụng bởi ProxySQL (trong trường hợp của chúng tôi là proxysql-monitor).
Chèn dữ liệu vào MySQL / EC2 Instance của bạn
Như đã nêu ở trên, chúng tôi không muốn khôi phục các giản đồ hệ thống. Do đó, chúng tôi sẽ di chuyển các tệp liên quan đến các lược đồ đó ra khỏi thư mục mydumper của chúng tôi:
[email protected]:~# mkdir /tmp/rdsdump_sys/
[email protected]:~# mv /tmp/rdsdump/mysql* /tmp/rdsdump_sys/
[email protected]:~# mv /tmp/rdsdump/sys* /tmp/rdsdump_sys/
Khi chúng ta làm xong, đã đến lúc bắt đầu tải dữ liệu vào phiên bản MySQL / EC2:
[email protected]:~/mydumper# ./myloader -d /tmp/rdsdump/ -u tpcc -p tpccpass -t 4 --overwrite-tables -h 172.30.4.238
Xin lưu ý rằng chúng tôi đã sử dụng bốn luồng (-t 4) - hãy đảm bảo rằng bạn đặt điều này thành bất kỳ điều gì có ý nghĩa trong môi trường của bạn. Tất cả là về việc bão hòa cá thể MySQL mục tiêu - CPU hoặc I / O, tùy thuộc vào nút cổ chai. Chúng tôi muốn tận dụng nó nhiều nhất có thể để đảm bảo rằng chúng tôi đã sử dụng tất cả các tài nguyên hiện có để tải dữ liệu.
Sau khi dữ liệu chính được tải, cần thực hiện thêm hai bước nữa, cả hai đều liên quan đến nội bộ RDS và cả hai đều có thể phá vỡ bản sao của chúng tôi. Đầu tiên, RDS chứa một vài bảng rds_ * trong lược đồ mysql. Chúng tôi muốn tải chúng trong trường hợp một số trong số chúng được sử dụng bởi RDS - quá trình sao chép sẽ bị hỏng nếu nô lệ của chúng tôi không có chúng. Chúng ta có thể thực hiện theo cách sau:
[email protected]:~/mydumper# for i in $(ls -alh /tmp/rdsdump_sys/ | grep rds | awk '{print $9}') ; do echo $i ; mysql -ppass -uroot mysql < /tmp/rdsdump_sys/$i ; done
mysql.rds_configuration-schema.sql
mysql.rds_configuration.sql
mysql.rds_global_status_history_old-schema.sql
mysql.rds_global_status_history-schema.sql
mysql.rds_heartbeat2-schema.sql
mysql.rds_heartbeat2.sql
mysql.rds_history-schema.sql
mysql.rds_history.sql
mysql.rds_replication_status-schema.sql
mysql.rds_replication_status.sql
mysql.rds_sysinfo-schema.sql
Vấn đề tương tự là với các bảng múi giờ, chúng tôi cần tải chúng bằng cách sử dụng dữ liệu từ phiên bản RDS:
[email protected]:~/mydumper# for i in $(ls -alh /tmp/rdsdump_sys/ | grep time_zone | grep -v schema | awk '{print $9}') ; do echo $i ; mysql -ppass -uroot mysql < /tmp/rdsdump_sys/$i ; done
mysql.time_zone_name.sql
mysql.time_zone.sql
mysql.time_zone_transition.sql
mysql.time_zone_transition_type.sql
Khi tất cả điều này đã sẵn sàng, chúng ta có thể thiết lập sao chép giữa RDS (chính) và cá thể MySQL / EC2 (nô lệ) của chúng ta.
Thiết lập nhân rộng
Mydumper, khi thực hiện kết xuất nhất quán, ghi lại vị trí nhật ký nhị phân. Chúng tôi có thể tìm thấy dữ liệu này trong một tệp có tên là siêu dữ liệu trong thư mục kết xuất. Hãy xem xét nó, sau đó chúng tôi sẽ sử dụng vị trí để thiết lập nhân rộng.
[email protected]:~/mydumper# cat /tmp/rdsdump/metadata
Started dump at: 2017-02-03 16:17:29
SHOW SLAVE STATUS:
Host: 10.1.4.180
Log: mysql-bin-changelog.007079
Pos: 10537102
GTID:
Finished dump at: 2017-02-03 16:44:46
Một điều cuối cùng chúng tôi thiếu là một người dùng mà chúng tôi có thể sử dụng để thiết lập nô lệ của mình. Hãy tạo một cái trên phiên bản RDS:
[email protected]:~# mysql -ppassword -h rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com
mysql> CREATE USER IF NOT EXISTS 'rds_rpl'@'%' IDENTIFIED BY 'rds_rpl_pass';
Query OK, 0 rows affected (0.04 sec)
mysql> GRANT REPLICATION SLAVE ON *.* TO 'rds_rpl'@'%';
Query OK, 0 rows affected (0.01 sec)
Bây giờ đã đến lúc nô lệ máy chủ MySQL / EC2 của chúng tôi khỏi phiên bản RDS:
mysql> CHANGE MASTER TO MASTER_HOST='rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com', MASTER_USER='rds_rpl', MASTER_PASSWORD='rds_rpl_pass', MASTER_LOG_FILE='mysql-bin-changelog.007079', MASTER_LOG_POS=10537102;
Query OK, 0 rows affected, 2 warnings (0.03 sec)
mysql> START SLAVE;
Query OK, 0 rows affected (0.02 sec)
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Queueing master event to the relay log
Master_Host: rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com
Master_User: rds_rpl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin-changelog.007080
Read_Master_Log_Pos: 13842678
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 20448
Relay_Master_Log_File: mysql-bin-changelog.007079
Slave_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: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 10557220
Relay_Log_Space: 29071382
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: 258726
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1237547456
Master_UUID: b5337d20-d815-11e6-abf1-120217bb3ac2
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: System lock
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.01 sec)
Bước cuối cùng sẽ là chuyển lưu lượng của chúng ta từ phiên bản RDS sang MySQL / EC2, nhưng trước tiên chúng ta cần để nó bắt kịp.
Khi nô lệ đã bắt kịp, chúng ta cần thực hiện cắt bỏ. Để tự động hóa nó, chúng tôi quyết định chuẩn bị một tập lệnh bash ngắn sẽ kết nối với ProxySQL và thực hiện những việc cần phải làm.
# At first, we define old and new masters
OldMaster=rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com
NewMaster=172.30.4.238
(
# We remove entries from mysql_replication_hostgroup so ProxySQL logic won’t interfere
# with our script
echo "DELETE FROM mysql_replication_hostgroups;"
# Then we set current master to OFFLINE_SOFT - this will allow current transactions to
# complete while not accepting any more transactions - they will wait (by default for
# 10 seconds) for a master to become available again.
echo "UPDATE mysql_servers SET STATUS='OFFLINE_SOFT' WHERE hostname=\"$OldMaster\";"
echo "LOAD MYSQL SERVERS TO RUNTIME;"
) | mysql -u admin -padmin -h 127.0.0.1 -P6032
# Here we are going to check for connections in the pool which are still used by
# transactions which haven’t closed so far. If we see that neither hostgroup 10 nor
# hostgroup 20 has open transactions, we can perform a switchover.
CONNUSED=`mysql -h 127.0.0.1 -P6032 -uadmin -padmin -e 'SELECT IFNULL(SUM(ConnUsed),0) FROM stats_mysql_connection_pool WHERE status="OFFLINE_SOFT" AND (hostgroup=10 OR hostgroup=20)' -B -N 2> /dev/null`
TRIES=0
while [ $CONNUSED -ne 0 -a $TRIES -ne 20 ]
do
CONNUSED=`mysql -h 127.0.0.1 -P6032 -uadmin -padmin -e 'SELECT IFNULL(SUM(ConnUsed),0) FROM stats_mysql_connection_pool WHERE status="OFFLINE_SOFT" AND (hostgroup=10 OR hostgroup=20)' -B -N 2> /dev/null`
TRIES=$(($TRIES+1))
if [ $CONNUSED -ne "0" ]; then
sleep 0.05
fi
done
# Here is our switchover logic - we basically exchange hostgroups for RDS and EC2
# instance. We also configure back mysql_replication_hostgroups table.
(
echo "UPDATE mysql_servers SET STATUS='ONLINE', hostgroup_id=110 WHERE hostname=\"$OldMaster\" AND hostgroup_id=10;"
echo "UPDATE mysql_servers SET STATUS='ONLINE', hostgroup_id=120 WHERE hostname=\"$OldMaster\" AND hostgroup_id=20;"
echo "UPDATE mysql_servers SET hostgroup_id=10 WHERE hostname=\"$NewMaster\" AND hostgroup_id=110;"
echo "UPDATE mysql_servers SET hostgroup_id=20 WHERE hostname=\"$NewMaster\" AND hostgroup_id=120;"
echo "INSERT INTO mysql_replication_hostgroups VALUES (10, 20, 'hostgroups');"
echo "LOAD MYSQL SERVERS TO RUNTIME;"
) | mysql -u admin -padmin -h 127.0.0.1 -P6032
Khi tất cả hoàn tất, bạn sẽ thấy nội dung sau trong bảng mysql_servers:
mysql> select * from mysql_servers;
+--------------+-----------------------------------------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| hostgroup_id | hostname | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+-----------------------------------------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| 20 | 172.30.4.238 | 3306 | ONLINE | 1 | 0 | 100 | 10 | 0 | 0 | read server |
| 10 | 172.30.4.238 | 3306 | ONLINE | 1 | 0 | 100 | 10 | 0 | 0 | read server |
| 120 | rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com | 3306 | ONLINE | 1 | 0 | 100 | 10 | 0 | 0 | |
| 110 | rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com | 3306 | ONLINE | 1 | 0 | 100 | 10 | 0 | 0 | |
+--------------+-----------------------------------------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
Về phía ứng dụng, bạn sẽ không thấy nhiều ảnh hưởng, nhờ khả năng ProxySQL xếp hàng các truy vấn trong một thời gian.
Với điều này, chúng tôi đã hoàn thành quá trình chuyển cơ sở dữ liệu của bạn từ RDS sang EC2. Bước cuối cùng cần làm là xóa nô lệ RDS của chúng tôi - nó đã làm đúng công việc của mình và có thể xóa được.
Trong bài đăng blog tiếp theo của chúng tôi, chúng tôi sẽ xây dựng dựa trên điều đó. Chúng tôi sẽ xem xét một kịch bản trong đó chúng tôi sẽ chuyển cơ sở dữ liệu của mình ra khỏi AWS / EC2 thành một nhà cung cấp dịch vụ lưu trữ riêng biệt.