運維的苦,誰懂?一次“心驚肉跳”的遷庫經(jīng)歷?。ㄓ胁实埃?/h1> 原創(chuàng)
【51CTO.com原創(chuàng)稿件】IT 運維工程師一直是個“苦逼”的職業(yè),“鋤禾日當午,不如運維苦,對著破電腦,一調(diào)一下午”是對運維工作的一個形象的描述。下面看看本文作者一次驚心肉跳的數(shù)據(jù)庫遷移經(jīng)歷。
事件起源
整個事件的起源還要從我最近入職了一家區(qū)塊鏈金融公司說起,公司業(yè)務發(fā)展比較迅猛,突破百萬用戶也是近在眼前。
整個系統(tǒng)都在阿里云上運行,每天都能看到用戶的不斷增長,即興奮又擔憂,為什么這么說呢?
由于我過來的時候,公司業(yè)務就已經(jīng)上線了,系統(tǒng)接過來之后,快速了解了所有的應用服務都是在 Docker Swarm 跑起來的,也包括 MySQL 數(shù)據(jù)庫。
按照這種用戶量發(fā)展下去,MySQL 在容器中運行用不了多久肯定會撐不住,以至于我就有了遷庫的想法。
我開始隱隱的擔憂起來,畢竟不想每天提心吊膽的做運維。所以立即重新規(guī)劃了新的方案和大家一起探討。
最終總監(jiān)和相關技術負責人都敲定用 RDS 做為數(shù)據(jù)庫新的方案,周星馳的功夫中也說到:“天下武功,唯快不破”,于是就開始干起來。
遷移計劃
原架構圖
如上圖所示,分析一下原來的架構圖:
- 從入口層(CDN)→到安全層(WAF)→***到達應用層 (ECS集群)。
- Docker Swarm 打通了 ECS 集群中的每臺服務器,在每臺 ECS 宿主機安裝 Docker engine 并部署了公司需要的應用服務和數(shù)據(jù)庫(Nginx、PHP、Redis、MySQL等)。
- MySQL 容器通過本文件掛載到容器中實現(xiàn)數(shù)據(jù)持久化。
- 業(yè)務項目以 PHP 為主,PHP 也是運行在容器中,通過 PHP 指定的配置文件連接到 MySQL 容器中。
隨便展示一下其中一個庫的 docker-compose yaml 文件:
- version: "3"
- services:
- ussbao:
- # replace username/repo:tag with your name and image details
- image: 隱藏此鏡像信息
- deploy:
- replicas: 1
- restart_policy:
- condition: on-failure
- environment:
- MYSQL_ROOT_PASSWORD: 隱藏此信息
- volumes:
- - "/data//mysql/db1/:/var/lib/mysql/"
- - "/etc/localtime:/etc/localtime"
- - "/etc/timezone:/etc/timezone"
- networks:
- default:
- external:
- name: 隱藏此信息
從上面的信息可以看出來,每個庫只運行了一個 MySQL 容器,并沒有主從或讀寫分離的方案。
而且也沒有對數(shù)據(jù)庫做任何優(yōu)化,數(shù)據(jù)庫這樣跑下去讓筆者很擔憂,正常來說,都會把數(shù)據(jù)庫獨立部署運行。
調(diào)整后架構圖
從上圖可以看出來,筆者只是把 MySQL 獨立出來了,開通 RDS 實例來跑數(shù)據(jù)庫,當然還開通了其他的一些服務(比如 OSS、云 Redis 等),這些不是本文的重點,就沒有畫出來。
Nginx 和 PHP 服務還是在 Docker Swarm 中運行。本文只是對遷移后出了問題的庫進行分享,下面來看看遷移的方案吧。
遷移流程方案
遷移流程的方案:開通 RDS 實例→備份 SQL→導入到 RDS→修改數(shù)據(jù)庫配置文件→測試驗證。
遷移步驟如下:
- 根據(jù)業(yè)務量規(guī)劃開通 RDS 實例,創(chuàng)建數(shù)據(jù)庫和用戶
- 提前做好 RDS 白名單,添加允許訪問 RDS 的 IP 地址
- mysqldump 備份 Docker 中的 MySQL
- 把備份好的 .sql 文件導入到 RDS 中
- 修改 PHP 項目的數(shù)據(jù)庫配置文件
- 清空 PHP 項目的緩存文件或目錄
- 測試驗證
- RDS 定時備份
具體遷移細節(jié)就不展示了,我是在夜深人靜的時候進行遷移操作的,確定大半夜沒人訪問我們的 App 和網(wǎng)站了才開干的。
我們的業(yè)務情況有點像股市,我們是晚上 12 點不許操作和交易,第 2 天早上 9 點開盤,9 點鐘是并發(fā)的高峰期,就像朝陽大悅城上午開門一樣,大批的顧客同時并發(fā)過來了。
所以那天晚上在 12 點 15 分準時開干,按計劃和提前準備的配置、命令、腳本進行操作的。
把 Docker 中運行的 MySQL 遷移到 RDS 上非常順利,好幾個庫的遷移不到半個小時就結束了,并且把網(wǎng)站和 App 的流程都跑了一遍,也都是妥妥的。
最終把提前準備好的備份腳本放在 crontab 中定時執(zhí)行,可以看下腳本內(nèi)容:
- #!/bin/bash
- #數(shù)據(jù)庫IP
- dbserver='*******'
- #數(shù)據(jù)庫用戶名
- dbuser='ganbing'
- #數(shù)據(jù)庫密碼
- dbpasswd='************'
- #備份數(shù)據(jù)庫,多個庫用空格隔開
- dbname='db1 db2 db3'
- #備份時間
- backtime=`date +%Y%m%d%H%M`
- out_time=`date +%Y%m%d%H%M%S`
- #備份輸出路徑
- backpath='/data/backup/mysql/'
- logpath=''/data/backup/logs/'
- echo "################## ${backtime} #############################"
- echo "開始備份"
- #日志記錄頭部
- echo "" >> ${logpath}/${dbname}_back.log
- echo "-------------------------------------------------" >> ${logpath}/${dbname}_back.log
- echo "備份時間為${backtime},備份數(shù)據(jù)庫 ${dbname} 開始" >> ${logpath}/${dbname}_back.log
- #正式備份數(shù)據(jù)庫
- for DB in $dbname; do
- source=`/usr/bin/mysqldump -h ${dbserver} -u ${dbuser} -p${dbpasswd} ${DB} > ${backpath}/${DB}-${out_time}.sql` 2>> ${backpath}/mysqlback.log;
- #備份成功以下操作
- if [ "$?" == 0 ];then
- cd $backpath
- #為節(jié)約硬盤空間,將數(shù)據(jù)庫壓縮
- tar zcf ${DB}-${backtime}.tar.gz ${DB}-${backtime}.sql > /dev/null
- #刪除原始文件,只留壓縮后文件
- rm -f ${DB}-${backtime}.sql
- #刪除15天前備份,也就是只保存15天內(nèi)的備份
- find $backpath -name "*.tar.gz" -type f -mtime +15 -exec rm -rf {} \; > /dev/null 2>&1
- echo "數(shù)據(jù)庫 ${dbname} 備份成功!!" >> ${logpath}/${dbname}_back.log
- else
- #備份失敗則進行以下操作
- echo "數(shù)據(jù)庫 ${dbname} 備份失敗!!" >> ${logpath}/${dbname}_back.log
- fi
- done
- echo "完成備份"
- echo "################## ${backtime} #############################"
到了 1 點鐘,確定沒問題后發(fā)通知到群里,發(fā)微信給領導表示已遷移完成,進行很順利,然后筆者打車回家,睡覺。
雪崩來臨
其實這一晚筆者睡得也不踏實,到了 8 點半就醒了,因為我們 9 點鐘開盤,會有大量的客戶涌進,每天開始產(chǎn)生新的交易(買入和賣出),給大家看下截圖:
果不其然,9 點過后,我打開 App,一切正常,點擊切換幾個界面后,發(fā)現(xiàn)其中一個功能的請求超時了,一直在轉,然后緊接著其他功能也超時了。
完了,出問題了。趕緊開電腦查問題,過了一會兒群里就開始沸騰了(反映好多客戶打開 App 都顯示請求超時了),我的電話也***時間響了,技術總監(jiān)打來的,問我怎么回事,我說正在開電腦排查。
緊急處理
排查問題
電腦打開后,首先想到的就是 RDS 數(shù)據(jù)庫出了問題,登錄阿里云,進入 RDS 中的 DMS 數(shù)據(jù)管理控制臺,一進去就傻眼了 “CPU 爆了”,這么多連接數(shù),如下圖:
進入會話去看看,發(fā)現(xiàn)會話“炸鍋了”,發(fā)現(xiàn)幾百頁的 select 都擠在 ub_user_calculate 這個表中,這個表數(shù)據(jù)量相對大一些,目前有 200 多萬條數(shù)據(jù),如下圖:
我的自然反應就是去查看此表的結構,但發(fā)現(xiàn)此表沒有索引,我被驚訝到了,竟然沒有索引,這......
然后筆者返回源數(shù)據(jù)庫查看這張表,也發(fā)現(xiàn)沒有索引,由此可以確定我導過來的這張表就是沒有創(chuàng)建索引,如下圖:
當數(shù)據(jù)庫中出現(xiàn)訪問表的 SQL 沒創(chuàng)建索引,會導致全表掃描,如果表的數(shù)據(jù)量很大,掃描大量的數(shù)據(jù),執(zhí)行效率過慢,占用數(shù)據(jù)庫連接,連接數(shù)堆積很快達到數(shù)據(jù)庫的***連接數(shù)設置,新的應用請求將會被拒絕導致故障發(fā)生。
解決問題
我趕緊把此事反映給開發(fā)負責人,表明問題根源找到了,會話鎖死了,是由其中的一張表沒有索引而導致的,問詢需要給哪幾個字段加索引。
然后接著操作增加索引:
點擊保存后,發(fā)現(xiàn)創(chuàng)建索引的 SQL 一直卡死著,如下圖所示:
突然想起來還有一堆會話在那里,先 Kill 掉所有會話吧,不然索引肯定創(chuàng)建不了,然后又發(fā)現(xiàn)會話根本殺不完,如下圖:
怎么辦呢?會話殺不完...沒辦法,先把訪問入口切斷吧,反正現(xiàn)在用戶訪問也超時,就毅然決定先把域名停了,訪問入口給切斷了,然后在增加索引。索引加上了,發(fā)現(xiàn) CPU 還下不去,如下圖:
為了快速讓 CPU 降下去,重啟這個實例吧:
實例重啟完后,CPU 下去了,會話也下去了:
開啟入口層的域名訪問吧,再次觀察現(xiàn)在的會話和 CPU 等況,如下圖:
這就對了,會話也正常了,通知領導業(yè)務恢復。
再來看一下服務器 CPU 的情況(遷移 MySQL 后的情況),明顯逐漸好轉。
索引使用策略及優(yōu)化
創(chuàng)建索引注意事項:
- 在經(jīng)常查詢而不經(jīng)常增刪改操作的字段加索引。
- order by 與 group by 后應直接使用字段,而且字段應該是索引字段。
- 一個表上的索引不應該超過 6 個。
- 索引字段的長度固定,且長度較短。
- 索引字段重復不能過多,如果某個字段為主鍵,那么這個字段不用設為索引。
- 在過濾性高的字段上加索引。
使用索引注意事項:
- 使用 like 關鍵字時,前置 % 會導致索引失效。
- 使用 null 值會被自動從索引中排除,索引一般不會建立在有空值的列上。
- 使用 or 關鍵字時,or 左右字段如果存在一個沒有索引,有索引字段也會失效。
- 使用 != 操作符時,將放棄使用索引。因為范圍不確定,使用索引效率不高,會被引擎自動改為全表掃描。
- 不要在索引字段進行運算。
- 在使用復合索引時,最左前綴原則,查詢時必須使用索引的***個字段,否則索引失效;并且應盡量讓字段順序與索引順序一致。
- 避免隱式轉換,定義的數(shù)據(jù)類型與傳入的數(shù)據(jù)類型保持一致。
參考鏈接:https://help.aliyun.com/document_detail/52274.html?spm=a2c4g.11174283.6.812.ZGPyBQ
總結
此次故障雖然是表沒有索引造成的,但是我是有責任的,沒有挨個表檢查一下表的結構。
通過此次故障也可以看出來開發(fā)在設計表的時候真的要非常的重視,注意細節(jié)。
還有就是之前在容器中運行的 MySQL 也時不時的出現(xiàn) CPU 瓶頸(比如 CPU 使用率偶爾會達到 80% 以上),我應該提前發(fā)現(xiàn)這些問題,徹底排查找出問題所在原因再進行遷庫的操作。
福利來啦
掃描下方二維碼。關注51CTO技術棧公眾號,歡迎在技術棧微信公眾號留言探討,您運維工作中最驚心動魄的“救火故事”,小編將選出留言最精彩的 10 名網(wǎng)友,送出《Docker從入門到實戰(zhàn)》圖書一本~活動截止時間 5 月 4 日 12 時整,特別鳴謝機械工業(yè)出版社為本次活動提供的圖書贊助。
內(nèi)容簡介
深度剖析 Docker 的核心概念、實現(xiàn)原理、應用技巧和生態(tài)系統(tǒng);全面涵蓋 Docker 四大管理工具、三大組件、集群編排;介紹上百個實戰(zhàn)案例,提升動手能力;以 Docker 當前的流行版本為例講解 Swarm 集群管理。
甘兵,高級運維工程師,6 年運維工作經(jīng)驗。曾就職于國家互聯(lián)網(wǎng)應急中心、天音控股等企業(yè)。擁有豐富系統(tǒng)運維經(jīng)驗,大型網(wǎng)絡架構設計經(jīng)驗。熱衷于開源技術的研究,關注的技術方向 Docker、DevOps 等。
【51CTO原創(chuàng)稿件,合作站點轉載請注明原文作者和出處為51CTO.com】