您好,登錄后才能下訂單哦!
今天給大家分享今日頭條架構演進,前面幾位講師講了很多具體的干貨,我的分享偏重基礎設施及架構思路的介紹,我們想法是通過提供更好的基礎設施,幫助架構做更好的迭代。
從架構的角度,技術團隊應對的壓力最主要來自三方面:
服務穩定性。接口的穩定性,讓服務更可靠;
迭代速度。迭代速度對于大公司來講相對沒那么重要,規模比較大,生存壓力相對小一點,但相對中型小型公司來講,迭代速度是必須要保證的,時間窗也是一個決定能否成功的重要因素;
服務質量。主要關注用戶滿意度,它也是一個特別重要的 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:我們現在如果做微服務平臺改造,業務系統開發模式是不是有比較大的改變?我們平臺從開發模式到設計都會有所改變,你們改造過了,你們有哪些經驗?
夏緒宏:我們改造到現在也沒改造完,這個改造挺困難的。你先定好一個大方向,因為很多東西是涉及到溝通的問題,推動的問題,你先需要溝通好的方向,達成一致,到怎么改造,機動性少一點,或者你把大部分的功能實現好,只需要做小小的遷移,減少遷移的成本。
原文發布時間為:2018-08-17
本文作者:夏緒宏
本文來自云棲社區合作伙伴“ 數據和云 ”,了解相關信息可以關注“ 數據和云 ”。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。