Amazon和Mysql之间的那点事儿
摘要
本文主要介绍了亚马逊RDS的使用过程中发现的问题以及基于亚马逊EC2实例自己搭建Mysql服务器的一些经验。
mysql遇上AWS初始
公司项目初始,就使用了亚马逊的各项云服务,亚马逊的各项服务真的非常棒,大大简化了公司产品的扩容和运维工作。
之前公司使用亚马逊的EC2实例,一切都非常好。随着业务的扩展,客户需要mysql关系型数据库,为了使用方便,我们选了亚马逊提供的RDS服务,这玩意儿就是那么简单,选个mysql版本,直接就部署好了,什么my.cnf 文件,那是啥?我不关心啊。
开始运行的挺好,各种方便,还能动态制作一个主机的镜像实例,真是简单又省心。
随着用户量的增加,高可用和负载均衡提上了日程。
高可用?很简单啊,亚马逊的RDS高可用跟用户没关系,他自己内部都冗余好了,亚马逊系统自己准备的slave会顶上去的;负载均衡,嗯,这有点麻烦,我找找资料。
深入
亚马逊提供了一个通用的ELB模块,来动态分配访问落到哪台RDS上,但两台RDS的数据一致性怎么解决呢?
mysql社区版本并不提供集群服务,也就是说实际上在很多mysql系统中,并没有官方的负载均衡的解决方案,这就意味着,如果要从系统层面解决,必须使用第三方工具,或者通过用户的应用代码来完成。现在RDS就是提供一个数据库链接,所有系统工具都不能用。
第三方系统工具用不了,那么让用户改代码?这岂不是和我们的目标冲突了?我们的目标就是让用户能够零修改就能使用我们服务。
于是,我们分析了RDS的状况。
优点:
- 简单易用
- 自动高可用
- 定期有snapshot
缺点:
- 缺乏系统级的数据库管理界面
- 没有root权限
- …(不说了)
缺点的第一和第二两点,足以让我们放弃RDS的应用了。
这难道就是一言不合就开撕?呵呵,并不是,如果亚马逊的RDS能交出root权限,能解决数据同步,读写分离,负载均衡,动态迁移… 。嗯,我们还会是好朋友的 ☺。
弃坑挖新坑
好了言归正传,我们转手搞了3台EC2实例,搭了三个mysql,一主两丛,结构是1常主,一备主,一永从。
这很好理解了,2台做主的,性能比较好,一台永从的,只做数据备份用,按照一定的时间间隔备份数据到S3服务器上。
这里要介绍一个熟悉mysql都会知道的专门搞mysql,扩展mysql的大牛公司:PERCONA。写下这个几个字母的时候,俺的心情是激动的,所以都是大写的。
大家都知道mysql的存储引擎现在主流的有两种MyISAM和INNODB,其中的差别我们不说,只说数据备份,MyISAM的备份很简单,拷贝复制; INNODB的备份就扯了,用mysqldump 命令对数据库进行蹂躏。有时还会偶尔疏忽,漏了个参数,咋办?vi打开sql文件改几十,几百个地方?还是再来重复蹂躏一下,再dump一遍?Oh my god,太痛苦了,想想就是一场噩梦。
一方有难八方支援之一
Percona华丽丽的给出了一份在线热备的工具XtraBackup。这真是mysql admin的居家旅行,XXXX的利器啊,老鸟可以不用在意,小鸟同学们,你们可要好好的掌握这一大杀器啊!
XtraBackup在运行期间,不锁库,不锁库,不锁库。重要的事情说三遍,光这个优势就可以弃用mysqldump了。
还有什么增量备份,差异备份,单库备份恢复等等,犹如瑞士军刀,总有一件适合你。
下面给三条命令:
- 备份(备份的时候不需要停服务,如果是主库,用户是无感的)
innobackupex --defaults-file=/etc/my.cnf --user='root' --password='xxxxx' /opt/data/abcd --no-timestamp
注:/opt/data/abcd 是指定数据库备份输出的目录, --no-timestamp让工具不要主动生成时间戳目录
- 恢复
innobackupex --user=root --default-file=/etc/my.cnf --apply-log /opt/data/abcd
innobackupex --user=root --default-file=/etc/my.cnf --copy-back /opt/data/abcd
注1:以上是两条命令
注2:恢复之前,需要停mysql服务,删除mysql的data目录下的所有数据,恢复完之后,需要执行命令chown –R 命令把mysql data目录改为mysql:mysql ,之后启动mysql 服务。
Xtrabackup输出的数据目录会有一个文件,里面记录了bin-log文件的序号和position位置,也就是说,我们在执行Xtrabackup命令进行备份的时候,此时输出的数据,是和此文件序号中的position位置的log记录相匹配的。(如果你搭建过主从,就会明白,否则就会认为我在胡言乱语。)
想要深入了解Xtrabackup是怎么干的,可以去看下[Mysql技术内幕-InnoDB存储引擎]。
有了这个工具,搭建主从不要太方便。
先找台做主服务的EC2,搭个mysql。
装下google的半同步插件(写到这里,不禁想到,RDS不知道是用的是啥,难道是异步同步)
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
把REPLICATION SLAVE和REPLICATION CLIENT都搞上,然后就能用Xtrabackup来一式两份了。
GRANT REPLICATION SLAVE ON *.* to 'xxx'@'%' identified by 'xxx';
GRANT REPLICATION CLIENT ON *.* to 'xxx'@'%' identified by 'xxx';
把Xtrabackup输出的目录打个包,scp到两台从机上,恢复并启动mysql服务之后,执行命令:
CHANGE MASTER TO MASTER_HOST='xxx',master_port=3306,master_user='xxx',master_password='xxx',master_log_file='xxx',master_log_pos=xxx;
命令中的xxx各不相同哦,各位谨慎。
master_log_file='xxx',master_log_pos=xxx; 这两个数据可以从xtrabackup_binlog_pos_innodb 文件中获取。
然后在mysql命令行下 show slave status\G; 看下主从复制的情况,就万事OK了!
一方有难八方支援之二
既然搭建了主从,那么MHA也是必须的。
MHA项目地址 https://code.google.com/p/mysql-master-ha/
虽然这个项目许久没有更新,不过历史证明还是蛮可靠的。
我曾经做过一个无负载测试,搞了1600多次,每次都在10-15秒之内顺利切换完成。如果你的服务器能停止mysql服务1600多次,那我还能说什么呢?
MHA一般配合Keepalived 给App提供一个唯一可用的mysql链接ip,一旦MHA脚本检测到mysql 服务中断,可以自己写脚本,中断目标服务器的keepalived服务,这样VIP就漂移到新的服务器上,继续提供服务了。
但是我们架设在亚马逊EC2实例上的mysql服务器为了安全起见都是跨网段的,Keepalived不支持,实现不了啊。还好天无绝人之路,EC2实例提供了辅助私有ip的功能,用AWS命令为主服务器添加一个辅助私有IP,并且把原来的辅助私有IP回收掉,不就可以了吗?
想到就干。
回收:
aws ec2 unassign-private-ip-addresses --network-interface-id xxx --private-ip-addresses $VIP
添加:
aws ec2 assign-private-ip-addresses --network-interface-id xxx --private-ip-addresses $VIP --allow-reassignment
之后我们看下MHA提供的代码:
打开文件master_ip_failover 这是用perl写的(写到这里,又情不自禁的想到了,谁说perl不行了,系统管理处处是perl啊!):
GetOptions(
'command=s' => \$command,
'orig_master_host=s' => \$orig_master_host,
'orig_master_ip=s' => \$orig_master_ip,
'orig_master_port=i' => \$orig_master_port,
'orig_master_user=s' => \$orig_master_user,
'orig_master_password=s' => \$orig_master_password,
'new_master_host=s' => \$new_master_host,
'new_master_ip=s' => \$new_master_ip,
'new_master_port=i' => \$new_master_port,
'new_master_user=s' => \$new_master_user,
'new_master_password=s' => \$new_master_password,
);
这串代码蛮关键,是上游代码调用该脚本时传进来的参数,这些参数也蛮好理解,望文生意的。通过这些拿到的ip,帐号,就能上服务器去折腾一下,重新分配IP到备主上,这样就能很方便的完成常主->备主的切换了。
再看下MHA的配置脚本:
[server default]
user=xxx
password=xxx
repl_user=xxx
ssh_user=xxx
master_binlog_dir=/opt/mysql
remote_workdir=/var/log/masterha
secondary_check_script= masterha_secondary_check -s x.x.x.x -s x.x.x.x -s x.x.x.x
ping_interval=3
master_ip_failover_script=/mha4mysql/script/master_ip_failover_app1
report_script= /mha4mysql/script/send_report
[server1]
candidate_master=1
hostname=x.x.x.x
[server2]
candidate_master=1
hostname=x.x.x.x
[server3]
no_master=1
hostname=x.x.x.x
需要解释下的包括:
secondary_check_script= masterha_secondary_check -s x.x.x.x -s x.x.x.x -s x.x.x.x
mha检查机制,内置的,咱不用管,只要接着填写-s 后面的ip就好了,有几个就填几个。
ping_interval=3
俗语说叫采样间隔,放这儿就叫探测间隔吧。
master_ip_failover_script=/mha4mysql/script/master_ip_failover_app1
failover时执行的脚本,做一些IP回收,分配啥的,主从强制数据同步,以及最新数据源挑选等在主服务器拒绝服务之后,MHA内置脚本帮我们都搞定了,我们也不要care了。(我们这里不用选,就一个 ☺)
report_script= /mha4mysql/script/send_report
这个也挺关键,failover之后发送邮件通知,要不数据库少了一个服务,你还不知道,那不是扯淡么。
后台Daemon运行:
nohup masterha_manager --conf=/etc/app1.cnf < /dev/null >> /var/log/masterha/app1.log 2>&1 &
好了,一套可靠的mysql服务就搭好了。
那么各位要说了,MHA搞定了,那负载均衡呢?
呃~ 各位等我喝口水,且听下回分解吧,哈哈!
作者信息
作者系 MaxLeap 团队_Service&Infra 成员:Kevin, 喜欢开发一些小脚本来协助流程建设。