GitLab事件筆記

GitLab完整公開了他們誤刪資料資料庫的事件在他們的網站,整個事件除了工程人員需要借鏡之外,最大的重點在於GitLab做事的文化、面對事情的態度、危機處理能力。

我想,除了工程端之外,GitLab也是有許多值得我們學習的地方。我將重點都摘錄下來給大家參考。

另外我跟Azure不太熟,有關Azure相關的設定以及基礎,如果有寫錯,也麻煩告知一下。


架構

  1. 有兩台DB做Failover,以下稱為DB1 (主要DB)以及DB2(備援DB)

事件速寫

  • GitLab打算測試資料庫Load Balance的架構,想以此改善效能,所以他們先複製了一份到Staging
  • DB1出現大量負載,負載來源有兩個
  1. 出現大量SPAM
  2. 一隻背景程式正嘗試刪除一名員工的資料,這支程式是用來刪除那些濫用的帳號
  • 因為DB1出現大量負載,導致DB2的資料同步出現延遲
    原因是所需的資料(WAL segments)在DB1已經被刪除,所以同步功能不只被延遲,而是整個卡死。
  • 手動同步DB2資料
    要做這件事情,必須先清除DB2的資料,再利用 pg_basebackup 將DB1的資料複製到DB2。
  • 資料同步的過程中,突然凍結
    原因可能是DB1的連線數(WAL Sender)已達上限,為了解決這個問題,他們決定增加連線數,但DB1拒絕重啟,因為總連線數已達上限。為解決這問題,他們降低了應用程式的連線數。
  • 重啟DB1後,DB2仍然無法同步
    工程師開始為pg_basebackup debug並找到凍結點發生在poll函式的呼叫,但是沒有提供任何有意義的資訊

(此時已經過了六小時)

  • 修復DB2的pg_basebackup,卻誤刪DB1資料
    一名工程師在想,可能是pg_basebackup在上一個步驟建立了一些檔案,避免他被重覆執行。其他工程師認為這是個正常的行為,pg_basebackup將會等待DB1送資料過來,在這段時間,不會有任何訊息。很可惜的,在他們的工程文件及官方文件都沒有清楚地提到這件事情。為了恢復資料同步,他們必須在DB2刪除所有資料,但不幸的,他們卻在DB1進行這項作業,儘管工程師馬上意識到這件事情(刪錯機器),並立即中止,但仍然遺失了300G的資料

失敗的復原程序

  • 目前有採用的備份包含
  1. 每24hr會把資料庫dump出來,儲存在Amazon S3,舊的備份會定期被移除 (利用pg_dump)
  2. 每24hr會產生硬碟的鏡像檔,接著該鏡像檔會被載入staging環境,做測試用途
  3. 其他的資料(Git/NSF)則利用Azure的Disk Snapshot,每24hr進行一次
  4. 資料庫備援,如同上述資料庫架構,當DB1死了,自動轉移到DB2
  • 當他們打算採用S3的備份資料來復原DB時,發現S3裡面是空的,因為他們備份的程序是使用 pg_dump 9.2,而主機已經是9.6。當資料庫與備份工具版本不同,會導致dump失敗,原先Omnibus應該會自動偵測資料庫使用版本,但因為他們將Omnibus運行在Application Server而非DB Server,在無法直接偵測DB版本的狀況下,選了預設9.2版,導致失敗
  • 錯誤通知系統發生異常
    原先Cronjob應該會將所有錯誤訊息發送給所有人,但是發信機制並沒有附上DMARC的驗證,導致這些信件被Mail Server阻擋,所以也沒人知道自動備份機制已經壞了。
  • 沒有採用 Azure 的 Disk Snapshot
    Azure的Disk Snapshot會一次備份整個硬碟,但是並不容易單純的取出個別資料。Azure規定storage account可以連結到很多個host,但是每個storage account卻有30TB資料的限制,當他資料被還原在相同domain的host,速度很快,然而要還原到其他host可能要花費數小時。所以他們不打算太仰賴Azure。所以他們並沒有讓DB的備份資料儲存在Azure
  • LVM的Snapshot原本是用來將production複製到staging,原本不是用來做災難後復原工作,但在悲劇當下,Gitlab擁有兩份snapshots,分別是定期24hr做一次的,以及六個小時前做的資料。
  • Snapshot產生步驟:
  1. 建立production的Snapshot
  2. 將Snapshot複製到Staging
  3. 利用Snapshot在Staging建立新的磁碟
  4. 移除新磁碟內DB的所有webhook

