自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

萬字解讀云原生時(shí)代,如何從 0 到 1 構(gòu)建 K8s 容器平臺(tái)的 LB(Nginx)負(fù)載均衡體系

云計(jì)算 云原生
云原生時(shí)代,基于 Kubernetes 的容器編排方案是當(dāng)下最優(yōu)選擇,各個(gè)中型、大型互聯(lián)網(wǎng)公司全都擁抱 Kubernetes,沒有其他方案可以與 Kubernetes 匹敵。

云原生時(shí)代,基于 Kubernetes 的容器編排方案是當(dāng)下最優(yōu)選擇,各個(gè)中型、大型互聯(lián)網(wǎng)公司全都擁抱 Kubernetes,沒有其他方案可以與 Kubernetes 匹敵。

所有業(yè)務(wù)(尤其是高并發(fā)業(yè)務(wù))的訪問必然要通過負(fù)載均衡 LB 代理層,服務(wù)端高并發(fā)系統(tǒng)離不開負(fù)載均衡,大中型公司下,負(fù)載均衡代理層都是有專人進(jìn)行獨(dú)立開發(fā)和建設(shè)的,云原生 Kubernetes 容器平臺(tái)下的 LB 代理層,同樣需要有專人來負(fù)責(zé)建設(shè)和維護(hù)。那么 Kubernetes 容器平臺(tái)基礎(chǔ)下的的 LB(Nginx) 負(fù)載均衡代理層要怎么建設(shè)?和非容器平臺(tái)下的 LB 建設(shè)有什么異同?建設(shè)的核心要點(diǎn)和當(dāng)下最優(yōu)的方案是什么?相信看完本文,都會(huì)對(duì) Kubernetes 容器平臺(tái)的 LB(Nginx)負(fù)載均衡了然于心,并且可以快速深入建設(shè) Kubernetes LB(Nginx)負(fù)載均衡體系。還可以了解到,一個(gè)中大型公司,是如何從 0 到 1 來構(gòu)建大規(guī)模 Kubernetes 容器平臺(tái)的 LB(Nginx)負(fù)載均衡體系的一些非常寶貴的實(shí)戰(zhàn)經(jīng)驗(yàn)。

適應(yīng)人群 :Kubernetes 開發(fā)者、LB 開發(fā)者、Kubernetes 基礎(chǔ)運(yùn)維人員、LB(Nginx)從業(yè)者、容器平臺(tái)開發(fā) or 架構(gòu)設(shè)計(jì)人員。

一、容器 LB 建設(shè)的背景

PS:如果對(duì) Kubernetes 基本概念還不熟,那么需要先理解一下 Kubernetes,本文是針對(duì)對(duì) Kubernetes 基本概念有一定理解的基礎(chǔ)上來進(jìn)行分析和設(shè)計(jì)。

1.初識(shí)負(fù)載均衡(LB)

負(fù)載均衡(Load Balancer,簡稱 LB)是指把客戶端訪問的流量通過負(fù)載均衡器,然后根據(jù)指定的一些負(fù)載均衡策略進(jìn)行轉(zhuǎn)發(fā),最終可以均勻的分?jǐn)偟胶蠖松嫌畏?wù)器上,然后上游服務(wù)器進(jìn)行響應(yīng)后再返回?cái)?shù)據(jù)給客戶端。負(fù)載均衡的最常見應(yīng)用是充當(dāng)反向代理,通過負(fù)載均衡,可以大大的提高服務(wù)的響應(yīng)速度、提高并發(fā)請(qǐng)求、提高穩(wěn)定性(防止單點(diǎn)故障)。

  • 負(fù)載均衡的基本實(shí)現(xiàn)方案,從業(yè)界來看,一般分為軟件和硬件兩大類,軟件負(fù)載均衡又可以分層如4層、7層負(fù)載均衡,如下:
  • 硬件負(fù)載均衡
  • 如 F5,性能好,但是貴。一般的互聯(lián)網(wǎng)公司都沒有采集硬件負(fù)載均衡
  • 軟件負(fù)載均衡
  • 目前這兩個(gè)都可以實(shí)現(xiàn) 4 層,但是更多的還是使用 Nginx 的 7 層功能。
  • 4 層:典型的如 LVS
  • 7 層:典型的如 Nginx、HAProxy

2.容器化下 LB 的異同點(diǎn)

在物理機(jī)時(shí)代,還沒有容器化之前,典型的負(fù)載均衡的建設(shè)方案就是搭建一套 Nginx 集群,提供 7 層的代理;搭建一套 LVS 集群,提供 4 層代理方案。并且同時(shí),一般 7 層之上,都有一個(gè) 4 層代理,流量的基本流向就是 client -> LVS(4 層) -> Nginx(7層) -> server 。

在物理機(jī)這個(gè)時(shí)代,運(yùn)維人員對(duì) Nginx 的 upstream 的配置,基本都是手動(dòng)添加修改各個(gè) server,然后推送配置上線應(yīng)用。傳統(tǒng)的物理機(jī)時(shí)代的維護(hù)方式,是基于后端 server 的 IP 基本是固定的,比如,你上線一個(gè) WebServer 的服務(wù),要部署到哪些機(jī)器上,這個(gè)是事先確定好的了,IP 會(huì)固定不變,不管你怎么升級(jí),服務(wù)都還是固定在這些機(jī)器上,因此這個(gè)時(shí)代這樣的維護(hù)方式,并沒有太多問題,大家以往也都維護(hù)的挺和諧。

在容器化時(shí)代,基于 Kubernetes 的容器化平臺(tái)下,LB 的建設(shè)有哪些差異呢?主要分為兩大塊:

