1. 程式人生 > >Amazon和Mysql之間的那點事兒

Amazon和Mysql之間的那點事兒

初始

公司專案初始,就使用了亞馬遜的各項雲服務,亞馬遜的各項服務真的非常棒,大大簡化了公司產品的擴容和運維工作。

之前公司使用亞馬遜的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記錄相匹配的。(如果你搭建過主從,就會明白,否則就會認為我在胡言亂語)

有了這個工具,搭建主從不要太方便。先找臺做主服務的EC2,搭個mysql,裝下google的半同步外掛:

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也是必須的。

我曾經做過一個無負載測試,搞了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 &