最大規模技術重建:資料庫連線從15000個到100個以下

全文共3660字,預計學習時長10分鐘

最大規模技術重建:資料庫連線從15000個到100個以下

圖源:unsplash

一名新員工最近在午餐時問筆者:“DigitalOcean的科技債務是什麼樣子的?”

聽到這個問題,筆者忍不住笑了。軟體工程師詢問一家公司的科技債務相當於詢問信用評分。這是他們衡量一家公司可疑的過去和他們要揹負何種包袱的方式,我們對技術包袱並不陌生。

作為一家管理自己伺服器和硬體的雲提供商,我們面臨著許多其他初創公司在雲計算新時代沒有遇到的複雜問題。這些艱難的處境最終使得我們不得不在生存初期做出權衡。任何一家快速發展的公司都知道,早期做出的技術決策往往會在日後趕上你。

看著桌子對面的新員工,筆者深吸了一口氣,說到:“我來講講那個我們的資料庫有1500個直接連線的時候的故事……”

最大規模技術重建:資料庫連線從15000個到100個以下

筆者給新員工講述的故事是DigitalOcean迄今為止最大規模的技術重建。全公司上下為其奮鬥持續了多年,從中也學到不少。筆者希望這個故事將對處在棘手的技術債務難題的其他開發人員有所幫助。

一切從哪裡開始

從一開始,DigitalOcean就痴迷於簡潔。這是其核心價值觀之一:力求簡單而優雅的解決方案。這不僅適用於我們的產品,也適用於我們的技術決策。在最初的系統設計中,這一點再明顯不過了。

像GitHub、Shopify和Airbnb一樣,DigitalOcean在2011年開始作為Rails應用程式。Rails應用程式(內部稱為Cloud)管理UI和公共API中的所有使用者互動。幫助Rails的是兩個Perl服務:Scheduler和DOBE(DigitalOcean後端)。

Scheduler計劃並分配Droplet給管理程式,而DOBE負責建立實際的Droplet虛擬機器。當Cloud和Scheduler作為獨立服務執行時,DOBE在機隊的每臺伺服器上執行。

Cloud、Scheduler和DOBE都不能直接交流。他們透過MySQL資料庫進行通訊。這個資料庫有兩個作用:儲存資料和安排通訊。這三個服務都使用一個數據庫表作為訊息佇列來傳遞資訊。

每當使用者建立一個新的Droplet時,Cloud就會向佇列中插入一個新的事件記錄。Scheduler每秒連續調查資料庫以查詢新的Droplet事件,並計劃在可用的管理程式上建立這些事件。

最後,每個DOBE事件將等待新的計劃Droplet被建立並完成任務。為了使這些伺服器可以檢測到所有新改動,它們都需要調查資料庫以查詢表中的新記錄。

最大規模技術重建:資料庫連線從15000個到100個以下

在系統設計方面,無限迴圈和給每個伺服器一個與資料庫的直接連線,這可能是最基本的,很簡單,而且很有效——特別是對於一個人手不足的技術團隊來說,他們面臨著緊迫的最後期限和快速增長的使用者群。

四年來,資料庫訊息佇列構成了DigitalOcean技術棧的主幹。在此期間,我們採用了一種微服務體系結構,用gRPC替換了HTTPS作為內部通訊量,用Golang代替Perl作為後端服務。然而,所有的路仍然通向那個MySQL資料庫。

重要的是,不能僅僅因為某些東西是陳舊的,就認為它就是不正常的,應該被取代的。Bloomberg和IBM擁有用Fortran和COBOL編寫的遺留服務,它們所產生的收入比整個公司多得多。另一方面,每個系統都有一個比例限制。我們需要面對。

從2012年到2016年,DigitalOcean的使用者流量增長超過10000%。我們在產品目錄中增加了更多的產品,在基礎設施中增加了更多的服務。這增加了資料庫訊息佇列上事件的進入量。

對Droplet的需求增加意味著Scheduler正在加班加點地將它們全部分配給伺服器。不幸的是,對於Scheduler來說,可用伺服器的數量並不固定。

最大規模技術重建:資料庫連線從15000個到100個以下

為了跟上不斷增長的Droplet需求,我們增加了越來越多的伺服器來處理流量。每個新的管理程式意味著另一個到資料庫的持久連線。到2016年初,該資料庫擁有超過15000個直接連線,每個連線每1到5秒查詢一次新事件。

如果這還不夠糟糕的話,那麼每個管理程式用來獲取新的Droplet事件的SQL查詢也變得越來越複雜。它已經變成了一個150多行的巨人,橫跨18張表格。它既令人印象深刻,又岌岌可危,難以維持。

