AWS RDS Mysql数据库做主库与外部Mysql从库进行复制
最近在帮一用户迁移mysql,用户使用复制功能可以将数据从AWS RDS MySQL 5.6 数据库实例导出到在外部运行的 MySQL 实例,在该过程中RDS Mysql实例将作为主库与外部的Mysql从库建立复制关系。外部的 MySQL可在数据中心内本地运行,也可在 Amazon EC2 实例上运行。RDS MySQL 数据库实例必须运行 5.6.13 版或更高版本。本文将介绍如何建立这种复制关系的步骤,并且指出可能由RDS实例本身特性而容易导致的一些错误,对于准备使用aws rds但又不知道如何选择配置来说,下边提供一些常用的配置方便大家做参考。
Amazon RDS价格一览
本文尝试通过一些直观的数据和表格,来看看Amazon某个规格的RDS实例到底是什么价格以及如何计费。
亚马逊RDS计费分为两个主要的部分,一个是“实例费用”(CPU和内存),另一个是“存储费用”(磁盘容量和IOPS)。这两类资源的费用,又细 分为单可用区和多可用区,另外,还可以选择“按小时计费”、又或者是“包年计费”的方式购买,这些对价格都有很大影响。本文分多个部分细致介绍了亚马逊如 何计算一个RDS实例的价格。
“实例费用”
“基本规格”
基本规格根据CPU和内存使用来划分,Amazon RDS有如下基本规格:
根据实际的应用场景,选择你需要的规格。
“按小时付费”与“包年付费”
对于上面这些基本规格,你可以“按小时付费”付费,还可以选择“包年付费”。包年的方式,非常便宜,基本上只有前者的一半的价格。
“单可用区”与“多可用区”
可以简单的理解为,实例是否有一个备库。如果是单可用区,那么实例没有备库,实例故障时,用户只能从备份中恢复数据,如果实例很大,恢复的时间可能 会很长;如果是多可用区,则Amazon会为你构建一个同步备库,主实例发生故障时,Amazon会自动为你切换到备库上。多可用区实例的备份是发生在备 库上,不会影响主库的实例;而单可用区实例在备份的时候,IO则可能会又很大的影响。
当然多可用区价格也更贵,多可用区的价格则恰好是单可用区的两倍,下面是一个参考价格列表:
“存储费用”
确定好了实例,接下来要做的是选择存储。存储有三个选项:“通用存储/SSD”、“预留IOPS的存储/SSD”、“传统磁盘”。另外,对于单可用区和多可用区存储的价格也是不一样的。
通用存储/SSD
“通用存储/SSD”:只会按照存储空间的大小来计费,范围是5GB到3TB,价格比较便宜。这类存储,不会按照IOPS计费,存储到底提供多少IOPS,Amazon也没有明确说明。
预留IOPS的存储/SSD
“预留IOPS的存储/SSD”:这类则是明确定义IOPS能力的存储,容量范围是100GB到3TB,IOPS能力从1000到30000,你可以根据自由选择。这类存储的计费分两项来独立计费,容量按照每GB计费;IOPS按照每一个IOPS多少钱来计费。
传统磁盘
“传统磁盘”:存储容量的价格相对便宜,但是IOPS却更贵。适合IOPS低,但是空间容量要求大的应用。
存储费用对比
详细费用列表可以参考价格列表页面,但是这个页面中的数据并不直观。下面我们来看一个具体的场景,如果购买一个多可用区的150GB的SSD磁盘,同时购买1000IOPS,存储对应的价格会是什么水平:
这样就清晰了一些。
总览
有了实例价格和存储价格,那么就可以计算一个完整的RDS实例价格了,比如,我们这里计算一个使用2颗vCPU,15GB内存,150GB存储空 间,1000IOPS的实例,因为是打算用于生产环境,所以这里选择的是多可用区,并计划使用一年,那我们看看这样的实例一个月多少钱呢?
有了上面这些计算和表格,我们对亚马逊RDS的价格就有了一个比较直观、清晰的认识了。
账单
下面是一个按小时实例的参考账单,刚刚建立实例不久:
本文部分名词对照表
AWS RDS Mysql数据库作为主从复制(Master-Slave)中的主库(Master)
在AWS RDS的文档中并没有刻意提到RDS Mysql可以作为主库与外部Mysql数据库建立长期稳定的复制关系,而只是在文档中“使用复制功能导出 Amazon RDS MySQL 5.6 数据”这部分提到了可以利用这种复制关系来将RDS中的数据导出到外部数据库。网上能找到一篇具体操作的文章,见参考资料,文章教大家Step by Step建立这种复制关系。但是由于AWS RDS本身的一些特性(限制),按文章中的方法操作可能会出现一些其他问题。
总之,在日常的数据库结构中,将AWS RDS Mysql作为主从复制中主库,将外部Mysql数据库作为从库的方法并不是Amazon官方文档中明确推荐的。请谨慎组建这样的复制关系,因为你并不能有权限来完全操作RDS Mysql实例的管理。
在下文中会将如何建立这种复制关系的步骤做具体描述,供大家参考。并且指出一些可能由RDS实例本身特性而出现的错误。
详细步骤
1 创建RDS Mysql 数据库实例
在AWS文档(中文,英文)中以图文并茂的形式详细描述了如何创建一个RDS Mysql实例,在本文中不再重复。
本文中选择的数据库版本为5.6.21,数据库名称为awsgood, 用户名为awsgood, 密码为awsgood.com。
在RDS实例启动完成后,可以用Mysql客户端命令连接其终端节点(endpoint)并登录:
$ mysql -hawsgood.cmscpiuewome.rds.cn-north-1.amazonaws.com.cn -uawsgood -pawsgood.com
Server version: 5.6.21-log MySQL Community Server (GPL)
Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.
mysql>
其中awsgood.cmscpiuewome.rds.cn-north-1.amazonaws.com.cn为数据库实例的终端节点,命名方式是数据库实例名+与AWS账户相关的随机字符串+rds+区域endpoint端点名。
2 创建外部Mysql数据库
外部Mysql数据库可以在任何位置的Linux系统中启动。本文选择将外部非RDS数据库创建在AWS EC2上,操作系统使用默认的Amazon Linux。Amazon Linux可以利用yum repository来下载和管理软件的依赖关系。
利用yum info命令查看可用的mysql版本:
$ yum info mysql
Loaded plugins: priorities, update-motd, upgrade-helper
4 packages excluded due to repository priority protections
Available Packages
Name : mysql
Arch : noarch
Version : 5.5
Release : 1.6.amzn1
Size : 2.7 k
Repo : amzn-main/latest
Summary : MySQL meta package
URL : http://www.mysql.com
License : GPLv2 with exceptions
Description : MySQL is a multi-user, multi-threaded SQL database server. MySQL is a
: client/server implementation consisting of a server daemon (mysqld)
: and many different client programs and libraries. The base package
: contains the standard MySQL client programs and generic MySQL files.
由上可知Amazon的yum repository中最新的版本为Mysql 5.5,而我们需要用等于或者高于5.6.21 (RDS Mysql版本)的Mysql,才能作为其从库(Slave)。
在Mysql官方文档中介绍了如何利用MySQL Yum repository来安装最新GA版本Mysql的方法(文章写作时最新的GA版本是MySQL 5.6)。
$ sudo yum localinstall http://repo.mysql.com/mysql-community-release-el6-5.noarch.rpm
利用yum repolist enable命令检查MySQL yum repository被成功地添加进来。
$ yum repolist enabled | grep “mysql.*-community.*”
!mysql-connectors-community/x86_64 MySQL Connectors Community 8+4
!mysql-tools-community/x86_64 MySQL Tools Community 18
!mysql56-community/x86_64 MySQL 5.6 Community Server 95
添加了MySQL yum repository后,利用下面的命令安装Mysql 5.6版本。
$ sudo yum install mysql mysql-server
$ sudo chgrp -R mysql /var/lib/mysql
$ sudo chmod -R 770 /var/lib/mysql
$ sudo service mysqld start
$ sudo mysqladmin -u root password mypass
查看Mysql的版本:
$ mysql –version
mysql Ver 14.14 Distrib 5.6.21, for Linux (x86_64) using EditLine wrapper
EC2上安装的Mysql与RDS Mysql的版本相同,可以形成一个Master-Slave关系。
3 在RDS Mysql实例上将其配置为主库(Master)
3.1 确认RDS上的binlog已经被打开
mysql> show variables like ‘log_bin’;
+—————+——-+
| Variable_name | Value |
+—————+——-+
| log_bin | ON |
+—————+——-+
1 row in set (0.00 sec)mysql> show master status;
+—————————-+———-+————–+——————+——————-+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+—————————-+———-+————–+——————+——————-+
| mysql-bin-changelog.015493 | 120 | | | |
+—————————-+———-+————–+——————+——————-+
1 row in set (0.00 sec)
3.2 创建并授权可以来读取日志文件的用户
mysql> CREATE USER ‘repluser’@’%’ IDENTIFIED BY ‘replpass’;
Query OK, 0 rows affected (0.17 sec)mysql> GRANT REPLICATION SLAVE ON *.* TO ‘repluser’@’%’;
Query OK, 0 rows affected (0.01 sec)
3.3 利用上一步创建和授权的账号,用mysqlbinlog来测试查看binlog,如下可以成功:
$ mysqlbinlog -h awsgood.cmscpiuewome.rds.cn-north-1.amazonaws.com.cn -u repluser -preplpass –read-from-remote-server -t mysql-bin-changelog.015493
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
……
CREATE USER ‘repluser’@’%’ IDENTIFIED BY PASSWORD ‘*D98280F03D0F78162EBDBB9C883FC01395DEA2BF’
/*!*/;
# at 280
#141123 16:00:43 server id 1056411688 end_log_pos 407 Query thread_id=1333 exec_time=0 error_code=0
SET TIMESTAMP=1416758443/*!*/;
GRANT REPLICATION SLAVE ON *.* TO ‘repluser’@’%’
/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
在此处可能会出现如下错误:
Got fatal error 1236 from master when reading data from binary log: ‘Could not find first log file name in binary log index file’
如果出现,则需要利用show master status命令查看最新的binlog文件,有可能已经切换成mysql-bin-changelog.015494。再利用mysqlbinlog命令重新执行,-t参数后面跟上最新的binlog文件。
关于这个错误,是由RDS本身的机制导致的,具体原因和较好的解决方法请参看后文中的“RDS Mysql特性及常见问题”部分。
4 将EC2上的Mysql数据库配置为从库(Slave)
4.1 在配置文件/etc/my.cnf的[mysqld]下面加入以下几行:
[mysqld] log-bin=mysql-bin
server_id=2 # server-id 可以选在为 1 到(2的32次方–1)之间的整数
relay_log=mysql-relay-bin
log_slave_updates=1
read_only=1
replicate-ignore-db=mysql
4.2 重启mysql服务
$ sudo service mysqld restart
4.3 在Slave数据库上指定并连接Master
在RDS主库上利用show master status来查看最新的binlog文件和位置,例如分别为mysql-bin-changelog.015496和120。
则在Slave数据库上用如下命令连接RDS Master:
mysql>CHANGE MASTER TO
-> MASTER_HOST=’awsgood.cmscpiuewome.rds.cn-north-1.amazonaws.com.cn’,
-> MASTER_USER=’repluser’,
-> MASTER_PASSWORD=’replpass’,
-> MASTER_LOG_FILE=’mysql-bin-changelog.015496′,
-> MASTER_LOG_POS=120;
4.4 开始复制
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
4.5 查看slave的复制状态
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: test1.cmscpiuewome.rds.cn-north-1.amazonaws.com.cn
Master_User: repluser
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin-changelog.015496
Read_Master_Log_Pos: 120
Relay_Log_File: mysql-relay-bin.000004
Relay_Log_Pos: 566
Relay_Master_Log_File: mysql-bin-changelog.015496
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB: mysql
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: 410
Relay_Log_Space: 775
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: 0
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: 1056411688
1 row in set (0.00 sec)
5 测试同步
在RDS Master Mysql上
mysql> create database testdb;
Query OK, 1 row affected (0.06 sec)mysql> use testdb
Database changed
mysql> create table test (id int, string varchar(100));
Query OK, 0 rows affected (0.24 sec)
在EC2 Mysql上查看testdb和test table是否都已经同步过来
mysql> use testdb
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -ADatabase changed
mysql> show tables;
+——————+
| Tables_in_testdb |
+——————+
| test |
+——————+
1 row in set (0.00 sec)mysql> show create table test\G
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`id` int(11) DEFAULT NULL,
`string` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
由上面的测试结果可知,在Master上建立的数据库和表成功已经同步到Slave上。
RDS Mysql特性及常见问题
1 binglog特性
如果按照上文的步骤执行,很有可能会遇到的一个问题就是:
Got fatal error 1236 from master when reading data from binary log: ‘Could not find first log file name in binary log index file’
因为RDS Mysql设计的理念就是过几分钟就将binlog切换(rorate),而不是等到到达最大size时才做切换。并且在完成切换后,会将旧的 binlog文件即时上传到Amazon S3中进行存储,并将实例上的binlog文件清除。所以在外部的Slave来指定RDS Master的binlog文件和位置时,可能很容易发生无法找到文件的报错。
RDS提供了存储过程mysql.rds_set_configuration给用户,功能是修改binlog文件在RDS实例中的保留时间,以小时为单位,在AWS RDS文档中进行了说明。
下例将保留期设置为 1 天,并查看修改结果:
mysql> call mysql.rds_set_configuration(‘binlog retention hours’, 24);
Query OK, 0 rows affected (0.00 sec)mysql> call mysql.rds_show_configuration\G
*************************** 1. row ***************************
name: binlog retention hours
value: 24
description: binlog retention hours specifies the duration in hours before binary logs are automatically deleted.
1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)
利用修改RDS的保留时间,可以很大程度上避免找不到binlog的报错。
2 mysql数据库
在上面的详细步骤中,配置从库my.cnf时加上了语句replicate-ignore-db=mysql,表示在复制时不复制数据库mysql 中的内容。这样配置的目的是因为RDS Mysql数据库中存在一些RDS特有的表,这些表在普通的Mysql数据库中可能不存在,如果直接将RDS Mysql中的mysql库与外部Mysql的mysql库复制,可能会导致如下报错:
Last_SQL_Error: Error ‘Table ‘mysql.rds_heartbeat2′ doesn’t exist’ on query. Default database: ”. Query: ‘INSERT INTO mysql.rds_heartbeat2(id, value) values (1,1416392460255) ON DUPLICATE KEY UPDATE value = 1416392460255′
从上面的报错可知,外部的Mysql数据库并没有rds_heartbeat2表,从而导致复制关系失败。
参考资料
http://www.ruempler.eu/2013/07/07/replicating-aws-rds-mysql-databases-to-external-slaves/