? 后端服務(wù)的 IP,會(huì)由于集群的調(diào)度,IP 是可變的,每當(dāng)你部署、升級(jí)等操作的時(shí)候,IP 都會(huì)改變,那么這個(gè)時(shí)候,我們顯然不能夠再繼續(xù)采用原有寫死 IP 的方式來進(jìn)行 7 層代理的維護(hù)了。由于服務(wù) IP 的不確定性,我們必須要改變姿勢,不能由人為填充 Nginx 的 upstream 的 server ip 的方式,只能通過動(dòng)態(tài)的獲取和變更,這個(gè)就需要 LB 能夠主動(dòng)發(fā)現(xiàn)后端服務(wù)并且動(dòng)態(tài)更新

? Kubernetes 的容器化平臺(tái)下,集群內(nèi)部的網(wǎng)絡(luò)是虛擬的,虛擬網(wǎng)絡(luò)的 IP 在集群外部是無法訪問的,因此還需要解決好容器集群內(nèi)外的網(wǎng)絡(luò)互通問題。

二、容器 LB 負(fù)載均衡怎么建設(shè)

1.Kubernetes 的負(fù)載均衡

Kubernetes 本身有內(nèi)置一個(gè)集群內(nèi)部的負(fù)載均衡方案,叫 kube-proxy,但是這個(gè)只能內(nèi)部訪問,并且功能稍顯不足;而實(shí)際上,我們的容器平臺(tái),必須要提供集群外部訪問的功能,因?yàn)槟愕挠脩簦蛻舳耍┒际窃诩和獠俊?/p>

Kubernetes 負(fù)載均衡相關(guān)的方案,包括:

  • 集群內(nèi)部負(fù)載均衡【內(nèi)置】

Pod IP 在集群內(nèi)部都是互通的,因此集群內(nèi)部無需考慮網(wǎng)絡(luò)互通問題

每個(gè) Node 節(jié)點(diǎn)上的 kube-proxy,就是集群內(nèi)置的內(nèi)部負(fù)載均衡的解決方案;但是只限于集群內(nèi)部,并且功能有限

  • 集群外部負(fù)載均衡【額外添加】

社區(qū)提供的 nginx-ingress-controller 方案可以滿足需求

云廠商的 Cloud provider 也可以滿足需求

參考 nginx-ingress-controller 的模式,自建 LB 方案

由此可見,如果是在自己 IDC 內(nèi)部建設(shè)容器 LB 方案,那么只能采用自建方案 或者基于 nginx-ingress-controller 方案來建設(shè);如果是上云的話,那么可以自建,也可以直接采用云廠商的方案。

下面所有的介紹,都是基于自建方案來設(shè)計(jì),在 IDC 內(nèi)部,我們要怎么從 0 到 1 來建設(shè) K8s 容器的 LB 體系。

2.業(yè)務(wù)需求

業(yè)務(wù)功能需求就在于,業(yè)務(wù)(開發(fā))使用容器 LB 體系的時(shí)候,他們會(huì)需要哪些需求,包括怎么使用、需要哪些功能、需要哪些策略,作為容器 LB 建設(shè)的開發(fā)人員,我們需要能夠站在業(yè)務(wù)方的角度去考慮,如下圖所示,有這些業(yè)務(wù)需求:

圖片

詳細(xì)說明如下:

  • 體驗(yàn)需求

LB 分組:這個(gè)業(yè)務(wù)非常核心,需要獨(dú)立的 LB 集群,也就是 LB 代理層需要分組

域名解析線路:如果是多集群、多 IDC,那么服務(wù)暴露的域名,要怎么解析,是全 IDC 都解析,還是只解析到某一個(gè)集群

7 層代理的一些高級(jí)配置,如 uri 的 rewrite 規(guī)則、自定義一些特殊配置

大部分用戶:業(yè)務(wù)要暴露自己的服務(wù)只需要足夠簡單的配置和理解,他們不需要也不想關(guān)注服務(wù)暴露的細(xì)節(jié),要的就是一個(gè)結(jié)果,我的服務(wù)部署了,我要暴露出去給 client 端調(diào)用

小眾用戶:業(yè)務(wù)非常核心,有各種不確定因素存在,業(yè)務(wù)開發(fā)人員需要關(guān)注細(xì)節(jié)

  • 負(fù)載均衡代理層的常規(guī)功能需求

要能夠統(tǒng)計(jì) SLA ,包括 QPS、慢請(qǐng)求、錯(cuò)誤數(shù) 等

要能夠針對(duì)異常進(jìn)行告警

要能夠支持常見的負(fù)載均衡算法,如輪詢、最小連接、hash 等

負(fù)載均衡代理層要能夠支持超時(shí)、重試等基本功能

負(fù)載均衡代理層還必須要能夠支持對(duì)后端服務(wù)的健康檢查

基本的服務(wù)暴露:支持 4 層、7 層的代理方案,支持 7 層的 HTTP、HTTPS,也支持基本的 PATH 路由

域名:服務(wù)暴露的時(shí)候,每個(gè)服務(wù)肯定需要有自己的域名,那么這個(gè)域名需要能夠支持默認(rèn)按照一定規(guī)則生成,還需要能夠支持自定義域名;具體怎么選擇就看業(yè)務(wù)自己的需求

內(nèi)外網(wǎng)的需求:有些業(yè)務(wù)是直接給 APP 調(diào)用的,那么必然需要暴露到外網(wǎng);而有些業(yè)務(wù)只是需要集群內(nèi)部訪問,那么就暴露到內(nèi)網(wǎng)即可;

upstream 上游(后端)服務(wù)的基本策略

監(jiān)控和統(tǒng)計(jì)

  • 負(fù)載均衡代理層的高級(jí)策略需求

限流策略:高可用服務(wù)必須要有的功能,通過 LB 代理層進(jìn)行限流,防止流量太大從而導(dǎo)致后端過載引發(fā)整體故障