不出所料,就是在這個時期前後,裂縫顯現。一個單一的故障點和數千個依賴項爭奪共享資源,不可避免地導致了一段混亂的時期。表鎖和查詢積壓導致中斷和效能下降。

而且由於系統中的緊密耦合,沒有一個明確或簡單的解決方案。Cloud、Scheduler和DOBE都是瓶頸。僅修補一個或兩個元件只會將負載轉移到其餘的瓶頸。於是,經過反覆考慮,工程人員想出了一個三管齊下的整改方案:

· 減少資料庫上的直接連線數。

· 重構排程器的排序演算法以提高可用性。

· 解除其訊息佇列職責的資料庫。

開始重構

為了解決資料庫依賴性問題,DigitalOcean工程師建立了事件路由器。事件路由器充當區域代理,代表每個資料中心的每個DOBE例項輪詢資料庫。而不是成千上萬的伺服器每個查詢資料庫,將只有少數代理做查詢。

每個事件路由器代理將獲取特定區域中的所有活動事件,並將每個事件委託給相應的管理程式。事件路由器還將龐大的輪詢查詢分解得更小、更易於維護。

最大規模技術重建:資料庫連線從15000個到100個以下

當事件路由器上線時,它將資料庫連線的數量從15000多個銳減到不到100個。

接下來,工程師們將目光投向了下一個目標:Scheduler。如前所述,Scheduler是一個Perl指令碼,用於確定管理程式將負責建立的Droplet。它透過使用一系列查詢對伺服器進行排名和排序來實現這一點。每當使用者建立一個Droplet時,Scheduler就會用最好的機器更新錶行。

雖然聽起來很簡單,但Scheduler有一些缺陷。它的邏輯很複雜,很難處理。它是單執行緒的,在流量高峰時效能會受到影響。最後,只有一個Scheduler例項而它必須服務於整個機隊。這是一個不可避免的瓶頸。為了解決這些問題,工程團隊建立了Scheduler V2。

更新後的Scheduler徹底修改了排名系統。它沒有在資料庫中查詢伺服器度量,而是從管理程式聚合並將其儲存在自己的資料庫中。此外,Scheduler團隊透過併發和複製使他們的新服務可在負載下執行。

事件路由器和Scheduler V2都取得了巨大的成就,解決了許多體系結構的故障。即便如此,還是有一個明顯的缺陷。到2017年初,集中式MySQL訊息佇列仍在使用中,甚至很繁忙。它每天處理多達40萬條新記錄,每秒更新20次。

不幸的是,刪除資料庫的訊息佇列並非易事。第一步是阻止服務直接訪問它。資料庫需要一個抽象層。它還需要一個API來聚合請求並代表它執行查詢。如果任何服務想要建立一個新事件,它就需要透過API來建立。於是,Harpoon誕生了。

得到入股的時間比你想象的要長

但是,為事件佇列構建介面是最簡單的部分。事實證明,要得到其他團隊的入股更加困難。與Harpoon整合意味著團隊必須放棄對資料庫的訪問,重寫部分程式碼庫,並最終改變他們一直以來的工作方式。那並不容易。

一個團隊接著一個團隊,一個服務接著一個服務,Harpoon工程師成功地將整個程式碼庫遷移到他們的新平臺上。這花了大約一年時間,但到2017年底,Harpoon成為資料庫訊息佇列的唯一發布者。

現在真正的工作開始了。完全控制事件系統意味著Harpoon可以自由地重新設計Droplet工作流。

Harpoon的第一個任務是將訊息佇列職責從資料庫提取到自身中。為此,Harpoon建立了自己的內部訊息傳遞佇列,該佇列由RabbitMQ和非同步工作站組成。當Harpoon把新事件推到一邊的佇列中時,工作站把它們從另一邊拉了出來。

由於RabbitMQ取代了資料庫的佇列,工作站可以自由地直接與Scheduler和事件路由器通訊。因此,Harpoon沒有使用Scheduler V2和Event Router輪詢資料庫中的新更改,而是直接將更新推送到資料庫中。2019年撰寫本文時,這就是Droplet事件體系結構所處的位置。

最大規模技術重建:資料庫連線從15000個到100個以下

在過去的七年裡,DigitalOcean已經從庫樂隊的根基成長為今天的老牌雲提供商。與其他轉型期科技公司一樣,DigitalOcean定期處理遺留程式碼和科技債務。無論是打破整體,建立多區域服務,或消除單一故障點, DigitalOcean工程師始終致力於制定優雅和簡單的解決方案。

最大規模技術重建:資料庫連線從15000個到100個以下

留言點贊關注

我們一起分享AI學習與發展的乾貨

如轉載,請後臺留言,遵守轉載規範