螞蟻搬家式遷移mysql數據庫
乘機房搬遷的機會,打算做一次業務整合。現有的架構是在2010年規劃並運營起來的,隨著時間的推移,項目也越來越多。打開nginx配置文件,有四十多行include包含存在,每一個包含就是一個項目(有些是web,有些是app)。一整個機櫃,老舊的設備,負載均衡高可用架構。為保證業務一致性和降低成本,業務數據(開發的應用程序及用戶上傳數據)共享一套NFS;各業務共享同一套物理數據庫(一臺物理服務器mysql創建多個庫)。隨著業務和訪問量的增長,這種隱患越來越令人擔憂,主要表現在以下幾個方面:
◆安全問題
數十個站點共享目錄,以nfs方式共享給各物理服務器,這幾十個項目,只要任何一個有安全漏洞存在,有心人都能進來為所欲為,讓站點全部淪陷。時不時的,被人註入惡意代碼,針對性的進行清除,但沒多久又被註入篡改。大家心裏都有數,存在漏洞的地方,不一定是被篡改的那個。但站點太多,又沒有隔離,根本無法用安全工具掃描(一個站點進行掃描,平均花費一天)。
[root@web57 ~]# more /usr/local/nginx/conf/nginx.conf user www www; worker_processes 6;
worker_rlimit_nofile 51200;
events { use epoll; #use kqueue; #FreeBSD system worker_connections 51200; }
http { include mime.types; default_type application/octet-stream; #charset gb2312; server_names_hash_bucket_size 256; client_header_buffer_size 256k; large_client_header_buffers 4 256k; client_max_body_size 500m; …………………………………………省略若幹………………………………… include vhosts/faxian.quanzhen.com.conf; include vhosts/www.quanzhen.com.conf; include vhosts/news.quanzhen.com.conf; include vhosts/s.quanzhen.com.conf; include vhosts/down.quanzhen.com.conf; include vhosts/static.quanzhen.com.conf; include vhosts/image.quanzhen.com.conf; include vhosts/3g.quanzhen.com.conf; include vhosts/mini.quanzhen.com.conf; include vhosts/xml.quanzhen.com.conf; include vhosts/mayiapi.quanzhen.com.conf; include vhosts/www.android77.com.conf; include vhosts/fahongbao.android77.com.conf; include vhosts/update.android77.com.conf; include vhosts/dev.quanzhen.com.conf; include vhosts/qr.110.cc.conf; include vhosts/110.cc.conf; include vhosts/eggserver.quanzhen.com.conf; include vhosts/apkegg.quanzhen.com.conf; include vhosts/eggserver.yidong7.cn.conf; include vhosts/www.yidong7.cn.conf; include vhosts/down.yidong7.cn.conf; include vhosts/wan.quanzhen.com.conf; include vhosts/open.quanzhen.com.conf; include vhosts/bakdown.yidong7.cn.conf ; include vhosts/hanhua.quanzhen.com.conf; include vhosts/mpk.quanzhen.com.conf; include vhosts/android.quanzhen.com.conf; include vhosts/pay.quanzhen.com.conf; include vhosts/cmstop.quanzhen.cn.conf; include vhosts/news.quanzhen.cn.conf; include vhosts/pingce.quanzhen.cn.conf; include vhosts/gonglue.quanzhen.cn.conf; include vhosts/hao.quanzhen.cn.conf; include vhosts/all.quanzhen.cn.conf; include vhosts/s.quanzhen.cn.conf; include vhosts/apkz.quanzhen.com.conf; include vhosts/ajax.quanzhen.com.conf; include vhosts/union.quanzhen.com.conf; include vhosts/mai.quanzhen.com.conf; include vhosts/blog.quanzhen.com.conf; include vhosts/guazi.quanzhen.com.conf; include vhosts/lockscreen.yidong7.cn.conf; include vhosts/dsp.pujia8.com.conf; include vhosts/3svx4haii9.quanzhen.com.conf; include vhosts/u.quanzhen.com.conf; include vhosts/bianji.quanzhen.com.conf; include vhosts/default.conf; } |
◆性能問題
主要集中在數據庫上邊,只要有一個庫出現問題,引起鎖表或者其它競爭,全部相關業務都會掛起,煩不勝煩啊。想進行拆分,決策人認為,本來就滿機櫃了,如果再新家機器,得另租機櫃,考慮到成本等其它問題,只求不出事即可。
整合的計劃是,遷移部分業務到公有雲上,騰出服務器後,對現有的設備進行擴充配置(拼內存、硬盤等,古舊的機器直接下架)。留下配置高的,進行虛擬化,既能減少設備數量(托管費降低),又有利於日常維護。
前邊說了這麽多,似乎與技術關系不大,但對於一些有遺留問題的項目,還是具有參考意義。接下來,我們就進入正題,看看我們要遷移的項目狀況。要往雲上遷移的數據包括網站數據及數據庫數據,網站數據比較好辦,rsync同步到對應的目錄,而數據庫相對而言,要麻煩不少。兩個數據庫,一個容量38G,另一個29G,不算太大,但公用的ibdata1文件卻有123G,最初是嘗試把這兩個庫,直接導入到阿裏雲的RDS,在進行數次操作失敗後,咨詢客服得到的答復是RDS暫時不支持分表的數據庫。為節省成本,購買一個配置高一點的雲主機(cpu 8core,內存32G,1T高效雲盤),部署上mysql5.6,供兩個數據庫使用。
第一次嘗試
預估了一下,200G的數據,貪心一把,看一次性能不能遷移完。提前幾天,把雲上的環境全部準備妥當(能出來測試頁),運營部門把通知發下去,然後某天夜裏0:30分,一些人在辦公室,一些人在家裏,瞇著眼,莊重地在鍵盤敲入“screen”這幾個字符。在qq群裏得到一致許可,可以進行數據庫導出操作以後,小弟小心翼翼地發來一條指令:
[root@db-209 ~]# innobackupex --user=root --passwor='i%=KGb76' \ --defaults-file=/etc/my.cnf \ --databases=“quanzhen_mobile7lockscreen quanzhen_equipment” /data/bakmysql/ InnoDB Backup Utility v1.5.1-xtrabackup; Copyright 2003, 2009 Innobase Oy and Percona Ireland Ltd 2009-2012. All Rights Reserved.
This software is published under the GNU GENERAL PUBLIC LICENSE Version 2, June 1991.
180618 00:30:31 innobackupex: Starting mysql with options: --defaults-file='/etc/my.cnf' --password=xxxxxxxx --user='root' --unbuffered -- 180618 00:30:31 innobackupex: Connected to database with mysql child process (pid=20090) 180618 00:30:37 innobackupex: Connection to database server closed IMPORTANT: Please check that the backup run completes successfully. At the end of a successful backup run innobackupex prints "completed OK!".
innobackupex: Using mysql Ver 14.12 Distrib 5.0.95, for redhat-linux-gnu (x86_64) using readline 5.1 innobackupex: Using mysql server version Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
innobackupex: Created backup directory /data/bakmysql/2018-06-18_00-30-37 180618 00:30:37 innobackupex: Starting mysql with options: --defaults-file='/etc/my.cnf' --password=xxxxxxxx --user='root' --unbuffered -- 180618 00:30:37 innobackupex: Connected to database with mysql child process (pid=20123) 180618 00:30:39 innobackupex: Connection to database server closed
180618 00:30:39 innobackupex: Starting ibbackup with command: xtrabackup_55 --defaults-file="/etc/my.cnf" --defaults-group="mysqld" --backup --suspend-at-end --target-dir=/data/bakmysql/2018-06-18_00-30-37 --tmpdir=/tmp innobackupex: Waiting for ibbackup (pid=20132) to suspend innobackupex: Suspend file '/data/bakmysql/2018-06-18_00-30-37/xtrabackup_suspended'
xtrabackup_55 version 2.0.7 for Percona Server 5.5.16 Linux (x86_64) (revision id: 552) xtrabackup: uses posix_fadvise(). xtrabackup: cd to /data/mysql_db xtrabackup: Target instance is assumed as followings. xtrabackup: innodb_data_home_dir = ./ xtrabackup: innodb_data_file_path = ibdata1:10M:autoextend xtrabackup: innodb_log_group_home_dir = ./ xtrabackup: innodb_log_files_in_group = 2 xtrabackup: innodb_log_file_size = 5242880 >> log scanned up to (601191481892) [01] Copying ./ibdata1 to /data/bakmysql/2018-06-18_00-30-37/ibdata1 >> log scanned up to (601191481892) >> log scanned up to (601191481892) >> log scanned up to (601191481892) >> log scanned up to (601191481892) >> log scanned up to (601191481892) >> log scanned up to (601191481892) >> log scanned up to (601191481892) …………………………………省略…………………………………………… |
樂觀估計,上午7點前,能完成整個遷移,幾個人商量輪流監看進展程度,等進行完一步後叫醒休息的人,以便進行下一步。結果,到淩晨六點多,才執行完這個innobackupex,還差好幾步呢,每一步都同樣耗時,只能宣告遷移暫時失敗,選個黃道吉日,分兩次進行遷移。
第二次分拆遷移
萬年歷排除近期諸事不宜的日子,再搖卦選利用用神的地支,選定日誌,約上相關人等,繼續進行遷移。有了上一次的教訓,在遷移前又對要遷移的庫做了清理,刪掉了一些無用的數據,省出來好幾個G的空間。在源數據庫,執行指令:
[root@db-209 ~]#innobackupex --user=root --passwor='i%=KGb76' \ --defaults-file=/etc/my.cnf --databases=“quanzhen_equipment” /data/bakmysql/ |
我交到好以後,就躺下睡覺,到淩晨三點電話響了,告知第一步完成。
[root@db-209 ~]#innobackupex --apply-log /data/bakmysql/2018-06-18_00-30-37 |
日誌應用倒是執行的很快,回車即完。然後進行tar 打包和復制文件到目標服務器,由於租賃的出口帶寬太小(總帶寬30M,現在讀者知道為什麽要夜間訪問低谷進行遷移了吧?),復制文件到目標服務花了一些時間。
目標服務器,僅僅需要安裝好mysql軟件,創建好目錄/data/mysql_db,不需要執行數據庫初始化操作,因為innobackupex導入時,要求數據目錄必須為空。阿裏雲的配置,遠比源服務器配置高,解壓文件很快就完成。
檢查一下mysql選項文件/etc/my.cnf,註意是選項文件。設定“—datadir=/data/mysql_db”,就可執行導入操作,指令如下:
[root@msyql mysql_db]# innobackupex --defaults-file=/etc/my.cnf \ --copy-back /data/db_bk/2018-06-18_00-30-37 |
源數據導出時,沒有把庫mysql一並導出,這倒不是什麽要緊的事情,反正只有一個賬戶需要創建。接下來,初始化數據庫並創建應用帳號,具體操做如下:
[root@msyql mysql_db]#cd /usr/local/mysql/ [root@msyql ~]#scripts/mysql_install_db --user=mysql --datadir=/data/mysql_db [root@msyql ~]#mysql mysql>grant all on quanzhen_equipment.* to …… |
還要記得給mysql空密碼消除掉。
源庫與目標庫,比對一下表的數量,以及隨機抽取一些大表,對記錄數進行比較。確認數據完整以後,一幫去調試應用,後續工作不表,沒我什麽事。
第三次分拆遷移
有了上一次的成功經驗,這次信心滿滿了,不過擔心還是有的,就是那個目標庫導入時,要求數據目錄為空。小弟在未開始時,就來征求我的意見,我擔心可能會有障礙,就對他說,你只要把源站數據導出準備好,放到目標數據庫,余下的我親自搞定。
自己的選擇有兩個,一個是使用選項“--force-non-empty-directories”,如果不行,就再弄一個mysql實例,啟用3307端口,雙實例運行。先嘗試第一個選項,看能不能進行下去,具體指令為:
[root@msyql db_bk]# pwd /data/db_bk [root@msyql db_bk]#innobackupex --defaults-file=/etc/my.cnf --copy-back \ --force-non-empty-directories 2018-06-22_00-24-52 180623 23:31:57 innobackupex: Starting the copy-back operation
IMPORTANT: Please check that the copy-back run completes successfully. At the end of a successful copy-back run innobackupex prints "completed OK!".
innobackupex version 2.4.11 based on MySQL server 5.7.19 Linux (x86_64) (revision id: b4e0db5) innobackupex: Can't create/write to file '/data/mysql_db/ib_logfile0' (Errcode: 17 - File exists) [01] error: cannot open the destination stream for ib_logfile0 [01] Error: copy_file() failed. |
悲催了,有同名文件存在,不行!直接終止運行。好吧,我把文件“ib_logfile0、ib_logfile1”挪走,再執行,還是不行,提示文件“ibdata1”存在,這可是個大家夥。雖然擔心新導入的ibdata1可能不包含現有數據庫相關信息,但忍不住想試一把。可能有讀者會問,這樣搞可能把數據庫原有的數據破壞掉了,其實我想到這一層來,老早我就把整個庫做了備份,買了保險的。
正全神貫註盯著屏幕查看輸出,希望進展順利,突然,qq群有消息傳來,問進展如何,啥時能完成。一看時間,六點了,北方大地已經一片光明。時間來不及了,停掉進程,試試直接復制文件,不使用innobuckupex。心中沒底,就去仔細比較了數據庫目錄與導出數據目錄中的三個文件“ibdata1、ib_logfile0、ib_logfile1”,發現其大小完全相同。不管了,把現有數據庫裏的這幾個文件搬走,從導出目錄cp來著三個文件。復制完,執行mysqld_safe啟動服務,失敗,提示ib_logfile0無寫入權限;這好辦,一條chown指令而已。再執行啟動mysql服務,正常。
那麽數據對不對呢?我不能確定,萬一不對,就再配一個mysql,導入數據,以雙實例啟動,後邊再想法整合;阿裏雲購買的服務器,相互通信是內網,不會在傳輸上浪費太多時間。
既然服務正常,就對一下數據吧,萬一運氣爆棚(前幾天夜裏夢到自己能飛,抓住一只巨型天鵝,我美美地摟著天鵝的脖子…),數據完整可用呢!我自己悄悄對比了一陣,沒差異呢,又到qq群呼叫其它人,說導入有障礙,數次不成功,後邊采取了一些不確定的手段,mysql服務是起來了,請大家核實一下數據,看是否完整可用。幾個程序員一陣忙碌,得到答復,數據是完整可用的。到此,我的工作完成了。
有人可能要鄙視我一番,為什麽不先測試?不制定完善的流程?這個問題問得好!我數次建議決策人,準備點資源,說白了就是準備1臺空閑服務器,再內網演練,就算白天也能能進行(復制數據走內網,不在用戶訪問的帶寬),但是,沒有資源給我啊,但事情又不得不做。雖然累點,折騰一番,翻過來想,咱玩懸的也獲得經驗,不然也沒有這個文章問世,你們覺得覺呢?
道長有話說
最近受邀在51CTO博客專欄出版《負載均衡高手煉成記》,依托自己十余年的IT運維經驗,以實際工作經驗為基礎,介紹不同場景下,負載均衡的實現方式,以及負載均衡的日常維護。
本專欄適合於一直徘徊在運維初級未找到入佳境之門的運維工程師,也適合對負載均衡有興趣了解和學習的技術愛好者。跟著田道長學完這個系列課程,不僅學知識,更是漲薪、升職、進心儀公司的一大捷徑!
負載均衡高手煉成記
螞蟻搬家式遷移mysql數據庫