架構重整系列分享在工作上遇到的棘手架構案例。希望讓同樣面對這些問題的人也能從中得到一些靈感來處理!
先簡單列一下這個案例的狀況:
- 原始碼部分:
code base 已經發展五、六年,使用 twistd 框架架設出來的單塊系統,所有的應用 backend 都塞在同一份 code base 裡面,而且還在使用 python2!開發上沒有分層設計,底層 db 的 orm instance 直接暴露到表現層上,不同應用會使用到相同的表,甚至前後端沒有分離,互相沾黏非常嚴重。
- 架構部分
依然在使用當年的舊機型 c3.xlarge 作為前端第一台 EC2,後面有再接一台 c4.xlarge 的 EC2 作分流,但兩台效能都已經落後於現在的 c5.xlarge,時常 cpu 推到 90%。db 依然使用 EC2 自建,沒有使用 RDS,使用 script 自動化做備份,但還原機制不明朗,沒有任何關於重建 db 的文件留下。同時因為資料量已經長大,資料庫 schema 沒有做對應的優化,晚上又有很多 cronjob 再跑,db 的 cpu 也時常吃滿。
- 文件部分
零。可以說根本沒有,所以對於當時的狀況只能用看 code,然後連進去看系統,看先前留下來的設定,用猜的,然後祈求上天保佑。
詳細的架構和調整會在之後的文章中細部討論。這篇主要是記錄將 db 從 EC2 migrate 到 RDS 的過程,與踩的坑。
故事正式開始。
「J,BD說客戶端又在抱怨說登不進去了!」C 一早就跑來跟我說。
「好吧,我也只能再重啟 process 了」我無奈的使用之前遺留下的 jenkins trigger 來 restart。
這個場景在最近這一個月幾乎天天上演。重啟 process 後最多也只能撐幾個小時,塞住的問題又會重現。觀察 db 的 EC2,cpu 非常的高!尤其是客戶端登入後的第一頁,後端調資料的時候會 join 相當多表來計算。這些表行數又特別的多,跑起來更慢,更吃資源。只要有人前面跑了,db 就會忙著處理這些 request,後面的人就只能排隊等著。
「看來我們必須趕快把 db 的效能先拉起來!」我和 」C 說。
但說起來容易,前人根本沒留下任何文件資料關於當時 db 和 EC2 的相關設定。不過在一次的 AWS 線上 seminar 得知,他們有一個服務叫做「Database Migration Service」,後面簡稱為 DMS,他可以在原始db持續運作下,把資料整個 dump 過去到 rds 上面,並且持續更新後續的新資料。聽起來相當完美好用!感覺他就是我們的救世主了!
「不如我們就來試試看這個dms吧!」我和 C 說。她也同意。
初步閱讀 aws 文件後發現,由於目前是使用 PostgreSql 做 db engine ,aws 其實建議使用原生的 pgdump 工具來做轉移。但如果使用 pgdump 的話就需要停機時間!當初我看中 dms 服務就是因為他的 slogan 號稱零停機,實在是安全倍增!所以我們依然決定繼續使用 dms,殊不知開啟後續的踩坑之旅。
dms 運作的原理是一開始會直接對 db 做 select 轉移資料,後續使用 replication slot 串流的方式做更新。因此文件第一步就要我們對原先的db開啟 replication 功能。於是乎,我開始嘗試做這件事。
# 修改 postgresql.conf
wal_level = logical
max_replication_slots = 5 # 文件表示 > 1 即可
max_wal_senders = 5 # 文件表示 > 1 即可
wal_sender_timeout = 0
但第一步就發現,做這件事必須重啟 db!但之前 B 在的時候,他說在某次重啟master db後,slave db (一樣也是使用ec2建立) 就壞了!再也不能同步資料,搞得之後沒人敢做這件事。
但我想想,幹,要是不做,就不能改變,冒險一下!於是改完設定後,立馬重啟。
j@master-db:/$ sudo service postgresql restart
屏氣凝神了1分鐘,系統表示重啟完成,檢查了一下, PostgreSql 服務有正常啟動。手動修改一筆不重要的資料看看,嗯,有串流過去 slave db。看起來一切正常…個屁。正當我暗自慶幸的時候,slack 的 server log channel 開始狂跳錯誤, twistd 抗議說連不到 db!原來重啟造成原來的連線斷開,但系統使用的 orm lib 「storm」 並沒有處理斷線重新連線的問題,所以就開始哀嚎了!
於是只好再度使用重啟大法,把所有 twistd process 全部重來,盯著 log,看來是恢復正常了,突破了第一關。
接下來依照文件指示,起一台 dms replication instance,簡稱 RI。然後增加對應的 db source 和 target。
但發現 Db source 怎麼樣都連不進去,多次檢查防火牆,也就是 security group,都設定正確,為何依然無法連線呢?
# error log
Test Endpoint failed: Application-Status: 1020912, Application-Message: Cannot connect to ODBC provider Network error has occurred, Application-Detailed-Message: RetCode: SQL_ERROR SqlState: 08001
NativeError: 101 Message: [unixODBC]timeout expired ODBC general error.
孤狗了一段時間,判定應該是 Ubuntu 的 iptable 有被設定過,所以被擋住。於是立刻查看,果然裡面有密密麻麻的設定!
「太好了!猜中,趕快把 ip 加上去!」我內心雀躍的加入並儲存。再試一次,哇靠還是不行!
「見鬼了啦!」因為怕嚇到隔壁同事,我只好在內心暗罵無數個髒話。紓解完後再度靜下心來看 dms 的 log。從 log 來看,目前的問題依然是無法連入,和修改iptable 之前的狀況一樣,難道還有其他的防火牆設定嗎?
突然想到 h 大在離開前曾經跟我說到他在 db 的 系統中有另外裝一個防火牆,直覺告訴我最後一個兇手就是他!但,我根本忘記他裝的防火牆是那一套。孤狗說大多會裝 ufw,但我敲入指令,系統嘲笑我般的說「抱歉,沒有這個指令!」
bash: ufw: command not found
「難道就要在這一關敗下陣來?」
經驗告訴我,問題遇到死胡同時候,就是要站起來休息一下,上個廁所,轉換腦袋,自然而然就會浮現出好辦法。
回到座位,我重新孤狗防火牆有關的關鍵字,去除掉 Ubuntu 字眼,用一般性的 linux 來查詢,突然看到搜尋結果有一個熟悉的字眼,shorewall!
「幹對啦,就是他啦!」我難掩我心中的喜悅,查詢文件了解基本指令後鍵入,系統不帶表情的跟我說,shorewall 正在執行中!
「運氣不錯,賽對了!」立刻再依照文件把 ip 和 port 加入,測試一次,總算!連進去了!但過不了沒多久,又報錯!
「wtf,有沒有這麼難!」好不容易才突破了連自己人都搞不清楚的三層防火牆,難道裡面還有什麼秘密防火嗎?
原來,postgresql 自己還有一套連入規則,必須手動修改把連入的 ip 輸入,如果要走 replication 的話,也需要同時設定給予權限。
# 修改 /var/lib/postgresql/data/pg_hba.conf
host all all 172.31.23.112/32 md5
host h2 awsdms 172.31.23.112/32 md5
host replication awsdms 172.31.23.112/32 trust
總算!RI 已經可以正確的連入 master db 裡面要資料了!
「駭客任務還真不好當!」我自己自嘲。心中算著,我總共突破了4層防火牆,分別是 security group, iptable, shorewall, PostgreSql 本身。「不過和真正高手突破防火牆還是有很大一段距離啦!」我自己對著螢幕苦笑。
跑了約莫20多分鐘,開始有人回報說客戶端又開始卡頓!原來是 RI 把 master db搾乾了!
「shit!一波未平一波又起!」趕快把 RI 關掉,看來又得重新破關,思考怎麼解決搾乾的問題了!
延伸閱讀:
拯救脆弱系統 – Migrate to RDS by DMS #2
AWS Data Migration Service 攻略
參考資料:
AWS DMS
How can I troubleshoot AWS DMS endpoint connectivity failures?
ShoreWall
封面圖片備註:在破爛的 code base 打滾久了,就學會閉上眼睛,或是幫同事遮住眼睛,避免業障重。