達達集團高可用系統架構進化之路

達達是一個年輕的創業公司,在整個創業過程中,遇到了各種各樣的問題,解決這些問題常常會受到人力資源以及時間的限制,如何帶領團隊搭建最高性價比的系統架構是我着重分享的內容。所以副標題是——小廠的經濟適用性方案。

我們團隊做方案,一直秉承一個原則——如何獲取最高的性價比,所以我分享的各種方案也許不是最先進的,也許不是功能最完善的,但是一定是在當時環境下,性價比最高的。

今天的分享共有三部分。首先是 2017 年達達集團遇到的困難與挑戰,其次是我們採取的解決方案,最後是達達集團未來的一些迭代以及優化。

1
困難與挑戰

達達高峯時期接近日千萬的單量級別,數據庫大概在萬級的 TPS ,大概有 150 個微服務,1000 多個虛擬機節點,業務跑在單雲雙機房上。

達達的技術棧非常簡單,整個的服務治理直接把 consul 拿來,沒有做任何的修改就直接使用;

公司的監控系統是基於一套 Log 的分析系統,我們將 Log 分析系統拿來,經過清洗之後,塞到 TSDB 或 ES 裏;

技術棧是 Java 和 Python 共存的狀態;

中間的 RPC 協議是最原生的 HTTP + JSON 等等。

以上是公司背景,我們來看看都有哪些問題?

第一類是中間件宕機問題,這個問題最讓我們苦惱。任何一個數據源宕機諸如數據庫、Redis、消息隊列等問題,至少需要 10 分鐘才能恢復過來。當時確實束手無策,除此之外,冷備資源及其數據同步也浪費了大量的資源。

第二類是內部流量問題。首先是內部流量無法限流問題,由於某些 Bug 或參與策略,內部相對核心的服務直接被核心較低的服務殺死;

其次就是冷熱分離問題,訂單系統承載了離線以及在線的業務需求,運營人員一次提取幾萬個單子,對系統的損耗是非常大的,這些請求雖然沒那麼重要,但是卻擠壓了重要業務的性能。

除去內部流量以及冷熱分離之外,壓測問題也比較大,達達的流量高峯與電商幾乎同步,每年的 618、雙 11 大促是流量的最高峯,在這些大促之前需要進行很多的壓測,但是由於沒有合適的工具,我們只能提前購買一批大批機器,重新部署一個完全網絡隔離的環境,把中間件、數據庫以及所有的服務重新搭建一遍,非常耗時耗力,性價比非常低。

最後一部分是在線測試問題,達達的每個核心服務有一羣人在修改,每個人修改出來的版本不同,但這些不同版本的服務無法同時測試。大家想要測試,要麼排隊,要麼搶資源,測試的效率非常低。

第三類是監控系統的問題,當時的系統是基於 Log 的監控系統,出現問題之後很難找到根源節點,任何一個事故發生,所有的系統都在報警,等大家找到問題所在,十多分鐘已經過去,大大地延誤了我們的戰機。其次是業務邏輯的 Bug 得依靠客服反饋,基於 log 的一套監控系統,是無法顯示不報錯 Bug 的,只能依靠客戶反饋,這讓我們的技術同學很難堪。

2 從發現問題入手

解決問題的前提是發現問題,如果問題都無法發現的話,解決問題就無從談起,想要解決這些流量治理或高可用的問題,我們希望把監控系統重新開發一次。

我們整理當時監控的所有需求,將監控系統定義了三個層次,針對每個不同的層次開發了一套額外的監控系統。

第一套監控系統——集羣級別的監控系統,這套監控系統可以看到集羣內部運行的所有的微服務。這是一個鳥瞰圖監控系統,而且當進入監控系統的任何一個圈裏,你還可以看到整條調用鏈。

這套監控系統有兩個先進之處,首先它可以讓我們瞭解系統的健康狀態。其次它解決了「發生了事故,卻無法找到根源的問題」,這整套的可視化的調用鏈,可以很輕易地知道報錯的節點。

第二套是時序業務和系統監控。基於 Log 的這套監控系統,其實存在很多問題。首先 Log 系統只能分析 Access Log 或 Air Log 之類的,所以 Log 收集上來的信息數據遠遠不夠 。其次系統擴展性非常差,如果我們想要埋點,Log 系統是很難做到,所以我們把整套的 Log 系統推翻掉,重新開發了一遍。