熔斷保護(hù)機(jī)制:當(dāng)服務(wù)發(fā)現(xiàn)異常,并且通過限流還不能解決的時(shí)候,需要能夠直接熔斷,也就是直接斷開請(qǐng)求,防止影響到其他業(yè)務(wù)

灰度放量:當(dāng)業(yè)務(wù)新上線一個(gè)功能(版本迭代)的時(shí)候,首先需要進(jìn)行灰度放量,然后觀察,看是否滿足預(yù)期,如果滿足預(yù)期則繼續(xù)灰度放量;如果有異常則需要馬上回滾

3.運(yùn)維需求

我們建設(shè)的容器 LB 方案,最終是要交付給運(yùn)維同學(xué)去使用的,運(yùn)維必須要把控好整個(gè)公司的流量入口,LB 就是整個(gè)公司的流量入口;而且一般業(yè)務(wù)同學(xué)也沒有權(quán)限去操作 LB 相關(guān)的配置。那么,站在運(yùn)維的角度來看,容器 LB 需要提供哪些功能呢?如下圖所示,有這些運(yùn)維需求:

圖片

詳細(xì)說明如下:

  • 負(fù)載均衡器的相關(guān)管理

負(fù)載均衡器的自動(dòng)化腳本部署,因?yàn)檫\(yùn)維需要部署負(fù)載均衡器,那么怎么樣能夠?qū)崿F(xiàn)更為智能的自動(dòng)化腳本部署,而不是零散的各個(gè)命令去操作呢?這塊依賴于我們提供的一些操作步驟和子命令,然后結(jié)合 ansible 來封裝實(shí)現(xiàn)

負(fù)載均衡器的擴(kuò)縮容,部署完了之后,后續(xù)還可能有擴(kuò)縮容需求,比如國慶期間、春節(jié)期間、大促期間,這是需要提前擴(kuò)容的,那么怎么能夠快速擴(kuò)縮容?怎么更自動(dòng)化?這塊同樣也是需要結(jié)合 ansible 來封裝實(shí)現(xiàn)

負(fù)載均衡器的分組,對(duì)運(yùn)維而言,穩(wěn)定性是首要的,那么線上的業(yè)務(wù),有重要的服務(wù),也有非重要的服務(wù),一般而言,對(duì)重要核心的服務(wù)、流量非常大的服務(wù),都需要單獨(dú)的分組,用來進(jìn)行物理上的隔離和管控

  • 權(quán)限管控和審計(jì)

權(quán)限,一般而言,公司建設(shè) Kubernetes 容器平臺(tái),都會(huì)有一套管理平臺(tái)系統(tǒng),所有人都是通過管理平臺(tái)來操作,包括運(yùn)維和開發(fā)。如部署業(yè)務(wù)服務(wù)、上下線、LB 的操作和管理等等。那么既然是這樣,那么必須要控制好權(quán)限,不同角色有不同的操作權(quán)限,避免所有人都能夠操作負(fù)載均衡的相關(guān)配置,只有管理員 或者 運(yùn)維人員才能夠操作

審計(jì),線上的所有變更,都需要有審計(jì),方便回溯問題

  • 業(yè)務(wù)服務(wù)的配置操作

Nginx 負(fù)載均衡的基本配置檢測,要能夠通過管理平臺(tái)來實(shí)現(xiàn),包括基本檢測和異常檢測,檢測通過才能執(zhí)行變更

Nginx 負(fù)載均衡配置的灰度和回滾機(jī)制,灰度是說變更之前,需要先灰度 1 個(gè) Nginx 節(jié)點(diǎn),確保這次變更沒有問題之后,才能全量變更;回滾是說如果灰度出現(xiàn)問題,那么需要能夠快速回滾到上一個(gè)版本

Nginx 負(fù)載均衡配置的基本查看、搜索;可以全局管理所有配置;可以搜索關(guān)鍵字來快速定位配置

  • 穩(wěn)定性的相關(guān)操作(流控)

業(yè)務(wù)限流,當(dāng)業(yè)務(wù)流量過大之后,根據(jù)實(shí)際情況進(jìn)行限流,避免打滿后端服務(wù)

灰度放量,業(yè)務(wù)更新之前需要一個(gè)灰度逐步放量的過程

  • LB 系統(tǒng)和域名管理系統(tǒng)打通

中大型公司而言,都會(huì)有內(nèi)部的域名管理系統(tǒng),每個(gè)服務(wù)都會(huì)有一個(gè)對(duì)外暴露的域名來訪問,那么域名管理系統(tǒng)必須要和 LB 系統(tǒng)打通并且聯(lián)動(dòng)起來,形成一個(gè)完整的操作鏈。這就需要用戶暴露一個(gè)服務(wù)的時(shí)候,并不用事先申請(qǐng)域名,直接在 LB 系統(tǒng)這里進(jìn)行申請(qǐng)即可。

4.基本方案和基本原則

Kubernetes 下,后端服務(wù)都是 Pod 的形態(tài),Pod 要能夠?qū)崿F(xiàn)對(duì)外的負(fù)載均衡,就必須要成為 nginx 的 upstream。而 Pod 的 IP 是隨時(shí)都可能變化的,為此,就需要一個(gè) Nginx-Controller 來動(dòng)態(tài)發(fā)現(xiàn) Pod,然后渲染為 nginx 的 upstream;Nginx-Controller 就是一個(gè) Nginx 再加上一個(gè) Controller(發(fā)現(xiàn) Pod 并渲染為 upstream)。

所以,就需要我們能夠自研一個(gè) Nginx-Controller 組件來實(shí)現(xiàn)了,那么這個(gè) Nginx-Controller 有些什么要求 ?

A,集群內(nèi)外的網(wǎng)絡(luò)要能互通

基本要求就是:

  • 集群內(nèi),Nginx-Controller 要能夠?qū)⒘髁糠职l(fā)給 Pod

