1. 程式人生 > >今日頭條架構演進之路——高壓下的架構演進專題

今日頭條架構演進之路——高壓下的架構演進專題

合服 51cto 還需要 ESS color 壓力 一點 日誌 規劃

今天給大家分享今日頭條架構演進,前面幾位講師講了很多具體的幹貨,我的分享偏重基礎設施及架構思路的介紹,我們想法是通過提供更好的基礎設施,幫助架構做更好的叠代。

從架構的角度,技術團隊應對的壓力最主要來自三方面:

服務穩定性?。接口的穩定性,讓服務更可靠;

叠代速度?。叠代速度對於大公司來講相對沒那麽重要,規模比較大,生存壓力相對小一點,但相對中型小型公司來講,叠代速度是必須要保證的,時間窗也是一個決定能否成功的重要因素;

服務質量?。主要關註用戶滿意度,它也是一個特別重要的 topic。
技術分享圖片

今日頭條發展特別快,只有 4 年的歷史,從人員數量和規模增長來看非常快,在穩定性可用性方面壓力比較大,一方面需要快速把業務實現,但在另外一方面,類似這些高可用的問題會經常騷擾工程師:?上線就掛、運營活動量大服務崩潰、單機性能頂不住、一個小服務上線把核心服務搞掛了……類似這些問題?,技術團隊需要如何更好的去應對?

先補充下我對架構演進的理解,在不同階段的公司都會面臨各種壓力。小公司壓力可能是業務沒起來,QPS 很低,要做優化也沒有環境及條件;當公司大了,服務器可能已經不是問題,但你要不斷考慮調優及應對訪問壓力,改善基礎設施以提供更穩定的開發環境。?所以說架構演進是持續一個過程,沒有終點。
為什麽今日頭條有這麽大的壓力?今日頭條增長速度是比較快的,從上圖可以看出,現在公司已有 4 年,2014 到 2016 年每年都是 DAU 翻番。這對業務挑戰是非常大,規模上來以後,我們原有的架構難以做到線性擴展,部分能線性擴展的服務,問題也比較多,業務增長太快,後端壓力比較大。

頭條架構發展簡史:三個歷史階段

今日頭條的架構是怎麽發展過來的?

從來沒有一個完美的架構能夠一直支撐下去,架構是動態系統、實時變化的,因為量變而發生質的變化,?不同的階段需要不同的架構?。

什麽時候需要做架構上的改造呢?當突然發現系統問題越來越多,經常出現事故或者報警特別多,溝通的效率降低等問題,很有可能你的架構出現問題了。

軟件架構有一個問題,它改動的周期相對比較長。架構的模式思路定下來,隨著業務的增長,包袱越來越大。做過基礎設施的人都有這樣的體驗:有一個好的想法很容易,但做一個好用軟件就有很多的困難。技術改造是漫長的,以年為單位。所以這個時候只能讓架構叠代更快一點。最後,不要企圖做特別完美的架構,我們只要保持敏捷演進就好了。

架構不可避免會劣化。

頭條第一階段:三層結構

今日頭條剛開始做的時候,就是一個簡單 Web 應用,搭個數據庫,把業務實現就行了。頭條最開始的優勢是推薦引擎,還有另外一套數據挖掘和離線計算。在線的服務在前端相對來講模式還是比較清晰的,三層就搞定了。業務剛開始起來的時候,沒什麽問題,訪問增大水平擴展一下就可以解決。

技術分享圖片
頭條第二階段:拆分

跟大部分公司的架構演進歷史非常相似,當上個版本遇到一些性能問題後,最簡單就做一些拆分。優化的過程中,那一塊太重了就從代碼上進行拆分。上圖中,A、B 和 C 是不同的業務,剛開始代碼是一起的,演進的過程中,叠代一年或者兩年的產品,異構去拆其實挺痛苦。
技術分享圖片
前面時代的架構,基本上沒考慮太多的人員或者規模上的發展,剛開始也沒有專門的人做架構優化,很多人都撲在業務上,把功能點加上。比如推薦的效果不好,就加強推薦,每塊都沒有專門的的人去考慮整體架構去怎麽組織規劃。