整套架構比較簡單直接,上圖綠色的框裏的內容都是經過二次開發的開源產品,實質上我們開發了一套 Metric 的收集系統,將 Metric 的收集系統當成一個 SDK 做到了業務系統裏,這套收集系統可以收集幾乎所有的技術指標,比如說 GVM 的信息、各種錯誤信息、異常的類型。其次達達開發了 Server,這個 Server 就是一個 Metric 收集器,達達每天大概有幾十億個 Metric 的點會彙報到這裏,在 Server 上可以進行數據清理以及數據格式化之類的工作。

團隊開發 Server 之後,將這些數據塞到 Kafka,放置到 InfluxDB 裏,我們在 Influx 外圍包了一層類似於 InfluxDB 集羣——它可以做自動的數據路以及各種 HA 的事情。InfluxDB 的展示層,很多人都使用 Grafana, Grafana 可以對接多個數據源,我們對 Grafana 也做了一些二次開發,使其可以支持同比環比的數據展示等等,至此全新業務和系統監控完成了。

比如業界比較通用的這種流量或者數據打標的方案無法進行,因爲這套方案需要很多改造,對於我們業務同學不太可能接受。另外一些現成的開源方案,如阿里的 Double 可能也不能用了,因爲它不支持 Python,所以後來決定自己進行,如果不能做流量和數據打標,我們就只能做節點打標,節點打標的好處是對業務來說完全透明的,架構和運維可能直接幹掉,其他儘量保持不變。

說到節點打標,我們發現真正所有流量相關的需求無非兩大類——隔離問題與路由問題。反觀現有的一些原數據是不足以做出整套流量治理方案的,所以我們又重新引入了兩套新的原數據。

一套原數據是鏈路,引入鏈路是爲了做隔離。現在達達集團鏈路的隔離方案,一共三套環境,生產環境、測試迴歸環境和開發環境,這三套環境之間的網絡是完全物理隔離的,但是每個環境之間通過鏈路來邏輯隔離。以壓測爲例,可以把線上的機器分割爲兩套不同的環境,一套是生產默認電路,另一套是專門爲壓測使用的壓測電路。因爲有了鏈路概念,所有工程都能擁有一套沙箱環境或者說沙箱鏈路,團隊之間的測試和開發工作互相不打擾。通過引入了鏈路這個概念,解決了流量邏輯的問題。

另外我們還需要一個概念解決路由問題——服務分組。

上圖是現實應用場景的示例圖,服務 B 可以分組,一個分組專門爲離線業務調用,慢一些也沒有關係,其餘的隔離分組爲在線的核心服務 A 提供調用。

當引入兩套原數據之後,我們就可以解決隔離和路由的問題,但是如何使用原數據?我們又在元數據的基礎上開發了一套規則協議,這套規則協議很簡單,用 JSON 就可以完成。具備所有必需的原數據以及對源數據操作的規則引擎之後,我們就剩下開發工作。

在發起調用以及發送請求之間,增加兩步就可以做到隔離和路由。我們提供了一套 SDK,第一步獲取隔離性,獲取一些鏈路的信息,第二步根據 IP 接口等匹配路由,然後直接發起調用。另外因爲實現過程非常簡單,所以未來只要進行一些擴展,就可以處理各種流量治理方面的問題。

採用這整套系統的效果非常不錯,兩位同學從設計、開發、測試到最終上線,兩個季度搞定。有了這套流量治理的方案之後,壓測資源從 250 人日提升到 70 人日,提升了接近 4 倍。

針對之前令我們最難受的數據源節點宕機問題,我們非常希望有一套自動 Recover 的方案。

最早之前是非常簡單的直聯方式,數據庫上 IP 地址都是從配置中心提取出來,如果一旦宕機發生,其實需要經歷以下步驟才能把整個系統恢復過來。

首先需要把配置中心裏的數據源 IP 地址修改爲備用集羣的 IP 地址,進行配置下發,最後所有受影響的應用服務都需要重啓。因爲整個過程中間需要有人工參與,所以 10 分鐘已經是最短的恢復時間,但是這對業務來說是不可以被接受的,所以達達決定開發一套快速恢復的系統。

當我們在開發系統的時候,我們有很多的選擇。最簡單的方法是既然 MySQL 是單機的,我們能否使用一些自帶 HA 功能的數據來替代 MySQL,典型的例子是 TiDB 以及 Redis;Redis 其實也一樣,我們之前 Redis 只是用 Proxy 模式,但是我們能否用 Redis Cluster 來替代;最後是雲廠商提供的一些高可用方案。