需要將 Nginx-Controller 納入到 Kubernetes 的節(jié)點(diǎn)中,也就是部署 Nginx-Controller 的機(jī)器必須是 Kubernetes 的 Node 節(jié)點(diǎn)

  • 集群外,外網(wǎng)的請(qǐng)求要能夠轉(zhuǎn)發(fā)到 Nginx-Controller 中

這就需要部署 Nginx-Controller 的機(jī)器能夠和外部互通,一個(gè)最簡單的方式就是,Nginx-Controller 采用二進(jìn)制部署,使用 Node 主機(jī)的網(wǎng)絡(luò),這樣就可以了

因?yàn)?Node IP 是互通的,只有 Pod IP 不互通

B,動(dòng)態(tài)發(fā)現(xiàn) Pod 并且渲染為 nginx 配置

首先,我們需要能夠 watch 到 Pod、Service、 Endpoints 等資源的變化,這個(gè)就需要和 K8s API Server 交互,一般我們現(xiàn)在都是使用 Golang 語言來實(shí)現(xiàn),因此可以基于官方的 client-go 來實(shí)現(xiàn)

在這,我們需要提供一套統(tǒng)一的模板配置,方便業(yè)務(wù)配置,然后自動(dòng)渲染。因?yàn)?Nginx-Controller 要 watch 的業(yè)務(wù)服務(wù)資源是未知的,隨時(shí)可以增加或者刪除,那么最好能夠有一套模板機(jī)制來實(shí)現(xiàn),對(duì)于 Golang,可以通過 Golang 的 template包來封裝模板的實(shí)現(xiàn),結(jié)合模版和當(dāng)前 Service、Endpoints 的情況,渲染成對(duì)應(yīng)的 nginx 配置。比如:

upstream test-api {
{{ k8sBuildUpstream "default.test-back" "port=8080" "max_fails=3" "fail_timeout=3s" }}

會(huì)渲染成相應(yīng)服務(wù)的節(jié)點(diǎn)列表和端口:

upstream test-api {
server 10.1.1.7:8080 max_fails=3 fail_timeout=3s;
server 10.1.1.9:8080 max_fails=3 fail_timeout=3s;
}

C,實(shí)現(xiàn)灰度、全量、回滾的機(jī)制

Nginx-Controller 雖然可以動(dòng)態(tài)渲染 nginx 配置了,但是作為線上服務(wù),必須需要有灰度、全量、回滾的機(jī)制。

因?yàn)槲覀兊娜萜?LB 是需要分組的,每一組 LB 也都會(huì)有多個(gè) nginx 節(jié)點(diǎn),灰度就是指,我們的配置要發(fā)布,首先灰度一個(gè)節(jié)點(diǎn),確保這個(gè)節(jié)點(diǎn) OK 之后,再灰度到下一個(gè) nginx 節(jié)點(diǎn),或者可以全量到所有 nginx 節(jié)點(diǎn)。回滾則是指當(dāng)我們灰度一個(gè)節(jié)點(diǎn)之后發(fā)現(xiàn)有問題,則回滾這個(gè)節(jié)點(diǎn)的配置。

怎么實(shí)現(xiàn)呢?可以通過兩個(gè) configmap 來解決灰度和全量更新的問題,configmap-canary 這個(gè)作為灰度的 configmap,并且通過 annotation 來標(biāo)記哪些是要灰度的 nginx 節(jié)點(diǎn)的 IP,這樣 nginx controller 如果識(shí)別到configmap-canary 里面的變化,則通過 annotation 的 IP 來判斷是否是本節(jié)點(diǎn)的,如果是本節(jié)點(diǎn)的則渲染配置并且 reload nginx,從而生效,如果不是本節(jié)點(diǎn)的,那么則丟棄。當(dāng)要全量的時(shí)候,則:

  • 首先,將所有的全量節(jié)點(diǎn)追加到 configmap-canary 的annotation["ip"]字段中,nginx-controller 讀取該字段,匹配ip字段,匹配節(jié)點(diǎn)更新配置
  • 然后,如果確保已經(jīng)全量成功,那么則先將 configmap-canary 的內(nèi)容覆蓋到 configmap-release 中,然后再清空 configmap-canary 中的 IP 列表;這樣就可以完成整個(gè)灰度和全量的過程。

如果灰度的時(shí)候,發(fā)現(xiàn)異常了,需要回滾,那么直接清空 configmap-canary 中的 IP 列表;然后再回滾到上一個(gè)版本后,重新再走一遍發(fā)布流程來完成回滾操作

D,容器 LB 組件本身的管理和部署

上面說到容器 LB 組件本身(Nginx-Controller)需要二進(jìn)制部署到 Node 主機(jī)上,那么要合理的管理這種二進(jìn)制部署的需要一直運(yùn)行的程序,一個(gè)較常見并且優(yōu)雅的姿勢就是通過 systemd 來管理。示例配置如下:

[Unit]
Descriptinotallow=nginx-controller daemon
Documentatinotallow=/www/nginx-controller/bin/nginx-controller -h
After=nginx.service
Wants=nginx.service

[Service]
Type=simple
ExecStart=/www/nginx-controller/bin/nginx-controller --slow-start=true --is_dynamic=true ${OPTIONS}
ExecStop=/bin/kill -SIGTERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGQUIT
Restart=on-failure
RestartSec=3s

[Install]
WantedBy=multi-user.target

只要將這個(gè)配置放到 /usr/lib/systemd/system/ 中,systemd 就可以管理起來了。

E,各種統(tǒng)計(jì)和監(jiān)控

Nginx-Controller 代理層所需的監(jiān)控包括如下:

  • 進(jìn)程的監(jiān)控

進(jìn)程是否存活、是否出現(xiàn) panic 等

  • 日志監(jiān)控

日志首先要采集,然后要對(duì)錯(cuò)誤日志進(jìn)行監(jiān)控,可以使用 ELK

  • 基本指標(biāo)監(jiān)控