到了去年,每個季度做的預算,到第二個月機器都用完了。高峰的時候有 60% 到 70% 的壓力,這裏涉及有兩個問題:第一個問題,有些地方是性能衰減的問題;另外一個,業務壓力太大。

架構團隊需要想辦法變得更快,即使出現訪問問題,壓力大,機器不夠,也要讓我們的服務有所保證。業務一直在快速前進,包袱是比較沈重,改造的成本比較高。基於這些問題,談下我們下一階段的思路,做微服務。

頭條第三階段:微服務

目前我們的思路是通過微服務方式做新架構。通過拆分成子系統,大的應用拆成小應用,抽象通用層做代碼復用。
技術分享圖片
系統的分層比較典型。我們重點在基礎設施,希望通過基礎設施提高快速叠代、容災和一系列的工作,希望各個業務團隊能更快做業務上的叠代以及架構上的調整。

微服務架構

微服務我們認為最關鍵的三點

解耦,一個服務會依賴另外一個服務、模塊或子服務的概念。

輕量,減輕維護人員的成本。

易管理。

技術分享圖片
現實中微服務的關鍵是自治。雖然微服務是自治自包含,但也需要有一個層級。比如你提供的服務是外面公司提供的,微博提供的服務,你不能夠要求微博為你得服務去做更改。微服務要有界限,在公司層面,不能讓它過於獨立,過於獨立會增加溝通上的成本。基礎設施和規範最好能復用。

現實中的微服務是什麽樣的?

??架構必須要落地成具象的東西。微服務有一個開發框架,做業務的同學根本不需要關心容災,也不需要重復做這樣一套東西,這個東西怎麽部署,他們也不用關心;

??需要有一個流程規範性去約束。有規範就可以做全局優化;

??微服務的表現形式是提供一個平臺或者一些工具。

頭條服務化的現在及未來

最後再給大家介紹前面服務化的思路在今日頭條是怎麽執行的?怎麽給各個業務團隊開發者提供服務?

頭條的主要服務化思路如下:

??立規範?。規範怎麽做?部署 RPC,一個服務調另外一個服務是怎麽做的?創新我覺得沒有問題,但你得考慮給其他人帶來成本,這個規範還是需要有的,這樣可以做全局控制。服務化的穩定和統一,你要考慮它帶來真正的優勢,性能高是一個點,但是本地優先會好一些;

??打基礎?。有了規範以後,開始真正落地的服務。比如說基礎庫,把Ngnix、Redis、MySQL這些庫封裝起來,統一起來做一些事情。開發框架,你不用關註數據去優化;

??漸進?。先拆離再叠代,把服務優化進來;

??一切都是服務?,第四點是和其他公司或團隊稍不一樣的地方,我們的想法是一切都是服務,每個節點都是抽象歸屬於某一個具體的服務。存儲的確是一個服務,但它不只是提供 API 或者提供功能的東西,還需要包括服務質量,需要別人用起來是比較簡單的;

??平臺化?。最後的落地是平臺化的東西。我們框架是怎麽設計,和服務怎麽結合?

技術分享圖片
首要規範:一切都是服務

??資源是有限的:按需申請,需申請和授權;

??簡單的使用方式:開發者只需要關註業務;

??有唯一定位的方式:用全局資源定位;

??最後,每個服務都有擁有者(owner),偏工程架構方面的東西,我的規範必須可執行的。

我們的規範

??必須要有全局的中心,服務統一註冊到 consul 中;

??服務有唯一的標示、命名範:{產品線}.{子系統}.{模塊} P.S.M,公司有很多部門,我們不希望部門之間溝通起來有差異,所以需要有全局規劃去追溯它;

??業務服務使用 Thrift 描述接口、必須傳遞標準參數。如果用弱的描述數據,沒有強約束,在客戶端的數據可能會出現類型錯誤;

