從 gitlab 事件中吸取的教訓

題註:這是一篇去年的文章,昨天早上看到 gitlab 運維人員愚蠢地 rm -rf, 心有戚戚焉,故而重發這篇文章,供大家參考。

這兩天不是很太平,程序圓媛猿親們出門前最好拜拜祖師爺 Ada,然後給八阿哥上柱香。

周一早上,我鍾愛的一個在線繪圖工具 gliffy 掛了。我發現這個問題是因為當天中午我有一個 tech talk,有兩張圖還沒截出來放在 slides 里,結果打開它的時候才發現是這麼個狀態:

起初我還沒在意,結果昨天發現還打不開,知道事情大了。一開始我猜想是黑客攻擊,後來看了 hacker news 上的討論,才知道一個可憐的 sysadmin(好吧,姑且認為他也是個程序員吧,誰叫 dev ops 不分家呢)誤操作,刪除了 production database,然後整個系統就果斷罷工了。gliffy 的技術團隊日以繼夜地試著恢復他們的數據,可是直到今天,還沒有恢復完成。你要是 CEO,你想不想廢了那個可惡的傢伙?

然後,昨天晚上,朋友圈開始狂轉一篇文章:「程序員的bug導致了天大的損失,要槍斃程序員么?」大意是一個坑爹的證券交易員的烏龍導致交易軟體里一個「頭上有犄角,身後有尾巴」的八阿哥跳出來大唱「我就是不撤單,我就是不撤單」,然後一天之內幾百億美金就被這個八阿哥給吃了。你要是證券公司的老總,你想不想做了那個放出來八阿哥的程序員?

。。。

你看看醫生多悲催,別說醫療事故了,沒有醫活也許本就無醫可救的病人,運氣好的,被病人家屬說些誅心的話;運氣不好,被醫鬧公然折騰,或者在冷僻處被拍板磚。如果程序員每寫出一百個 bug 就要被誅心的話,恐怕沒有程序員活得過三十。

還好,這個世界是個對程序員友好的世界,程序員不哭。

當 gliffy 事件持續發酵時,hacker news 里滿滿地都是正能量 -- 大多數人的觀點是:作為一個程序員,你如果沒有「日了狗了」的高光時刻,你都不好意思給自己掛個資深的抬頭。有個哥們這麼說:

My very first job - ~25 years ago.

Destroyed the production payroll database for a customer with a bug in a shell script.

No problem - they had 3 backup tapes.

First tape - read fails.

Second tape - read fails.

Third tape - worked.... (very nervous at this point).

還有個更絕:

I was testing disaster recovery for the database cluster I was managing. Spun up new instances on AWS, pulled down production data, created various disasters, tested recovery.

Surprisingly it all seemed to work well. These disaster recovery steps werent heavily tested before. Brilliant! I went to shut down the AWS instances. Kill DB group. Wait. Wait... The DB group? Wasnt it DB-test group...

Id just killed all the production databases. And the streaming replicas. And... everything... All at the busiest time of day for our site. Panic arose in my chest. Eyes glazed over. Its one thing to test disaster recovery when it doesnt matter, but when it suddenly does matter... I turned to the disaster recovery code Id just been testing. I was reasonably sure it all worked... Reasonably...

Less than five minutes later, Id spun up a brand new database cluster. The only loss was a minute or two of user transactions, which for our site wasnt too problematic.

My friends joked later that at least we now knew for sure that disaster recovery worked in production...

Lesson: When testing disaster recovery, ensure youre not actually creating a disaster in production.

還有很多溫情的留言,說如果這個可憐的哥們(姐們)被炒魷魚了,他們願意立刻僱傭他(她),理由很簡單:唯有經歷刻骨銘心,才能換來成熟。

程序君也干過誤刪資料庫的蠢事,作為一個教訓,我把它寫進了我的『途客圈創業記』裡面。

Murphys law 告訴我們:"Anything that can go wrong, will go wrong." 當你運營著一個系統,伺服器會崩潰,資料庫會損壞,硬碟會失效,... 不要相信所謂的 MTBF(Mean time between failure),一切一切的小概率事件,只要發生在你身上一次,就是災難。

作為事後諸葛亮,我們想想,遇到這樣的災難該怎麼處理?

首先 我們要有一個詳細的災難處理流程(Disaster Recover Process,以下簡稱DRP)。把所有可能發生的事情做個攻防演練:如果發生其中的一個或者多個意外情況,你該怎麼處理?

比如說:黑客攻擊了你的伺服器,刪除了所有的備份,怎麼恢復伺服器的運行?

你的 DRP 可能是:多級備份,數據除了本地備份外,還備份到一個許可權更高的,遠程的,物理上隔離的地方。

如果你使用 AWS,這個翻譯過來就是:備份的賬號和生產環境的賬號分開,生產環境在自己的賬號下的 S3(或者其他服務下)備份數據以外,還要在備份賬號下的 S3 備份數據。這樣,當黑客獲取了生產環境的 aws 賬號的最高訪問許可權,即便刪除一切,只要備份賬號還健在,一切還能救過來。