Nginx-Controller 的一些基本指標(biāo)監(jiān)控,可以使用 Prometheus

比如 reload 次數(shù)、更新次數(shù)、更新是否失敗 等。。。。

  • LB 所在主機(jī)的機(jī)器性能監(jiān)控

CPU:idle、system、user 等指標(biāo)

網(wǎng)卡軟中斷

網(wǎng)絡(luò)帶寬:流入和流出帶寬指標(biāo)、網(wǎng)卡丟包指標(biāo)

內(nèi)存使用、swap 使用

磁盤 IO:讀、寫兩方面

剩余句柄數(shù)

  • LB 代理層的基本業(yè)務(wù)指標(biāo)監(jiān)控

SLA

錯(cuò)誤統(tǒng)計(jì)

延遲統(tǒng)計(jì)

域名維度、path 維度等

三、容器 LB 體驗(yàn)優(yōu)化(LB 架構(gòu)產(chǎn)品設(shè)計(jì))

1.初期的架構(gòu)圖

我們既然是從 0 到 1 來構(gòu)建 K8s 的 負(fù)載均衡體系,那么初期必然是需要從物理機(jī)轉(zhuǎn)向容器,一般的選擇是為了能夠保證項(xiàng)目可以正常實(shí)施,容器 LB 這塊的抉擇,會(huì)結(jié)合著運(yùn)維同學(xué)的一些習(xí)慣、可接受性以及更少的改動(dòng)、更高的穩(wěn)定性來做一些架構(gòu)上的取舍。

沒有容器化之前,7 層代理的架構(gòu)一般是 client -> CDN -> LVS -> 物理機(jī) Nginx -> server ;

為了滿足上述訴求,在容器化之初,容器 LB 可能還不穩(wěn)定,需要逐步導(dǎo)量過來,因此整體架構(gòu)會(huì)是client -> CDN -> LVS -> 物理LB -> 容器LB(Nginx-Controller) -> POD ,如下:

圖片

LVS 和 Nginx 都需要做高可用,因此:

  • LVS 就是通過 keepalive 本身來做高可用,并且 LVS 需要配置萬兆網(wǎng)卡,因?yàn)樗辛髁慷家?jīng)過 LVS。
  • Nginx 的高可用和高并發(fā)就是建立一組 Nginx(多個(gè) Nginx 實(shí)例),然后掛到 LVS 下面做心跳檢測和流量分發(fā)

LVS 4 層代理可以對(duì) Nginx 做檢測來保證高可用

LVS 4 層代理可以基于 4 層做流量分發(fā)到 Nginx 上

  • 容器 LB(Nginx-Controller) 和 Pod 的網(wǎng)絡(luò)需要能夠互通,因此 容器 LB 也需要建立在 Kubernetes 集群之內(nèi),在同一個(gè)網(wǎng)絡(luò)架構(gòu)下

Kubernetes 容器平臺(tái)的網(wǎng)絡(luò)可以選擇 Calico

2.最優(yōu)的架構(gòu)圖

在項(xiàng)目中后期,容器 LB 傾向穩(wěn)定之后,那么我們要考慮的就是性能問題、成本問題、體驗(yàn)問題了,為此,架構(gòu)需要逐步演進(jìn)。

  • 首先,物理機(jī) Nginx 的存在,會(huì)導(dǎo)致多了一層鏈路

增加響應(yīng)耗時(shí)

增加配置管理的復(fù)雜度

增加問題排查的鏈路分析

增加機(jī)器成本

  • 其次,Nginx-Controller 這個(gè)方案,有更優(yōu)的替代方案,那就是nginx-ingress-controller

整體的最優(yōu)的架構(gòu)流向就是: client -> CDN -> LVS -> Nginx-Ingress-Controller -> Pod

Nginx-Ingress-Controller 的具體介紹在后面章節(jié)進(jìn)行分析。

3.體驗(yàn)優(yōu)化

優(yōu)化 1:實(shí)現(xiàn)動(dòng)態(tài) upstream,減少 Nginx Reload 帶來的 502

為何需要支持動(dòng)態(tài) upstream 呢?這是因?yàn)椋?K8s 下,服務(wù)的 Pod IP 會(huì)經(jīng)常改變,比如每次發(fā)布更新的時(shí)候 Pod IP 都會(huì)變化,這也就意味著,nginx 的 upstream 的 server 列表會(huì)經(jīng)常改變,那么每次 IP 有變化的時(shí)候,nginx 都需要 reload 的話,那么在線上高并發(fā)、大流量的場景下,長連接的服務(wù)會(huì)經(jīng)常在 nginx reload 的時(shí)候出現(xiàn) 502,這個(gè)是不能接受的,非常影響業(yè)務(wù)的 SLA

那么為何長連接的服務(wù)會(huì)經(jīng)常在 nginx reload 的時(shí)候出現(xiàn) 502 呢?這個(gè)要重點(diǎn)分析下 nginx 在進(jìn)行 reload 的時(shí)候,對(duì)于老連接是怎么處理的,一個(gè)確定的流程是:

  • 如果當(dāng)前連接是空閑狀態(tài),那么直接關(guān)閉
  • 如果當(dāng)前連接還在等待 upstream response,那么會(huì)等待請(qǐng)求處理結(jié)束或者超時(shí) (proxy_read_timeout),再關(guān)閉