??RPC 使用統一收斂的庫;

??Nginx、Redis、MC、MySQL、etc 都是服務

服務註冊

我們服務統一使用 loader 或 wrapper 腳本啟動,具體啟動由業務決定。

服務啟動會有一個名字,把 app 註冊到服務裏面,看起來有一些約束,數據庫MySQL 可以啟動嗎?Redis 可以嗎?

啟動的時候,服務方式不用去管,就用同一個框架,一個新的規範,容易把已有的服務遷移上來,但這不是個特別強的規範,考慮遷移成本。?輕規範,易遷移。
技術分享圖片
服務中心

服務中心有服務信息,會同時帶上是什麽樣的服務,其他人比較簡單的調這個服務就 OK 了。這個服務到底提供什麽樣的服務質量,擁有者可以管理這個信息。Redis去服務,負載均衡,服務一個項目,把服務接上去。
技術分享圖片
服務關系與授權

服務之間有個關鍵的概念:服務授權。一般我們起一個服務,通過 IP 就可以連上它了。數據庫有用戶名認證,也可以對 IP 授權。不過內網很多服務限制比較少,不是所有服務都有授權認證。我們希望把服務之間的關聯關系,全局拓撲關系記錄下來並且可執行。
技術分享圖片
一個服務提供接口,我們可以由 owner 來做授權,其他服務授權後才可以訪問它。技術分享圖片
描述信息:這個服務是什麽樣子?最大的 QPS 是多少?通過描述信息發現問題,用戶信息服務托不住了,就拒了,把資源分到其它服務上面,就可以做更多的東西。還有機房信息可以放在這裏面。

服務授權認證思路:

??基於服務標示,重要服務增加更多認證方式;

??協同認證,客戶端自身協助認證。

舉一個 Thrift 的例子。這兩邊有兩個虛線,服務中心水平擴展能力很強,向它要基本授權的信息,我可不可以調這個服務?默認是可以,就是一個 Thrift 包,我知道你是誰,自己做策略,服務包帶過來。請求帶上來,分析調用是不是有問題,這也是規範的一部分。開發的同學是不用關心框架這邊如何做的。

技術分享圖片
另外一種向服務中心調用服務,把你拒了。QPS 壓力大,已經支持不了你。一個好處是可以避免浪費資源;另外,虛擬化 Docker 的環節。以前的思路按 IP 授權,每一個 IP 做控制,提供類似於匿名服務,根據節點所屬 IP 去做。現在用 Docker 拿一個標識不太好做,在網絡層也不太好做,在內網環境下有一定的可信,我自覺告訴你,我是誰,然後調用。

MySQL 目前正在做的一個方案見下圖,不像 Redis 要求帶上你是誰,調用 MySQL 需要把調用方是誰帶上來。一個重要數據庫,肯定做安全授權,我剛只是說常規情況下。這幾種方式疊加起來做,把原信息帶過來,Redis 帶過來,做加權校驗。

技術分享圖片
Redis 在協議層做不了,而 MySQL 在調用中增加上述信息不會影響語義。我們服務器提供 HTTP 接口就可以在 HTTP 頭提供這個信息做授權認證。
技術分享圖片
有授權關系,所有的服務構成完整服務的拓撲關系。一個服務預先授權才能調它。如果有線上真實的拓撲關系,就可以做報警優化。Redis 報警了,MySQL 報警了,有這樣的拓撲,會提升問題追查的速度。

我們有了這樣的拓撲信息,知道服務的全局元信息,我們就可以更好的做服務變更的影響評估和報警等等的優化。
技術分享圖片
RPC 開發框架

我們自己開發了一個 RPC 框架。開發框架會幫助我們開發代碼,這個事情很多人都在做。它的主要特性包括:

??快速開發:代碼生成;

??服務發現:理解服務化;

??可觀測性(Observability):logid, pprof, admin 端口;

??容災降級:業務降級開關;

??過載保護:斷路器,頻率控制;

??多語言支持:Python/Go