還原 GitLab.com

  • LVM六個小時前的備份資料是目前唯一的選擇,還原的整個過程將會包含以下步驟
  1. 複製Staging的資料庫到Production,但這份資料就不會包含所有webhook
  2. 同時複製Snapshot,因為這份Snapshot內容包含所有webhook (不是很確定)
  3. 從步驟一還原資料庫
  4. 從步驟二還原資料庫
  5. 利用上一步驟拿到的資料庫,還原webhook
  6. 將資料庫所有sequence增加100000,避免這六個小時空窗期,有任何sequence被使用,導致資料錯誤
  7. 重新啟動GitLab.com
  • 因為成本因素,Staging環境使用Azure Classic,而非Premium Storage,所以磁碟速度相當緩慢,這成為整個還原程序的瓶頸,但此時有兩個選項可以還原出相同的資料
  1. 複製LVM Snapshot
  2. 複製Staging的PostgreSQL Data目錄
  • 選項二是相對簡單的方法但是還有一些問題
  1. 從Staging複製到Production要花費18hr
  2. 這些Disk實質為網路磁碟,速度大概是6Mbps,而且無法升級到Premium Storage

(接著就開始進行還原,過了24hr後…)

  • Gitlab完成了還原資料庫的工作,但是沒有webhook
  • 同時,也重新在Staging 還原了一次Snapshot(略過刪除snapshot流程),並取得所有Webhook,也取得了完整資料庫的dump
  • 在一小時過後,完成了整個資料庫的復原程序,並確定所有功能正常運行

對外公開

在這個過程中,他們將所有的過程及事件公布在Google Doc,同時將整個復原的過程透過YouTube直播,並透過Twitter來通知那些沒有看直播的人最新消息。

原先這是一份私有的Google Doc,所以工程師將自己名字放上去,在公開之後,由於裡面包含著誤刪資料的工程師的名字,Gitlab認為這會讓工程師感到不舒服,所以他們將會拿掉這些名字。


問題分析

GitLab內部利用 The 5 Whys 來分析問題發生的主因,他們統整了兩個大問題

  • 問題一:GitLab.com關閉了將近18hr
  1. 為什麼GitLab.com關了?因為DB1的資料庫目錄被意外刪除了,而非預期想刪除的DB2資料庫目錄。
  2. 為什麼資料庫目錄被刪除?因為DB2的Replication功能已經停止,所以DB2需要被重建,重建過程需要清除目錄,還原的過程需要手動處理,而非自動,也沒有標注清楚。
  3. 為什麼Replication功能停止了?突發的負載量導致資料庫Replication過程中止,因為DB2在取得所需的WAL Segments之前,DB1已經先把它刪了。
  4. 為什麼資料庫的負載會增加?因為兩個突發事件同時發生:大量的Spam以及清理員工資料的相關程序
  5. 為什麼要刪除GitLab員工的資料?因為該名員工被網路霸凌回報濫用,目前的系統在處理濫用問題僅僅只是檢視回報的細節,導致該名員工突然被排入刪除程序。
  • 問題二:還原GitLab.com花了18hr
  1. 為什麼GitLab.com花這麼多時間還原?因為GitLab.com必須使用Staging資料庫的備份來還原,他們被放在Azure比較慢的區域。
  2. 為什麼還原GitLab.com需要Staging資料庫?因為資料庫主機並沒有啟動Azure Disk snapshots,而定期備份的pg_dump則沒有正常運作。
  3. 為什麼DB1出錯時,沒有將所有資料庫工作轉移到DB2(異常備援)?因為DB2的資料在一開始進行同步的過程中,已經清掉了一部分資料,所以無法作為還原用途。
  4. 為什麼不使用標準的備份程序?標準的備份程序使用pg_dump來進行備份,而這個程序則因為資料庫版本不合(9.2 & 9.6)導致失敗。
  5. 為何你們不知道資料庫備份程序異常?由於Email設置的錯誤,導致所有的系統信件都被Email Server阻擋,所以通知系統無法正確送信給所有人。
  6. 為何Email會被阻擋?因為Email Server會檢查DMARC來避免垃圾郵件,而通知系統沒有設定DMARC。
  7. 為何不啟動Azure Disk snapshot?我們以為自己的備份程序已經相當充足,而且,恢復Snapshot可能會花費很長的時間。
  8. 為何平常不進行備份程序的測試?因為沒人負責測試這個程序。

改善復原程序

  • GitLab將專注在改善災情復原,讓工程人員更清楚他們使用的機器以及他們下的命令。比如說將rm的功能換成其他更安全的功能,避免他們不經意使用了rm -rf 。
  • 一個理想的環境,應該是你可以犯錯,而且可以被輕易地從將災難的影響程度從最小降到零。這需要平時就須執行這些程序,而且這些程序也可以被測試,或是輕易的rollback。
  • Gitlab正在為自己的基礎建設,建立更好的復原程序,其中不只是資料庫,而且確保所有程序都有人負責。
  • 讓備份的程序也可以被監控。
  • 最後,他們將改善他們的誤用回報系統