這一過程對(duì)于短連接的請(qǐng)求,是挺合理的,表現(xiàn)也挺正常的。但是對(duì)于長連接場景,nginx 有些處理不好的地方。對(duì)于長連接請(qǐng)求,nginx 在處理完最后一個(gè)請(qǐng)求,返回 response 的時(shí)候,他依然是返回 Connection: keepalive 的 response header。這樣就會(huì)導(dǎo)致會(huì)有一個(gè)時(shí)間窗口差,在 nginx 對(duì)于這個(gè)連接進(jìn)行 close 以及到 Linux 內(nèi)核完整 close 這個(gè)連接,并且發(fā)出 FIN 到 client 這個(gè)時(shí)間段內(nèi),client 端如果是高并發(fā)的場景,那么由于是長連接,因此很也可能會(huì)繼續(xù)復(fù)用這個(gè)連接來發(fā)起新的請(qǐng)求給 Nginx,這樣 Nginx 機(jī)器所在的 Linux 內(nèi)核看到對(duì)于一個(gè)已關(guān)閉的連接還有新的請(qǐng)求,那么就會(huì)直接返回 RST 包,從而導(dǎo)致了 client 的一些 502 的錯(cuò)誤。

優(yōu)化 2:實(shí)現(xiàn) SlowStart 功能,減少 Pod 啟動(dòng)初期的 SLA 性能下降

SlowStart 策略,指的是,在 Pod 初次啟動(dòng)并且能夠?qū)ν馓峁┓?wù)之后,剛開始給一個(gè)緩沖時(shí)間,在這個(gè)緩沖時(shí)間內(nèi),先提供小流量的請(qǐng)求,進(jìn)行有 weight 權(quán)重的 RR 算法,只允許非常小比例的流量;這個(gè)緩沖時(shí)間之后,再開始無權(quán)重的 RR 算法。

一般而言,Pod 的 Readiness 探針是可 worker 之后,就認(rèn)為這個(gè) Pod 可以開始對(duì)外提供服務(wù)了。但是針對(duì)某些 Java 服務(wù),Readiness 探針 OK 后,還不能馬上提供大量服務(wù),因?yàn)?Java 需要啟動(dòng) Java 虛擬機(jī),初始化相關(guān)系統(tǒng)、組件;還有一些各種內(nèi)存池、線程池 等初始化工作要做;而這些初始化工作在某些情況下可能需要一點(diǎn)耗時(shí);或者某些情況下是有請(qǐng)求過來后才進(jìn)行初始化,但是由于初始化需要時(shí)間,因此 Readiness 探針 OK 之后,還不能馬上提供大量服務(wù),否則在啟動(dòng)的時(shí)候就可能造成服務(wù)的些許不穩(wěn)定,從而降低 SLA,給業(yè)務(wù)帶來影響。這個(gè)是我們實(shí)際 Java 項(xiàng)目所得出的結(jié)論,因?yàn)?jit 的影響,如果在低流量下完成 jit 編譯,這樣給一個(gè)緩沖時(shí)間,最終效果就是可以提高 SLA。目前這個(gè)功能其實(shí)是一個(gè)規(guī)避措施,按理來說需要業(yè)務(wù)方自己解決的,因?yàn)椴煌臉I(yè)務(wù)方可能情況也有些區(qū)別。

具體怎么實(shí)現(xiàn)呢?這就要結(jié)合 Kubernetes 本身機(jī)制來綜合實(shí)現(xiàn)了。一般 Kubernetes 中服務(wù)的部署是通過 Deployment + Service 來部署一個(gè)服務(wù);那么這樣的話,服務(wù)就可以支持 Deployment 的滾動(dòng)更新的特性,通過配置MaxSurge(如 25%),MaxUnavailable(如 25%),minReadySeconds(如 30s),progressDeadlineSeconds(如 600s) 幾個(gè)參數(shù)來控制滾動(dòng)策略,可以實(shí)現(xiàn)每次滾動(dòng)升級(jí)過程中新舊一起加起來的總的 Pod 數(shù)會(huì)小于等于(1+MaxSurge)* desiredPods,而 available 可以的 Pod 節(jié)點(diǎn)數(shù)可以保證大于等于 MaxUnavailable * desiredPods,新增 Pod 節(jié)點(diǎn) ready 后等待最少 minReadySeconds 后成 available,整個(gè)滾動(dòng)流程超過 progressDeadlineSeconds 600s 停滯則認(rèn)為失敗,回滾舊版本。

為此,SlowStart 的機(jī)制實(shí)現(xiàn)就可以利用這個(gè)特性了,如果開啟了 SlowStart 功能,那么就判斷 Pod 節(jié)點(diǎn)是否是本次更新新啟動(dòng)的節(jié)點(diǎn),如果是新啟動(dòng)的的 Pod 節(jié)點(diǎn)則調(diào)整其 Pod 的 weight 成預(yù)設(shè)比例(一般是較小權(quán)重),當(dāng)節(jié)點(diǎn) ready 時(shí)間超過 MinReadySeconds 后 ,恢復(fù) weight 成正常權(quán)重(默認(rèn):100) ,從而實(shí)現(xiàn) SlowStart 慢啟動(dòng)。這個(gè)機(jī)制的 SlowStart 功能實(shí)現(xiàn)的慢啟動(dòng)針對(duì)的是整個(gè)業(yè)務(wù)的 Service 級(jí)別的。利用這個(gè)特性來判斷節(jié)點(diǎn)是否為新增節(jié)點(diǎn),總結(jié)來看需要滿足的條件如下:

# 1. 節(jié)點(diǎn)在deployment發(fā)布周期內(nèi)
LatestPod.ReadyStatus.LastTransitionTime + progressDeadlineSeconds > CurTime

# 2. 節(jié)點(diǎn)ready后未超過minReadySeconds窗口
CurPod.ReadyStatus.LastTransitionTime + minReadySeconds > CurTime

# 3. 當(dāng)前節(jié)點(diǎn)初始化時(shí)間與最新節(jié)點(diǎn)初始化時(shí)間差值未超過minReadySeconds窗口,防止擴(kuò)步長限流
CurPod.InitializedStatus.LastTransitionTime + minReadySeconds > LatestPod.InitializedStatus.LastTransitionTime

