前言
現代計算機基於計算、存儲和調度的體系, 於是現代架構都是圍繞這三大話題不斷演進。
在基礎架構部, 也是主要爲了解決這三個難題,爲業務事業部提供透明的、高可用、可快速伸縮的 三大能力, 我們組主要負責 [流量調度] 這個話題,下面是一些宏觀的技術筆記。
在單體結構, 流量調度是直觀且無感的(DNS+Nginx就可以完成一次流量調度)。
演進到 微服務結構(服務粒度變得更細、服務伸縮更靈活(上下線更加頻繁),團隊松耦合),流量調度並沒有消失,而是變得更加複雜。
關鍵名詞解釋
1. 控制平面/數據平面
控制平面: 內含路由表、負責路由控制, 引導流量的走向,注重“引導”, 屬於旁路業務(核心)。
數據平面:根據控制平面的路由邏輯,業務流量的實際走向。
控制面很多屬於[核心]旁路業務:要求一致性=> raft協議。
2. 東西/南北流量
南北流量: 業務客戶端--->服務器;
東西流量: 數據中心內或者數據中心之間的服務間調用;
東西/南北流量都屬於數據平面流量。
服務治理的演進
服務治理的基石是動態服務發現, 阿里雲服務治理的演進 大而全,這裏只記錄我的理解。
階段 | 目標 | 手段 |
---|---|---|
孵化期 | 動態服務發現 | 客戶端/服務端服務發現,負載均衡 |
成長期 | 提高開發和迭代效率 | 規範API、 統一配置、 版本管理 |
成熟期 | 部署邊界、鏈路追蹤,彈性伸縮 | 服務預熱、優雅下線、監控追蹤、限流,熔斷, 回退 |
核心的技能點
1. 爲什麼需要註冊中心?
並不是微服務催生了 註冊中心,而是微服務強化了註冊中心。
早期DNS+nginx 就能完成單體的 流量調度,但是不管是DNS解析出ip, 還是nginx解析出upstream ,底層都有註冊中心的影子。
這裏面有一個addressability的概念,也即服務可尋址性, 服務必須有一個唯一的可尋址的名字,這個名字不依賴於部署環境,表徵一組可以處理流量的實例資源。
對於資源,必定存在CRUD交互,這便是部署平臺和服務發現,與此同時當實例出現故障時,註冊中心必須能夠指示服務現在在何處運行。
很多時候除了在部署層面,存在健康探測告知業務方目前的應用就緒情況; 實際在接流的時候,負載層還會有自己的主動健康檢查探測。
2. 規範API接口, 統一配置
提高開發迭代效率,統一使用一種method、body payload形式的API接口(規避錯誤格式的傳參導致的撕逼)、不用上n臺實例修改配置。
各個團隊是松耦合的關係,上下游的變更並不會主動通知,故需要版本管理(低版本不能直接下線)、提供給開發團隊的版本調試接口。
3. 服務發現
服務發現是服務治理的基石,三板斧: 註冊、心跳、尋址。
- 部署系統做[註冊]動作。
- 微服務客戶端尋址
- 主動上報心跳/註冊中心主動探活: 維護實例資源狀態。
存在兩種模式: 客戶端服務發現、服務器服務發現, 核心區別在於 : 客戶端是否保存服務列表信息。
4. 負載均衡
- 隨機
- 輪詢
- 帶權輪詢
- 根據後端實例服務質量動態調度
最近思考了一個問題,負載均衡不僅是拿到服務的可用實例列表,然後做流量均分; 其實負載均衡的存在也爲我們無損切流提供了契機。
5. 飛機起飛和降落最容易出事故
- 服務預熱: 服務進程啓動,等待業務配置/緩存就緒,再向註冊中心通報實例資源就緒,可以接流。
- 優雅下線: 下線時設置服務終止時間(30s),處理在途流量, 不再接收新的請求流量。
6. 限流 熔斷
鏈路上部分服務的狀態會影響整個鏈路(雪崩), 故需要保障微服務鏈路的高可用 => 服務的熔斷、限流
熔斷: 熔斷掉對於下游的調用; 限流: 限制進入本應用的流量。
不管是客戶端服務發現,還是服務器服務發現,都存在註冊中心,也可以叫名字服務,是流量調度的基石,統一了流量調度的入口。
現代互聯網結構,流量在打到應用之前,都會以對應的姿勢接入某種負載層。
大多數時候,流量其實不care某個特定的應用實例,更在意的是服務的可用性;
服務端服務發現,在客戶端和接流應用之間形成了一個負載層,除了負載均衡外,還提供了故障轉移和無損擴縮容、無損切流的契機,這些都涉及動態上下線實例, 不同負載層有不同的接流姿勢。
基於nginx7層負載的動態服務發現
我們着重聊一聊基於nginx主機名字的動態服務發現(服務端服務發現)。
nginx做反向代理,負載均衡的時候,我們關注nginx [http配置節]的上下文[server配置節][upstream配置節]。
上面這個配置,nginx會匹配請求的Host頭
與server_name指令
,決定該請求轉發給哪一個upstream
虛擬主機。
相關知識,請關注Host請求頭在虛擬主機服務多網域服務中的關鍵作用
利用nginx的第三方組件nginx_http_dyups_module,可以做到動態修改upstream的配置。
This module can be used to update your upstream-list without reloadding Nginx.
daemon off;
error_log logs/error.log debug;
events {
}
http {
upstream test_upstream {
server 127.0.0.1:8088;
server 127.0.0.1:8089;
}
server {
listen 80;
location / {
# The upstream here must be a nginx variable
set $up test_upstream ;
proxy_pass http://$up;
}
}
server {
listen 8088;
location / {
return 200 "8088";
}
}
server {
listen 8089;
location / {
return 200 "8089";
}
}
server {
listen 8090;
location / {
return 200 "8090" ;
}
}
server {
listen 8081;
location / {
dyups_interface;
}
}
}
1. 該組件默認不被編譯進tengine(淘寶開源的具備強特性的nginx分發版),請使用--with-http_dyups_module
配置參數啓用。
./configure --add-module=./modules/ngx_http_upstream_dyups_module // 配置成靜態組件
make // 編譯
make install // 安裝
2. 需要添加dyups_interface
指令激活[動態修改upstream配置]能力
3. 演示利用dyups api在不重啓nginx的情況下修改upstream配置。
查詢upstream和server:localhost:8081/detail
test_upstream
server 127.0.0.1:8088 weight=1 max_conns=0 max_fails=1 fail_timeout=10 backup=0 down=0
server 127.0.0.1:8089 weight=1 max_conns=0 max_fails=1 fail_timeout=10 backup=0 down=0
// 實際請求`curl 127.0.0.1`,輪詢返回8088或者8089
更新upstream配置:
curl -d "server 127.0.0.1:8090;" 127.0.0.1:8081/upstream/test_upstream
// 再次調用`localhost:8081/detail`
test_upstream
server 127.0.0.1:8090 weight=1 max_conns=0 max_fails=1 fail_timeout=10 backup=0 down=0
// 實際請求`curl 127.0.0.1`,輪詢返回8090
以上是對於流量調度這個大的topic的理解,限於篇幅,戰術性動作沒有展開,路漫漫其修遠兮,文辭拙劣,如果錯誤或者不同見解,歡迎留言探討。