僅僅有 DRP 是不夠的,我們還要確保 DRP 隨時可用。這就是第二個要點:像測試你的生產環境一樣測試你的災難處理流程,使其隨時可用。這一點是被絕大多數人忽略的。你如果看 gliffy 的更新:

3/22/16 7:24am PST: Unfortunately one of the restore processes failed because it used significantly more disk space than we anticipated. The other restore processes have been configured with more disk space to reduce the chance of this problem happening again.

(作者註:gitlab 也是如此,多級備份沒有一個正常工作)

你會發現當無法預料的災難發生時,他們雖然有詳盡的 DRP,但 Murphys law 不幸應驗。很可能,他們從來沒有遇到類似的事故,所以也從未試驗過他們的 DRP,至少,沒有把他們所有三個流程都測試一遍(看起來他們有三級備份,很難得了)。

由於對第一個方案的失敗的準備不足,而對第二個方案的時間複雜度估計不足,使得整個服務的恢復過程竟然超過了 48 小時(現在還沒完成)。gliffy 的 Eric(Head of Engineer)說 "data transfer is taking longer than expected",可見第二種方案中,他們的備份和生產環境在不同的物理位置,如果是使用 aws,這就好比生產環境在俄勒岡,備份在弗吉尼亞。假設他們使用了 direct connect,理論上可以達到最大 10Gbps 的傳輸速度,也就是每秒 1.2GB(當然,工程師需要寫代碼保證並發處理網路讀寫,使其達到帶寬的上限)。在這樣的前提下,1PB 的數據需要大概 243 個小時進行傳輸,而從 gliffy 的日誌看,他們花費在數據傳輸上所花的時間大概 12 - 24 小時,所以,大致猜測 gliffy 要傳輸的數據在 50 - 100 TB。

注意,在網路上傳輸的數據很可能是壓縮過的數據,所以,實際的數據量可以要比這個大一倍到幾倍。

對於 gliffy 這樣的工具而言,48 小時還不足以致命,但在線交易,遊戲這樣的平台,可能就是災難性的。如果好好地測試 DRP,了解各個方案的不足並且進而想辦法加快處理的速度,就不會這麼被動。

以上都是紙上談兵,事後諸葛。

不過你想想看,如果一個程序員經歷了這樣的磨難,還能挺過來,她的內心該要有多麼強大?Randy Paursch 說:

experience is what you get when you didnt get what you wanted.

當然,最最最重要的,就是杜絕類似的事件發生:

  • 首先,automation, automation, automation! 任何 devOps 操作都要自動化,避免手工操作。以上例子中都是手工操作惹的禍,如果將其腳本化,輔以合適的 review,可以把人為錯誤的發生概率降到最低。(對於 gitlab,sysadmin 再疲憊,也不太可能出錯,因為腳本不會出錯)

  • 其次,設置合適的許可權(least privilege)。在伺服器上,代碼部署有代碼部署的用戶,備份有備份的用戶,系統維護有系統維護的用戶;在 aws 上,用 iam 設置每種角色,每個用戶。用戶的許可權嚴格定義,只賦予剛剛夠用的許可權,對於刪除操作,許可權一定要慎重。比如說 aws 的 RDS,在 console 里不允許刪除 db group,同時 db 的用戶不允許刪庫(只有超級用戶才可以);對於 unix 的特權用戶,不要對 sudo 設置免密碼,或者僅僅對特定的命令允許免密碼,如 apt-get,等等。合適的許可權可以避免意外的事情發生。(對於 gitlab,即便腳本出 bug 了,許可權系統也會阻止 rm -rf 的執行)

  • 最後,重要的操作一定要預先觸發備份 —— 比如刪庫,通過腳本,使得這樣的操作先進行一次完整備份,然後才真正刪除。這樣,萬一誤操作還有挽回的餘地。(對於 gitlab,即便許可權系統被繞過,在執行包含有 rm -rf 的腳本前,也會先備份,在備份期間,清醒過來的 sysadmin 還可以撤銷這個操作,即便沒撤銷,還有一份最新的磁碟映像可以恢復)

希望大家從 gitlab 和 gliffy 的錯誤中有所收穫!

PS: gitlab 這次危機公關做得相當到位,大寫的服!以後諸君發生類似的事情,手握大權的 HRM 們,還有各大領導們,先別著急指責和處理程序員和 devOps,學學人家怎麼公開透明而又高調地轉危為機!


推薦閱讀:

如何通過各種數據挖掘運維價值
除了日誌易,國內還有哪些這種產品?
隨著雲服務應用的普及和運維自動化的發展,運維這個職業的崗位需求量會不會大大減少?
系統運維、應用運維、硬體運維的區別是什麼?
干運維一個月了,怎麼辦?

TAG:运维 | 运维自动化 | 教训 |