如果是新增節(jié)點(diǎn)的話,則設(shè)置其 weight 為 100 * slow-start-weight,并且設(shè)置 service 級(jí)別的觸發(fā)器,在LatestPod.ReadyStatus.LastTransitionTime + minReadySeconds + 10s - CurTime 時(shí)間后恢復(fù)為默認(rèn)權(quán)重( weight=100)。

優(yōu)化 3:LB 配置發(fā)布和運(yùn)維域名管理系統(tǒng)打通,減少服務(wù)暴露的流程步驟

一般的互聯(lián)網(wǎng)公司,運(yùn)維這邊都會(huì)有自己的域名管理系統(tǒng),開發(fā)人員可以通過提單的方式,讓運(yùn)維給自己的服務(wù)分配一個(gè)域名(內(nèi)網(wǎng)、外網(wǎng));然后開發(fā)人員拿到這個(gè)域名之后呢,再和自己的服務(wù)綁定,這個(gè)綁定的過程就是服務(wù)暴露的過程。服務(wù)暴露就是指在 LB 這邊建立對(duì)應(yīng)的規(guī)則,然后讓就可以通過這個(gè)域名來訪問對(duì)應(yīng)的服務(wù)了。

這個(gè)服務(wù)暴露的過程,首先需要人工提單,拿到域名后再進(jìn)行手動(dòng)配置,為此,如果公司有合適的機(jī)制和契機(jī),那么應(yīng)該需要將容器 LB 進(jìn)行服務(wù)暴露的過程和域名管理系統(tǒng)打通,當(dāng)業(yè)務(wù)需要進(jìn)行服務(wù)暴露的時(shí)候,不再需要通過多個(gè)平臺(tái)的操作來完成,只需要在容器 LB 這邊的管理平臺(tái)中進(jìn)行服務(wù)暴露,然后內(nèi)部可以自動(dòng)生成域名或者自定義域名,然后自動(dòng)和域名管理系統(tǒng)打通,然后正式生效對(duì)外提供服務(wù)。

這樣的優(yōu)化主要的目的就是為了提升用戶體驗(yàn),減少中間的人工操作環(huán)境,從而也可以進(jìn)一步減少人力成本。

優(yōu)化 4:移除物理機(jī) Nginx,優(yōu)化鏈路,降低成本

我們前面說到,在初期的時(shí)候,為了保證穩(wěn)定和過渡,還是需要有物理機(jī) Nginx 的存在,物理機(jī) Nginx 的主要作用有兩方面:

  • 其一,可以通過物理機(jī) Nginx 這一層來對(duì)容器 LB 的流量進(jìn)行灰度放量,同時(shí)可以能及時(shí)回滾
  • 其二,整個(gè)公司的業(yè)務(wù)服務(wù),會(huì)有很多依然部署在物理機(jī)上,初期只會(huì)有小部分服務(wù)會(huì)開始逐步往容器進(jìn)行遷移,因此物理機(jī) Nginx 還必須要保留

但是在項(xiàng)目中后期,容器 LB 會(huì)逐步趨于穩(wěn)定,此時(shí),就需要逐步移除物理機(jī) Nginx,直接是 LVS 到容器 LB,但是移除物理機(jī) Nginx 需要有大量的工作要去梳理,因?yàn)槲锢頇C(jī) Nginx 的配置是手動(dòng)配置的,可能有很多差異化、特性化的配置。

優(yōu)化 5:采用 nginx-ingress-controller 方案,減少 nginx 配置的干預(yù),一步到位

前面說到 nginx-ingress-controller 可以作為最優(yōu)方案來替代 Nginx-Controller, nginx-ingress-controller 產(chǎn)生的主要目的就在于能夠?qū)?Kubernetes 中的 Service 所代理的 Pod 服務(wù)暴露在 Kubernetes 集群之外,這樣就能夠打通集群內(nèi)外的訪問問題,通過 ingress 可以直接進(jìn)行七層的負(fù)載均衡,并且可以對(duì)外訪問,同時(shí)減少了一些復(fù)雜的配置。

因此,請(qǐng)求流程 client -> LVS VIP -> ingress-controller -> 業(yè)務(wù) POD

具體的 nginx-ingress-controller 方案參看下面最后的說明。

四、容器 LB 開發(fā)設(shè)計(jì)的核心考量點(diǎn)

容器 LB 開發(fā)設(shè)計(jì)的核心考量點(diǎn)有如下:

圖片

詳細(xì)說明如下:

1.支持動(dòng)態(tài) upstream 的實(shí)現(xiàn)【非常重要】

K8s 容器平臺(tái)下,業(yè)務(wù)服務(wù)的 Pod 的是動(dòng)態(tài)變化的,比如再每次重新部署、滾動(dòng)升級(jí)、被驅(qū)逐重建等情況之后, Pod 的 IP 都是會(huì)發(fā)生改變。每次 Pod IP 改變,那么就意味著 Nginx 的 upstream 發(fā)生了變化,如果沒有實(shí)現(xiàn)動(dòng)態(tài) upstream,那么將會(huì)導(dǎo)致每次 Pod IP 變化,Nginx 都需要進(jìn)行異常 Reload 操作。在線上大規(guī)模集群下,如果業(yè)務(wù)的 QPS 請(qǐng)求很高,Nginx 頻繁 Reload 會(huì)導(dǎo)致 client 端的長連接請(qǐng)求在 Nginx Reload 的時(shí)候出現(xiàn) 502,這樣將降低業(yè)務(wù)的 SLA,故而無法提供高可靠的服務(wù)保障。

故而,只要我們實(shí)現(xiàn)了動(dòng)態(tài) upstream,比如基于 lua 模塊的實(shí)現(xiàn),那么不管后端 Pod IP 如何變化,Nginx 后端 upstream 的 IP 將會(huì)通過 lua 共享內(nèi)存?zhèn)鬟f并進(jìn)行負(fù)載均衡,因此 Nginx 將不會(huì)進(jìn)行 Reload,從而會(huì)大大提高 SLA 服務(wù)質(zhì)量。

