最近在做系統升級,由于當時設計的局限,導致系統不停服,保證服務的做法非常麻煩。當時再定方案的時候,由于自己在這方面沒有經驗,導致有些樂觀。到了實際做的時候,預期時間至少比預想的多了一周的時間,要知道,在互聯網公司,一周的時間是個非常長的時間。而這一周,還包括了OT。
在這里總結一下分布式系統設計的大忌,本來想試著分一下級,但是還是算了,一來標準太多,無法制定一個合適的規則來界定;二來自己的經驗也在增長,低調一下是自己也沒詳細的研究過超過5個分布式系統;三來做事情還是要嚴謹,不做沒有十足把握的事情。
1. 忽視服務接口的設計
雖然大家口口聲聲說對于一個集群來說,每臺機器都可能出故障。但是做方案設計的時候,某些資源卻向用戶直接暴漏了服務的實際地址。對于一個服務幾年的服務器來說,故障的可能性非常大,尤其是如果這個服務器的平時負載比較高的話。我不清楚一臺服務器的平均保修時間是多少,但是絕對不可能是幾個小時能搞定的,這個時間少則一天,多則半個月甚至更長。對于一些高級的用戶,它會使用本地的cache,或者其他的策略來屏蔽調用服務不可用帶來的影響,但是,幾天的停服對于用戶方的影響是無論如何不可能忽略的。
這種問題發現后,可能簡單的發布一個新版本的api,或者一個簡單的配置文件就可以糾正。但是對于線上用戶來說,他們運行的是一個一直都在running狀態的服務。這個簡單的改正可能需要他們服務重啟,這對于一個大型的集群來說,帶來的成本非常高。如果是因為這個服務的不可用導致了線上事故,那么應用方肯定會非常主動的去修正這個錯誤。但是如果使用架構方發現了這個問題,而主動推動應用方去修改,可能應用方會因為各種原因而推脫。
因此,設計服務的接口一定要注意,這個接口一定要是穩定的,而且后臺服務的故障,升級等操作絕對對于用戶要是透明的。不要將服務的實際地址暴漏給用戶方:這臺服務器終有一天會掛掉。尤其是對于C++等需要編譯的api來說,這個接口就更加重要了。畢竟api的修改對于應用方來說意味著要重新編譯;重新編譯意味著要重新走一下發布流程:至少要提測吧。
2. 后臺升級對用戶不透明
這實際上是又是一句大家都知道的。但是設計時確實有時候會忽略。對于彈性計算系統來說,服務的伸縮是必須的,這個也是設計的目標之一。但是對于一些小規模的計算集群來說,可能大家認為伸縮不是最重要的feature。最重要的feature就是能夠快速的完成系統設計和實現,為用戶服務。但是實際上,這個通過一些簡單的修改,就可以完成:Worker上帶一個agent和master或者meta server通信,保持心跳。心跳超時的Worker會被下線,以后的服務都不會發送到這個Worker上來。而新加入的Worker則會加入集群接收計算任務。這個不單是應對服務的伸縮,也是為了應對機器的故障。因此不用太大的改動,就可以將一個系統從山寨提升到真正的可用。
一個系統的服務質量,不是說在一般情況下的服務是可靠的,除了網絡丟包、網絡傳輸造成的問題外,服務質量可以做到10000個請求至多有1個失敗就是說這個系統是可用的。評價服務質量的另外一個重要指標是全年可服務時間。這個要將機器故障,機房故障考慮在內。如果依賴于運行環境沒有問題,才能達到99.99,那么這個服務就有點山寨,對于重要的應用方來說,這種服務不可接受。
3. 應用方設計時未衡量后臺服務失敗的影響
如果服務的可靠性要求非常高,比如是直接面向互聯網用戶的,要求任何時間都能夠對互聯網用戶提供服務,那么就需要在調用服務時做下服務不可用的預案。甚至做下超時機制:如果服務調用指定時間不返回,那么需要有其余的邏輯來替代。
當然了本次還遇到很多其他的痛點,每個都是設計上得小瑕疵,當時注意的話不會增加工作量,或者增加很少的工作量就可以做到可用。互聯網強調快,那么底線應該是可用吧。易用可能是更要的要求。當然了這個可能可以一種互聯網風格,就是一個事情可以快速做完,快速上線。當時上線時候也做了二期需要做的改進,但是后臺發現上線效果好,符合預期。又去做其它高優先級的事情去了。導致原來設計的局限就永遠的停留在那里了,這就是為后來人埋下一個坑。。
本次升級的時候,由于信息的不一致導致一臺服務器停服,導致大面積的失敗。后來為了避免其它的集群出現類似的問題,因此所有的信息都重新確認了一遍。而這帶來了半天的枯燥工作。因此,自己做設計的時候,一定要注意,不求最好,但求可用,在機器故障,服務升級,對于用戶來說,服務都可用。
BTW,正在做一個架構的設計,細節是魔鬼,正在和魔鬼做斗爭。