調研之後,這三項選擇都有一些問題,首先我們業務對主從延遲、響應時間要求挺高,TiDB 的性能無法滿足我們的業務需求。

其次 Redis Cluster 確實可以做,但是從 Redis Proxy 模式切換到 Redis Cluster 的模式,切換成本非常高,所以我們決定做,但是我們無法等待切換完成,第一是耗時太長,第二即使它做完,我們真正數據庫的問題還是沒有解決掉。

最後是雲廠商高可用方案,這個問題就更多了,首先這些方案不支持定製,不夠靈活。其次使用雲廠商的方案,數據遷移的成本也是非常高。

這三條路都行不通,達達還是決定自己研究。我們希望有一套方案——它可以讓任何的節點可以自行恢復,並且能覆蓋的 MySQL 和 Redis 以及其他數據源的通用方案,當然還得具備數據源治理的功能。

數據源或者中間件宕機自動恢復,總體分解出來只有兩點:第一,只需要在故障的時候能把它檢測出來,監測出來之後觸發一個切換。第二,只要應用服務能偵測到切換的 Event,它能重新建立連接就可以。

故障監測的過程,一個比較原生的想法是做一套探針,這套探針分佈在集羣裏的各個地方,可以實時地去監測所有數據源的健康狀況,但是如果使用探針系統,有很多的細節問題是需要考慮的。例如如何在保證探針監測準確性的同時,又能保證它的敏感性?

後來我們發現在流量治理時候使用的 Consul 系統,其實就是這樣的一套探測系統。Consul 原生自帶的高效協議是一個點對點的偵測協議,直接利用 Consul 將數據源當成無狀態的服務納入到 Consul 管理中就可以搞定。

後來我們又對 Consul 進行了一些二次開發。事實證明,這套方案是完全沒有問題的,成本非常低,不需要自己寫探針,不需要考慮細節的技術問題,僅僅使用 Consul 的原生能力就可以,但是我們做了一件很多人都不會做的事——把有狀態的服務納入到無狀態的節點管理中。

當健康檢查之後,第二步只需要興起 Watcher 服務,這個 Watcher 服務只需要實時監聽數據源的健康狀態。

如果任何一個數據源的節點,Consel 判定它是不健康的狀態,觸發切換就可以搞定了。緊接着興起一個 Watcher 服務監聽數據源狀態,在故障的時候進行切換,最後就是應用服務,讓應用服務能感知到切換就可以了。

綜上所述,我們開發了一套架在連接層的數據源中間件,它是不接觸 GDBC 或者 Redis 協議的,所以這套數據中間件的接入不需要業務改動任何已有的東西,業務端只需要從 Consel 裏面監聽依賴的數據源節點的信息,如果信息一旦發生變化,業務端只需要關閉之前的連接,重新建立一套連接就可以。到此爲止,高可用或者說數據源的故障自動恢復方案已經完成。這套方案的效果非常好——在 30 秒到一分鐘之內,任何的節點宕機都能自動地切換過來。

3 未來的迭代優化

2017 年的大部分各種問題都已經被解決,但是還有些問題沒有解決。例如達達仍然需要準備很多的冷備資源,中間的數據同步管道,成本上可能也不是最優的。

我們想嘗試使用一些自帶 HA 功能的系統來替代現有的系統,其實 MySQL 官網也提供了 MGR 的解決方案,但是因爲中間切換時間成本的問題,這套方案還在調研以及運行過程中,但是如果這套方案其實就跟 Redis Cluster 一樣,它自己可以管理集羣,對我們來說,這將會節省掉近 50% 的機器。

其次是消息隊列,目前內部消息隊列是兩套系統,在線服務運行在 RabbitMQ,離線的 Log 之類的大數據服務運行在 Kafka 上,這兩套消息隊列系統並存的時候,管理成本非常高,並且 RabbitMQ 本身會存在瓶頸,比如它有一個比較明顯的性能上限,以及它自帶的 HA 對機器資源的佔用非常高。

我們想要把兩套消息中間件合二爲一,完全統一到 Pulsar 裏面,Pulsar 可以既支持這種在線的隊列消息,又能支持這種 pop sum 模式,而且本身不管從性能上以及運維成本上都是非常有意思的。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/IvG_G2fl0fC4oLIpk5ln7g