2.支持后端 pod 的健康檢查

Pod 本身,K8s 的 kubelet 會(huì)做健康檢查,那么容器 LB 層面為何還需要對(duì) Pod(業(yè)務(wù)服務(wù))做健康檢查呢?

  • kubelet 本身可能會(huì)出現(xiàn)故障導(dǎo)致不能及時(shí)摘除異常的 Pod,因此我們不能完全信任 kubelet
  • 如果 Node 節(jié)點(diǎn)出現(xiàn)異常,那么 kubelet 把 pod 標(biāo)記不可用,基本需要幾十秒,也就是影響幾十秒之后才能檢測到

3.SlowStart 策略

Nginx 的商業(yè)版本有支持 slow_start 功能,使用如下:

upstream backend {
server backend1.example.com slow_start=30s;
server backend2.example.com;
}

SlowStart 策略是指配置了 SlowStart 策略的 server,在 SlowStart 時(shí)間范圍內(nèi),先給一定量的流量(比如 0% - 1%),在過了 SlowStart 時(shí)間之后,再恢復(fù) 100% 的流量。

這樣,在 SlowStart 時(shí)間范圍內(nèi),這個(gè) server 就可以在低流量下處理一些服務(wù)內(nèi)部初期的一些事情,比如 Java 服務(wù),可以在低流量下完成 jit 編譯、完成 Java 虛擬機(jī)初始化等,這樣,當(dāng)過了 SlowStart 時(shí)間之后,等一切就緒在恢復(fù) 100% 的流量,可以保證服務(wù)可以對(duì)外提供更好的質(zhì)量。

當(dāng)前,這個(gè)是商業(yè)版本的實(shí)現(xiàn),開源版本無法使用,因此就需要我們自己實(shí)現(xiàn),在 K8s 下,容器 LB 的 SlowStart 功能的具體實(shí)現(xiàn)可以參考文章前面的說明。

4.巡檢模塊

巡檢模塊不僅僅是針對(duì)容器 LB,可以是針對(duì)所有容器基礎(chǔ)模塊,這個(gè)的目的就在于,人為模擬一些實(shí)際情況,通過巡檢,把容器 LB 的各個(gè)環(huán)節(jié)都定期檢測一遍。這個(gè)在上線初期尤為重要。

巡檢模塊的實(shí)現(xiàn)至少包括如下:

  • 解耦待巡檢服務(wù)(利于增加不同的巡檢模塊)
  • 多久檢測一次(間隔、重試)
  • 檢測的異常定義(比如 latency、error 等)
  • 出現(xiàn)異常的處理機(jī)制(比如告警、輸出日志等)

通過巡檢模塊,可以有如下優(yōu)勢:

  • 首先可以保證容器 LB 出現(xiàn)問題能夠及時(shí)發(fā)現(xiàn),因?yàn)槭亲远x任務(wù)來檢測容器 LB 的各個(gè)環(huán)節(jié),因此大概率可以先于業(yè)務(wù)本身發(fā)現(xiàn)。巡檢模塊出現(xiàn)問題之后,需要及時(shí)告警給相關(guān)人員進(jìn)行處理
  • 然后因?yàn)檠矙z了容器 LB 的各個(gè)環(huán)節(jié),因此如果巡檢模塊沒有出現(xiàn)問題,那么容器 LB 的整體就基本是正常的,這個(gè)對(duì)于維護(hù)人員的信心度可以大大增強(qiáng)。

5.Nginx SLA 統(tǒng)計(jì)模塊

業(yè)界用的多是 tengine 的 ngx_http_reqstat_module,如果想要更優(yōu)化,可以在此基礎(chǔ)上進(jìn)行擴(kuò)展,增加如下這些功能:

  • 慢請(qǐng)求統(tǒng)計(jì)
  • 支持 http 自定義錯(cuò)誤碼(如 6xx 7xx) 等的統(tǒng)計(jì)
  • 自定義 http status 的統(tǒng)計(jì)
  • 支持以 upstream 為維度來統(tǒng)計(jì)

6.性能壓測和優(yōu)化

容器 LB 必須要進(jìn)行大量壓測和優(yōu)化,以求達(dá)到最優(yōu)的性能,提供最穩(wěn)定的服務(wù)。

本文轉(zhuǎn)載自微信公眾號(hào)「 后端系統(tǒng)和架構(gòu)」,作者「AllenWu」,可以通過以下二維碼關(guān)注。

轉(zhuǎn)載本文請(qǐng)聯(lián)系「 后端系統(tǒng)和架構(gòu)」公眾號(hào)。

責(zé)任編輯:武曉燕 來源: 后端系統(tǒng)和架構(gòu)
相關(guān)推薦

2021-10-18 11:58:56

負(fù)載均衡虛擬機(jī)

2022-07-18 18:48:32

Kubernetes云原生

2024-08-30 10:29:21

2024-11-27 16:37:57

2025-03-05 08:33:56

2021-04-25 10:26:58

云計(jì)算云原生

2021-07-14 18:21:38

負(fù)載均衡K8SgRPC

2025-01-03 08:08:56

2024-09-26 09:50:07

2024-07-15 07:55:00

2023-03-06 11:35:55

經(jīng)營分析體系

2022-04-07 10:17:18

云原生服務(wù)器優(yōu)化

2022-08-21 07:25:09

Flink云原生K8S

2023-03-06 07:19:50

2022-07-13 11:17:00

大數(shù)據(jù)規(guī)劃

2022-01-02 08:42:50

架構(gòu)部署容器

2018-02-01 10:31:12

Nginx負(fù)載均衡軟件

2022-07-15 16:31:49

Postman測試

2025-03-20 14:50:24

2021-08-09 11:43:02

容器云原生安全
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)