本文做者:HelloDeveloperphp
起初,在網盤快速發展期,爲了快速上線,採用了服務單體化 + 主幹開發模式進行研發,隨着用戶規模爆發式的增加以及產品形態的豐富,單體化的不足就體現出來了,因而架構上採用了微服務架構,開始對業務邏輯進行拆分部署。mysql
服務拆分以後,也引入了新的問題,具體以下:nginx
爲了解決這個問題,從2015年末開始思考解決方案,肯定了解決問題的核心在於管控請求流量
,在2016年開始自研網絡流量轉發中間件
- UFC(Unified Flow Control)
,業務經過同機部署的agent進行服務通訊,相關的發展史以下:redis
後來在調研業界相關技術的時候,發現了istio(業界Service Mesh的典型表明)
,從而發現了Service Mesh的存在,而它的定義是在2016.9 由Buoyant 公司的CEO William Morgan 提出的:sql
Service Mesh是一個專門用來處理服務和服務之間通訊的基礎設施。它複雜確保在一個由複雜服務構成的拓撲的現代雲應用中,請求可以被穩定的傳遞。在實踐中,Service Mesh一般經過一系列輕量級的代理來進行實現。這些代理和應用同機部署,而應用不須要感知到代理的存在。數據庫
A service mesh is a dedicated infrastructure layer for handling service-to-service communication. It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern, cloud native application. In practice, the service mesh is typically implemented as an array of lightweight network proxies that are deployed alongside application code, without the application needing to be aware.編程
從定義上,咱們不難發現UFC和Service Mesh的設計理念是一致的
,都是基於sidecar模式,有着控制面板和數據面板,UFC是Service Mesh的一種實現
。感慨的說,歷史的發展潮流是一致的,無論你在哪裏。後端
目前UFC應用於網盤過千個服務上,涉及虛擬化實例數量超過20W,千億PV,機器規模10W+(網盤+其它產品線機器),10個IDC
,從已知的實例規模上看,是國內最大的Service Mesh的實踐落地。安全
百度網盤的實踐落地並不僅侷限於Service Mesh,首先是構建了從點延伸到線的Service Mesh進行服務通訊管控
,而後是在UFC這個Service Mesh的基礎之上,站在全局視角對服務進行治理
,保障服務的穩定性,相關能力等發展以下:服務器
點
:關注與下游進行通訊,不關注上游的狀況線
:加入上游的標識,基於上游作異構的通訊策略面
:多條線組成面,站着全局視角進行服務治理
本文將會先介紹UFC(如何實現一個Service Mesh
),而後是基於UFC作服務治理(基於Service Mesh的實踐應用
)
只須要作兩個事情:
UFC爲每一個註冊的服務分配一個service_name
,service_name 是這個服務的惟一標識。同時須要對這個service_name配置它的相關配置:好比destination來源、負載均衡、熔斷、超時重試等策略
訪問下游的時候,只須要訪問本機固定端口
,帶上下游服務的service_name、自身標記、trace等信息
,例以下面就是一個發請求的demo例子:
curl 「http://127.0.0.1:8888/URI」 -H 「`x-ufc-service-name`=to_service_name」 –H 「`x-ufc-self-service-name`=from_service_name」 -H 「`x-ufc-trace-xxxx` = xxxxx」
介紹UFC基於點和線視角的相關能力,從服務聲明、請求路由、流量轉發、故障處理、故障定位、安全等維度和istio作了一個比較。而istio是大部分是基於下游這個點進行相關通訊能力設計,線視角能力不多(好比權限認證等)
總結來講,istio是能力全面,可是具體實現上策略比較簡單,而UFC是更貼近實際的業務場景
(具體的能夠看後面的介紹內容)
PS: 有些能力(好比流量複製/權限管理)UFC沒有,並表明百度網盤沒有這方面的能力,只是由於歷史緣由,經過其它的方案解決了。可是故障注入這塊,的確是UFC須要考慮的,有了這塊的能力,混沌工程也更容易的落地。
主要是介紹架構和相關具體能力的實現設計初衷
整個架構和Service Mesh同樣,都是採用了同機Sidecar進行了流量的轉發 + 中心化控制。
UFC組件
單機上的配置是全量的,經過版本號進行增量同步(全局的版本號+服務級別的版本號),同時會經過monitor監控配置是否同步成功
對於一個實時運行的系統,如何實時獲取相關的stat數據,用於問題定位呢?好比想獲取當前封禁後端列表之類的
爲了知足需求,增長了一個獲取數據的接口,獲取內存裏指定字段的數據,以^爲分隔符。好比如下demo就獲取了一個服務的動態數據,包括了請求次數,更新時間,失敗次數等信息
request: curl -v -H "token:token" 'http://10.10.11.11:8888/bypass?command=query&ar=request_info^pcs-upload' response: { "request_info": { "5xx_cnt": 2, "mtime": 1573456024, "request_cnt": 6, "success_cnt": 4 } }
主要介紹UFC基於點和線的相關能力細節以及設計出發點
提供相關的匹配能力,根據匹配條件進行後續相關的操做,好比設置後端的權重等進行多版本灰度測試、流量遷移等功能
基於請求特徵作路由匹配,例如http request header: headers[「x-http-flow-control」],能夠按隨機比例 或者 等價 進行匹配
相似於istio的路由規則
基於上游匹配是從線視角出發,UFC的線視角以下:
爲啥要作基於上游匹配,出發點以下:
流量等級
:
不一樣的上游服務重要性也不同,產生請求的重要性也不同,因而基於上游的標誌設置異構的策略就頗有必要。好比網盤的用戶文件列表展現服務和多端列表同步服務同樣會訪問數據庫,顯然前者比後者重要,用戶直接感知,須要區別對待。而若是是重試請求,這裏面的重要性又不同了,爲了簡化策略配置,目前在將請求權重化,根據若干個請求因素的計算出請求權重,而後根據請求權重執行不一樣的策略。
具體的實踐落地:請求權重能夠用於細粒度的降級策略。
機房策略
:
上游訪問下游,默認是不關注上游請求的來源機房,也不關注下游endpoint的機房歸屬,流量在機房之間是混連的,那麼當時候,要切空機房流量異常麻煩。基於上游請求的機房的標識設置機房路由規則就頗有必要了。
具體的實踐落地:能夠定製機房轉發策略,好比流量在同一個物理 或者 邏輯機房內轉發,詳見下文流量轉發裏的基於上游轉發。
從協議、負載均衡、基於上游轉發、傳輸策略四個方面介紹
Istio 只支持http/tcp/grpc協議,而業務使用的協議確定不止這些協議,好比redis/mysql等,若是都支持這些協議以及後續的其它協議,那麼兼容的研發成本將很是的高,在用戶需求和研發成本之間,UFC找到了折衷的解決方案實現了支持任意協議
,具體上是以穿透式和旁路式進行落地的
穿透式請求
: 適用場景爲http協議控制流,和istio的使用方式同樣
旁路式請求
: 增強版的DNS,適用場景爲http 協議數據流 or 非 http 協議,業務先從UFC拿到一個後端地址,而後業務本身經過這個後端地址訪問後端,最後須要回調UFC告知UFC此次通訊的結果,方便UFC更新相關數據(好比該後端的訪問成功率等,決策是否須要封禁之類的)。經過旁路式解決了任意協議的場景,同時對後端流量進行了管控。
採用了比較常見的負載均衡策略,好比輪詢、隨機、一致性hash(根據業務定義的字段進行hash)
主要的應用在於上下游IDC流量路由上,好比設置完下面的路由表以後,就實現了同(邏輯/物理)機房的流量轉發
主要是從鏈接策略、超時策略,重試策略介紹的
鏈接策略
:
超時策略
:
重試策略
:
從故障的範圍影響上分紅:
從故障處理流程上分紅:
故障處理具體發現故障和解決故障兩方面的內容,難點在於發現單點故障的準確性,是否存在漏判
發現故障
一個後端返回404的http status code,這個是符合預期的?
沒人知道,由於常規狀況下業務也會返回404,而在LNMP架構裏,若是單個實例磁盤問題致使PHP文件丟失,Nginx找不到PHP文件,也會返回404,這是一個混沌的狀態
。UFC的解決方案,就是和平均值進行比較,看是否偏離平均值。以 下圖後端狀態碼區間比例統計爲例子,後端2 4xx的http code達到了100%,而其它的後端這個比例也只有不到5%,那麼大機率後端2 就存在問題。
解決故障
主要是針對雪崩過載的場景下如何儘可能保障服務可用,也是從發現故障和解決故障進行介紹的,難點在於如何減小故障帶來的業務流量損失
發現故障
解決故障
PS: 動態熔斷的思想是借鑑了網絡,當雪崩過載的時候,至關於發生了請求的擁塞,和網絡擁塞是同樣的特徵行爲,網絡鏈路都帶寬至關於服務的容量
儀表盤基於數據源進行分析獲得如下內容
有兩方面的數據源:
什麼時候
由上游A
對下游B
進行訪問,請求
經過了後端
X1/X2進行訪問,重試
了N次,耗時
爲T1/T2等,狀態碼
爲S1/S2等
首先基於服務通訊access日誌作鏈路分析,而後將鏈路信息存入Elasticsearch方便檢索,好比下圖就是一個鏈路檢索
從點、線、面視角上進行數據的聚合分析
點視角
:後端維度
服務後端異常監控
:單實例異常觸發封禁
:觸發封禁的後端,長時間封禁走paas遷移流程
服務觸發熔斷
:觸發服務動態熔斷降級
線視角
:上下游維度
服務下游監控
:服務訪問全部下游的概貌,支持按http 狀態碼和idc作過濾,同時支持環比(昨天/一週前)。下面以視頻轉碼爲例子,展現對若干個下游的訪問概貌:
請求數
: 能夠根據曲線分析是否存在異常
請求失敗數
:根據失敗數量能夠算出上游對下游的請求sla
請求耗時
: 能夠比較昨天/上週的耗時數據,看是否存在異常
服務上游監控
:服務被全部上游訪問的概貌,能夠按http 狀態碼和idc粒度進行過濾,同時支持環比(昨天/一週前)。下面以一個異步化服務爲例子,被一堆的上游訪問,統計這些上游的訪問概貌:
請求數
: 在定位服務的請求數突增,能夠很容易識別出是哪一個上游致使的
請求失敗數
:若是一些上游訪問失敗數比較高,能夠聯繫業務進行分析定位
請求耗時
: 能夠比較昨天/上週的耗時數據,看是否存在異常
面視角
:全局視角
核心功能鏈路SLA監控
:當鏈路sla下降的時候,能夠很快定位到是哪一個鏈路分支出現的異常
耗時維度
:所有服務裏,耗時增長top 10 業務,快速知曉業務概貌
業務失敗率維度
: 所有服務裏,失敗數最多的top 10業務,快速知曉業務概貌
機器維度
:所有機器裏,請求5xx失敗最高的機器 top 10,快速知曉機器異常
如前文所述,服務治理是創建在Service Mesh基礎能力之上的,站在全局視角統籌規劃,以保障服務穩定性爲出發點。
服務治理的意義:以下圖所示,百度網盤全局拓撲異常複雜,靠傳統的人工套路去保障服務穩定性,效率和覆蓋面都有很大的缺陷,基於流量控制的service mesh進行服務治理纔是王道,具體從故障預防、故障定位和故障處理出發。
故障預防從如下三個維度進行:
具體落地中又分紅機房流量隔離以及在離線流量隔離:
機房流量隔離
:統一網盤全部服務邏輯IDC映射關係,UFC 自動識別上游所在機房,將請求轉發到下游服務相應機房,從入口到請求終端,以邏輯IDC機房維度進行了流量隔離。當發生機房故障的時候,入口處切流量便可解決機房故障
在離線流量隔離
:定義網盤全部服務的等級,包括在離線標記,UFC根據全局流量拓撲,能夠發現是否存在在離線混連狀況,避免低優先級的請求流量影響高優先級的請求,致使喧賓奪主。好比下圖中,Online-a 和 Offline-a都訪問Online-b服務,這樣Offline-a 有可能引起Online-b服務異常,而從影響Online-a與Online-b的請求,間接影響用戶請求。發現這種在離線混連的狀況,須要對服務進行拆分,Online-b/Onine-c各自拆分紅Onine和Offline兩套服務,進行在離線流量的隔離
具體落地中又分紅容量評估以及容量壓測,前置是根據鏈路拓撲作評估,後者是經過壓測實踐驗證評估的準確性:
容量評估
:經過鏈路上的qps,分析出每一個服務須要增長的qps,進一步推算出須要擴容多少實例(PS:須要解決環路的問題)
容量壓測
: 經過以線上流量以機房切流量逐漸加壓的方式來壓測,期間監控服務sla,低於某個閾值以後,自動中止壓測
無效請求產生的背景
:當client斷開鏈接以後,server還在繼續訪問其它的後端,進行無效的請求。好比下圖中,client以300ms的超時時間訪問server,server在訪問A和B以後,已經用掉了300ms,這個時候client已經斷開了和server的鏈接,可是server卻繼續訪問C和D,進行無效的請求。當這種無效請求在整個鏈路蔓延開,client又在大量的重試的時候,就是雪崩降臨的時刻。
解決方案 - 基本思路
:基於鏈路的智能超時,設置整個鏈路的超時時間,當發現超時時間已經到了,就再也不訪問其它的下游服務,避免無效請求。上游須要傳遞給下游執行超時時間(採用相對時間,避免機器之間的時鐘不一樣步),用於下游判斷執行時間是否已經到了解決方案 - 基於業務
:不須要使用service mesh,業務本身維護當前的超時時間,業務改造的成本比較大解決方案 - 基於service mesh
:UFC以惟一ID映射到一個請求到全部後端交互的鏈路上,UFC自動維護剩餘的請求耗時,實現對業務近視0侵入(PS:還未用於生產環境)
定位的思路爲:發現異常 –> 收集系統異常點/異常時間點相關變更 –> 定位緣由
除了基於service mesh採集系統的異常點,還須要聯動其它的系統監控項,好比服務容量
根據故障的影響面能夠分紅局部/全局雪崩故障
前置條件:
場景:經過機房切流量快速解決機房硬件故障、小流量上線引起故障、後端異常封禁失敗等局部異常
前置條件:
場景:經過全局動態熔斷 + 異構降級 + 降級閉環策略解決服務引發的雪崩問題,儘可能保障服務的可用度,具有自愈能力
在業務拆分面多衆多問題的背景之下,百度網盤從2015年末開始思考解決方案,肯定了解決問題的核心在於管控請求流量
,在2016年開始自研網絡流量轉發中間件
- UFC(Unified Flow Control)
,業務經過同機部署的agent進行服務通訊。後來經過調研借鑑業界技術的時候發現UFC和Service Mesh的設計理念是一致的
,都是基於sidecar模式,有着控制面板和數據面板,UFC是Service Mesh的一種實現
。通過多年的線上實踐驗證,UFC這個Service Mesh實現了動態熔斷 + 異構降級 + 降級閉環等故障處理、結合故障/上游進行流量轉發等創造性設計,知足業務的實際場景需求。可是百度網盤的實踐落地並不僅侷限於Service Mesh,首先是構建了從點延伸到線的Service Mesh進行服務通訊管控
,而後是在UFC這個Service Mesh的基礎之上,站在全局視角對服務進行治理
,保障服務的穩定性。
將來,UFC將會加入故障注入等能力,同時基於該能力落地混沌工程,而這只是服務治理中預防的一部分。服務治理的目標是自愈,爲了完成這個目標,還須要更加努力。