歡迎光臨
每天分享高質量文章

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

架構壓力主要來源


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


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

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

  3. 服務質量。主要關註用戶滿意度,它也是一個特別重要的 topic。


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


先補充下我對架構演進的理解,在不同階段的公司都會面臨各種壓力。小公司壓力可能是業務沒起來,QPS 很低,要做優化也沒有環境及條件;當公司大了,服務器可能已經不是問題,但你要不斷考慮調優及應對訪問壓力,改善基礎設施以提供更穩定的開發環境。所以說架構演進是持續一個過程,沒有終點。


為什麼今日頭條有這麼大的壓力?今日頭條增長速度是比較快的,從上圖可以看出,現在公司已有 4 年,2014 到 2016 年每年都是 DAU 翻番。這對業務挑戰是非常大,規模上來以後,我們原有的架構難以做到線性擴展,部分能線性擴展的服務,問題也比較多,業務增長太快,後端壓力比較大。


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


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


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


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


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


架構不可避免會劣化。


頭條第一階段:三層結構


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



頭條第二階段:拆分


跟大部分公司的架構演進歷史非常相似,當上個版本遇到一些性能問題後,最簡單就做一些拆分。優化的過程中,那一塊太重了就從代碼上進行拆分。上圖中,A、B 和 C 是不同的業務,剛開始代碼是一起的,演進的過程中,迭代一年或者兩年的產品,異構去拆其實挺痛苦。



前面時代的架構,基本上沒考慮太多的人員或者規模上的發展,剛開始也沒有專門的人做架構優化,很多人都撲在業務上,把功能點加上。比如推薦的效果不好,就加強推薦,每塊都沒有專門的的人去考慮整體架構去怎麼組織規劃。


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


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

頭條第三階段:微服務


目前我們的思路是通過微服務方式做新架構。通過拆分成子系統,大的應用拆成小應用,抽象通用層做代碼復用。



系統的分層比較典型。我們重點在基礎設施,希望通過基礎設施提高快速迭代、容災和一系列的工作,希望各個業務團隊能更快做業務上的迭代以及架構上的調整。


微服務架構


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


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

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

  3. 易管理。



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


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


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

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

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


頭條服務化的現在及未來


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


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


  • 立規範規範怎麼做?部署 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;


轉自:高可用架構

微服務

從已放棄到再入門


極客時間推出熱門微服務課程,幫你從0開始構建微服務知識體系。微服務不再是大企業的奢侈品,而是每個企業的必需品。



微博技術專家帶你深入微服務技術,跨越從程式員到架構師的分水嶺。幫助學習者循序漸進的掌握微服務知識。限時優惠分享返現

溫馨提示:

請搜索“ICT_Architect”“掃一掃”二維碼關註公眾號,點擊原文鏈接獲取更多電子書詳情

求知若渴, 虛心若愚

赞(0)

分享創造快樂

© 2021 知識星球   网站地图