路由是 Linkerd 的核心功能:接受請求(HTTP,Thrift,Mux或其他協議),并將該請求發送到正確的目標。本指南將詳細解釋 linkerd 如何確定請求應該發送到哪里。這個過程由4個步驟組成:identification/識別,binding/綁定,resolution/解析和load balancing/負載均衡。
識別
Identification/識別 是將一個名稱(也稱為路徑)分派給該請求的動作。名稱是斜杠分隔的字符串,表示請求的目的地。默認情況下,linkerd 使用一個名為 io.l5d.header.token
的identifier,該 identifier 根據 Host header 為請求命名,如下所示: /svc/<HOST>
。這意味著GET http://example/hello
的HTTP 請求將被分配名稱 /svc/example
。
(請注意,該URL的路徑, /hello , 在名稱中被刪除。它仍將作為請求的一部分被代理轉發 -該名稱僅決定請求如何路由,而不是發送到目標服務的內容)
當然,identifier 是一個可插拔的模塊,并可以用自定義的 identifier 來替換,這個 identifier 基于你想要的任何邏輯來分配名稱給請求。
identifier 分配給請求的名稱稱為 service name,因為它應該編碼應用程序指定的目標地址。它通常不編碼群集,區域,環境或主機的信息,因為您的應用程序不需要擔心這些問題。
例如,如果您的應用程序想要向 "users" 服務發出請求,它可以發出一個 HTTP GET 請求給linkerd,以 "users" 作為 Host header。 io.l5d.header.token
identifier將分配 /svc/users
作為該請求的 service name。
綁定
一旦將服務名稱分配給請求,該名稱將被 dtab(delegation table/委托表的簡稱)進行轉換。這被稱為 binding/綁定。有關 dtab 轉換如何工作的詳細文檔可以在 Dtabs頁面 中找到。
Dtabs 編碼描述 service name 如何轉換為 client name 的路由規則。client name 是 replicaset/副本集的名稱,通常是服務發現條目的名稱。與service name 不同,client name 通常包含集群,區域和/或環境等細節。
client names 通常以 /$
or /#
開頭. (兩個前綴的差別請看下面)
繼續這個例子,假設我們有以下 dtab:
/env => /#/io.l5d.serversets/discovery
/svc => /env/prod
service name /svc/users
將像這樣被綁定:
/svc/users
/env/prod/users
/#/io.l5d.serversets/discovery/prod/users
最終 /#/io.l5d.serversets/discovery/prod/users
成為 client name.
解析
解析/Resolution 是將 client name 解析為一組物理端點(IP地址+端口)。解析是通過稱為namer 的東西來完成的,通常會對某些服務發現后端進行查找。linkerd 帶有大量內建的主流服務發現的實現。請在 linkerd namer文檔 中詳細了解如何配置它們。
以 /$
開頭的 client name 表示應該加載 classpath 中的 namer 來綁定該名稱,而以 /# 開頭的 client name 表示加載 linkerd 配置中的 namer 來綁定該名稱。
例如,假設我們有一個 client name /#/io.l5d.serversets/discovery/prod/user
。這意味著來自 linkerd 配置的 io.l5d.serversets
namer 應該查找 /discovery/prod/users
服務器集(查找的結果是一組物理地址)。
類似地,client name /$/inet/users/8888
意味要為 inet namer 的搜索classpath。通過對"users" 進行 DNS 查找并使用端8888,該 namer 獲取一組地址。
負載均衡
一旦 linkerd 擁有副本集,它使用 負載平衡算法 來確定發送請求到哪里。因為 linkerd 在請求層而不是在連接層進行負載平衡,所以負載平衡算法可以利用請求延遲信息來減輕慢節點的負載,并避開超載下掙扎的主機。
------- 截取自 Linkerd 官方文檔