比如可觀測性是說所有的服務都能暴露內部的狀態,這有非常好的優勢,服務上來以後,默認剖析內部的端口或者服務端口,服務上線與平臺。根據拓撲關系自動分析出來服務狀態,甚至做性能剖析,開發者可以不用關心這些事情,天然獲得這些能力。

還有容災降級,還有過載保護,我們還有一個平臺管理關聯關系和降級,你可以更多關註業務。

下面是大概模塊的示意圖,通過模塊化的方式,而不是嵌入到框架裏面,使我們的維護成本更低。
技術分享圖片
前面服務是自治的體現,跟 Docker 比較像,我們也會做容器化的開發。只是把服務跑在容器內還遠遠不夠,把服務化體系打通,我們思路實現開放,實現我們“有態度”的私有雲,把基礎設施這一塊讓我們平臺做,業務部門只關心業務。

我們目前到這個環節,做一個服務的重構,我們的私有雲構建。前面的框架,

不斷去叠代。

最後我們和虛擬化 PaaS 平臺怎麽規劃?

我們通過三層實現,通過 PaaS 平臺統一管理。提供通用 SaaS 服務,同時提供通用的 App 執行引擎。最底層是 IaaS 層。
技術分享圖片
IaaS 管理所有的機器,把公有雲整合起來,頭條有一些熱點事件會全國推廣推送,對網絡帶寬比較高,我們借助公有雲,需要哪一種類型計算資源,統一抽象起來。基礎設施結合服務化的思路,比如日誌,監控等等功能,業務不需要關註細節就可以享受到基礎設施提供的能力。

Q&A

Q:剛才講單體服務拆分成微服務成本是不是有所增加,你怎麽考慮?

夏緒宏:我在過去建一個數據庫,直接跑起來。以前把整個庫升級,現在只需要升級一小部分,業務比較簡單規模比較小的時候單體服務確實成本低。當你的業務增大機器增多,單體服務會成為瓶頸,但是微服務如果是標準化的,可以用自動化的工具、平臺去管理,不能靠人去管理,因此成本反而是降低的。

Q:把服務跑在容器裏面,用了 consul,自身的容器和 IP 等自身的信息註冊到consul,更新您授權的 ACL?

夏緒宏:這的確是一個思路,我們用了 consul 是去中心化,不過也是增加了一層。如果你需要控制微服務的訪問與安全,容器節點還要分級別,比如我會分到小集群,物理層是隔離,以這種方式實現安全的。僅是 consul 是不夠的。

Q:RPC 服務發現是什麽?RPC 是自己實現的?

夏緒宏:服務發現是 consul;RPC 是自己在 Thrift 基礎上實現,服務調用上也實現了熔斷機制。

Q:選型的時候為什麽不用開源,我們是整個平臺的架構準備做微服務的改造,想選一下服務的架構,您這塊是自己做的,我們在開源和自己做之間在選。能舉一個例子?

夏緒宏:看場景,你們現在什麽都沒有可以考慮各種開源方案,我們也有一些自己特殊場景,開源的東西跟內部服務做整合,需要考慮一些整合成本和我們自己維護的成本。很多時候開源項目會出於普適性,會考慮的特性比較多一些,代碼也會相對復雜,有些功能我們用不到,我們要去做改造,整體上不復雜;

授權標準也是自己做的,基於服務標識,服務器裏面,並沒有考慮場景互聯。

Q:我們現在如果做微服務平臺改造,業務系統開發模式是不是有比較大的改變?我們平臺從開發模式到設計都會有所改變,你們改造過了,你們有哪些經驗?

夏緒宏:我們改造到現在也沒改造完,這個改造挺困難的。你先定好一個大方向,因為很多東西是涉及到溝通的問題,推動的問題,你先需要溝通好的方向,達成一致,到怎麽改造,機動性少一點,或者你把大部分的功能實現好,只需要做小小的遷移,減少遷移的成本。

今日頭條架構演進之路——高壓下的架構演進專題