基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

零壹技術棧發表於2019-03-02

前言

上一篇文章使用 ConsulRegistratordocker 的容器環境中搭建了服務註冊和發現叢集。在服務發現和註冊的基礎上,本文將引入 Nginx反向代理伺服器和 Consul-template 元件,實現動態的服務負載均衡


正文

1. 工具介紹

1.1. Nginx

一個高效能的 HTTP反向代理伺服器,用於前端訪問流量到後臺應用伺服器負載均衡請求轉發

1.2. Consul-template

Consul-templateHashiCorp 基於 Consul 所提供的可擴充套件的工具,通過監聽 Consul 中的資料變化,動態地修改一些配置檔案中地模板。常用於在 NginxHAProxy 上動態配置健康狀態下的客戶端反向代理資訊。

2. 實現原理

  • 通過 Nginx 自身實現負載均衡請求轉發
  • 通過 Consul-templateconfig 功能實時監控 Consul 叢集節點的服務資料的變化;
  • 實時的用 Consul 節點的資訊替換 Nginx 配置檔案的模板,並重新載入配置檔案;

Consul-templatenginx 必須安裝在同一臺機器上,因為 Consul-template 需要動態修改 nginx 的配置檔案 nginx.conf,然後執行 nginx -s reload 命令進行路由更新,達到動態負載均衡的目的。

2.1. 傳統負載均衡

傳統的負載均衡,就是 Client 支姐訪問 Nginx,然後被轉發到後端某一臺 Web Server。如果後端有新增/刪除 Web Server,運維需要手動改下 nginx.conf ,然後重新載入配置,就可以動態的調整負載均衡。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

2.2. 自動負載均衡

再看看基於服務自動發現和註冊的負載均衡,負載均衡的方式沒有變,只是多了一些外圍元件,當然這些元件對 Client 是不可見的,client 依然只能看到 Nginx 入口,訪問方式也沒變化。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

Nginx 的動態負載均衡實現流程如下:

  1. 以相同的 Consul 標籤Web Server 進行服務標記分類新增或者刪除 Web Server 伺服器節點;
  2. Registrator 監控Web Server 的狀態更新,自動在 Consul服務註冊中心將它註冊或者登出
  3. Consul-template 訂閱了 Consul 服務註冊中心的服務訊息,接收到 Consul 的訊息推送,即 Web Server 服務節點狀態發生改變。
  4. Consul-template 自動去修改和替換 Nginx 伺服器下的 nginx配置檔案中的模板,並重新載入服務達到自動負載均衡的目的。

3. 環境準備

3.1. 系統環境

軟體 版本
作業系統 Ubuntu:16.04 x86_64,核心:4.8.0-58-generic
docker Docker version 1.12.6, build 78d1802
docker-compose docker-compose version 1.8.0

3.2. 節點規劃

主機IP 元件
192.168.1.181 Consul Server, Registrator, Nginx, Consul-template
192.168.1.186 Consul Server, Registrator, Nginx, Consul-template
192.168.1.182 Consul Client, Registrator, Client WebApp1, Server WebApp1, Server WebApp2
192.168.1.183 Consul Client, Registrator, Client WebApp2, Server WebApp3, Server WebApp4
192.168.1.185 Consul Client, Registrator, Client WebApp3, Server WebApp5, Server WebApp6
  • Client WebApp:提供基於ThriftRPC客戶端和基於Http協議的RESTful客戶端,用於訪問 Server 程式。
  • Server WebApp:提供基於ThriftRPC服務端和基於Http協議的RESTful服務端,供 Client 程式呼叫。

這裡的3臺主機 - 192.168.1.182192.168.1.183192.168.1.185,每臺主機部署兩個 Client WebApp 容器和一個 Client Server 容器,用於模擬服務層的負載均衡。

3.3. 映象構建

  • Consul:consul:latest
  • Registrator:gliderlabs/registrator:latest
  • NginxConsul-template:liberalman/nginx-consul-template:latest
  • Client WebApp:test-client:latest
  • Server WebApp:test-server:latest

這裡先說說 test-clienttest-server 的映象構建:

  1. 克隆專案到本地專案環境: github.com/ostenant/sp…
  2. 切換到子模組 spring-cloud-starter-thrift-examples 下的 test 目錄,執行命令 mvn clean package 進行程式打包。
  3. 分別將 test-clienttest-server 專案根目錄下的 Dockerfile 檔案和target目錄下的 target/*.jar程式拷貝到 192.168.1.182192.168.1.183192.168.1.185 目錄下。
  4. 進入客戶端 Dockerfile 所在目錄,對客戶端程式 test-client 進行映象構建,命令如下:docker build . -t test-client:latest
  5. 進入服務端 Dockerfile 所在目錄,對服務端程式 test-server 進行映象構建,命令如下:docker build . -t test-server:latest

構建完成後檢視本地映象庫:

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

3.4. 部署模型

五臺主機,其中 192.168.1.181192.168.1.186 兩臺主機的主要作用如下:

  1. 作為負載均衡轉發器 (這裡只是演示,可以通過 KeepAlived 實現 NginxHA),將前端訪問流量經過負載演算法一次轉發到後臺 Client WebApp
  2. Server模式啟動 Consul節點,其中一臺作為整個服務發現與註冊叢集leader, 用於同步持久化其餘三臺 Client 模式的 Consul 節點的資料狀態資訊

其餘三臺主機 - 192.168.1.182192.168.1.183192.168.1.185,充當的角色如下:

  1. 每臺分別以 Client 模式部署 Consul 節點,用於註冊發現本機 docker 容器暴露的服務,同時和 Consul Serverleader 節點進行服務狀態同步
  2. 分別啟動一個 Client WebApp 容器例項和兩個 Server WebApp 容器例項,將 Client WebApp 的請求根據服務層的負載演算法二次轉發Server WebApp 中的任意一臺上完成具體的業務處理。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

這裡有兩次服務轉發操作:

  • 接入層的轉發:兩臺 Nginx 伺服器將客戶流量,經由一次轉發至三個 Client WebApp 服務例項中任意一個做處理。
  • 服務層的轉發:三個 Client WebApp服務例項其中之一,根據從服務註冊中心拉取的健康的服務快取列表,將請求二次轉發至六個 Server WebApp服務例項其中之一做處理。

3.5. 開始搭建

3.5.1. Consul Server主機

(a). 分別編寫 docker-compose.yml,注意 Registrator 需要配置各自的 IP地址。

  • 主機:192.168.1.181

docker-compose.yml

version: '2'
services:
  load_balancer:
    image: liberalman/nginx-consul-template:latest
    hostname: lb
    links:
      - consul_server_master:consul
    ports:
      - "80:80"

  consul_server_master:
    image: consul:latest
    hostname: consul_server_master
    ports:
      - "8300:8300"
      - "8301:8301"
      - "8302:8302"
      - "8400:8400"
      - "8500:8500"
      - "8600:8600"
    command: consul agent -server -bootstrap-expect 1 -advertise 192.168.1.181 -node consul_server_master -data-dir /tmp/data-dir -client 0.0.0.0 -ui

  registrator:
    image: gliderlabs/registrator:latest
    hostname: registrator
    links:
      - consul_server_master:consul
    volumes:
      - "/var/run/docker.sock:/tmp/docker.sock"
    command:  -ip 192.168.1.181 consul://192.168.1.181:8500
複製程式碼
  • 主機:192.168.1.186

docker-compose.yml

version: '2'
services:
  load_balancer:
    image: liberalman/nginx-consul-template:latest
    hostname: lb
    links:
      - consul_server_slave:consul
    ports:
      - "80:80"

  consul_server_slave:
    image: consul:latest
    hostname: consul_server_slave
    ports:
      - "8300:8300"
      - "8301:8301"
      - "8302:8302"
      - "8400:8400"
      - "8500:8500"
      - "8600:8600"
    command: consul agent -server -join=192.168.1.181 -advertise 192.168.1.186 -node consul_server_slave -data-dir /tmp/data-dir -client 0.0.0.0 -ui

  registrator:
    image: gliderlabs/registrator:latest
    hostname: registrator
    links:
      - consul_server_slave:consul
    volumes:
      - "/var/run/docker.sock:/tmp/docker.sock"
    command:  -ip 192.168.1.186 consul://192.168.1.186:8500
複製程式碼

(b). 在兩臺主機上分別通過 docker-compose 啟動多容器應用,命令如下:

docker-compose up -d
複製程式碼

這是在主機 192.168.1.181 上執行啟動命令時的輸出,可以看到 docker-compose 啟動時會先去檢查目標映象檔案是否拉取到本地,然後依次建立啟動 docker-compose.yml 檔案配置的容器例項

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

(c). 檢視正常啟動的容器程式,觀察ConsulRegistratorNginx/Consul-template的容器都正常啟動。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

(d). 利用 docker-compose,以相同的方式在主機 192.168.1.186 上啟動所配置的容器服務例項,檢視啟動狀態如下:

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

(e). 訪問 http://IP:8500 檢視 Consul Server節點資訊服務註冊列表

  • 節點資訊:

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

  • 服務狀態列表:

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

兩臺 Consul Server 主機上的容器服務例項均正常啟動!

3.5.2. Consul Client主機

一般情況下,我們把 Consul 作為服務註冊與發現中心,會使用它提供的服務定義 (Service Definition) 和健康檢查定義 (Health Check Definition) 功能,相關配置說明參考如下:

服務定義

環境變數Key 環境變數Value 說明
SERVICE_ID web-001 可以為GUID或者可讀性更強變數,保證不重複
SERVICE_NAME web 如果ID沒有設定,Consul會將name作為id,則有可能註冊失敗
SERVICE_TAGS nodejs,web 服務的標籤,用逗號分隔,開發者可以根據標籤來查詢一些資訊
SERVICE_IP 內網IP 要使用Consul,可訪問的IP
SERVICE_PORT 50001 應用的IP, 如果應用監聽了多個埠,理應被視為多個應用
SERVICE_IGNORE Boolean 是否忽略本Container,可以為一些不需要註冊的Container新增此屬性

服健康檢查定義

配置原則為: SERVICE_XXX_*。如果你的應用監聽的是 5000 埠,則改為 SERVICE_5000_CHECK_HTTP,其它環境變數配置同理。

環境變數Key 環境變數Value 說明
--- 以下為HTTP模式 --- ---
SERVICE_80_CHECK_HTTP /path_to_health_check 你的健康狀態檢查的路徑如 /status
SERVICE_80_CHECK_INTERVAL 15s 15秒檢查一次
SERVICE_80_CHECK_TIMEOUT 2s 狀態檢查超時時間
--- 以下為HTTPS模式 --- ---
SERVICE_443_CHECK_HTTPS /path_to_health_check 你的健康狀態檢查的路徑如 /status
SERVICE_443_CHECK_INTERVAL 15s 15秒檢查一次
SERVICE_443_CHECK_TIMEOUT 2s 狀態檢查超時時間
--- 以下為TCP模式 --- ---
SERVICE_443_CHECK_TCP /path_to_health_check 你的健康狀態檢查的路徑如 /status
SERVICE_443_CHECK_INTERVAL 15s 15秒檢查一次
SERVICE_443_CHECK_TIMEOUT 2s 狀態檢查超時時間
--- 使用指令碼檢查 --- ---
SERVICE_CHECK_SCRIPT curl --silent --fail example.com 如官方例子中的check_redis.py
--- 其他 --- ---
SERVICE_CHECK_INITIAL_STATUS passing Consul預設註冊後的服務為failed

配置說明

(a). 分別編寫 docker-compose.yml,同樣注意 Registrator 需要配置各自的 IP 地址。test-servertest-client服務例項在配置時需要指定相關的環境變數

  • 主機:192.168.1.182

docker-compose.yml

version: '2'
services:
  consul_client_01:
    image: consul:latest
    ports:
      - "8300:8300"
      - "8301:8301"
      - "8301:8301/udp"
      - "8302:8302"
      - "8302:8302/udp"
      - "8400:8400"
      - "8500:8500"
      - "8600:8600"
    command: consul agent -retry-join 192.168.1.181 -advertise 192.168.1.182 -node consul_client_01 -data-dir /tmp/data-dir -client 0.0.0.0 -ui

  registrator:
    image: gliderlabs/registrator:latest
    volumes:
      - "/var/run/docker.sock:/tmp/docker.sock"
    command:  -ip 192.168.1.182 consul://192.168.1.182:8500

  test_server_1:
    image: test-server:latest
    environment:
      - SERVICE_8080_NAME=test-server-http-service
      - SERVICE_8080_TAGS=test-server-http-service-01
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/health
      - SERVICE_25000_NAME=test-server-thrift-service
      - SERVICE_25000_TAGS=test-server-thrift-service-01
      - SERVICE_25000_CHECK_INTERVAL=10s
      - SERVICE_25000_CHECK_TIMEOUT=2s
      - SERVICE_25000_CHECK_TCP=/
    ports:
      - "16000:8080"
      - "30000:25000"

  test_server_2:
    image: test-server:latest
    environment:
      - SERVICE_8080_NAME=test-server-http-service
      - SERVICE_8080_TAGS=test-server-http-service-02
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/health
      - SERVICE_25000_NAME=test-server-thrift-service
      - SERVICE_25000_TAGS=test-server-thrift-service-02
      - SERVICE_25000_CHECK_INTERVAL=10s
      - SERVICE_25000_CHECK_TIMEOUT=2s
      - SERVICE_25000_CHECK_TCP=/
    ports:
      - "18000:8080"
      - "32000:25000"

  test_client_1:
    image: test-client:latest
    environment:
      - SERVICE_8080_NAME=my-web-server
      - SERVICE_8080_TAGS=test-client-http-service-01
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/features
    ports:
      - "80:8080"
複製程式碼
  • 主機:192.168.1.183

docker-compose.yml

version: '2'
services:
  consul_client_02:
    image: consul:latest
    ports:
      - "8300:8300"
      - "8301:8301"
      - "8301:8301/udp"
      - "8302:8302"
      - "8302:8302/udp"
      - "8400:8400"
      - "8500:8500"
      - "8600:8600"
    command: consul agent -retry-join 192.168.1.181 -advertise 192.168.1.183 -node consul_client_02 -data-dir /tmp/data-dir -client 0.0.0.0 -ui

  registrator:
    image: gliderlabs/registrator:latest
    volumes:
      - "/var/run/docker.sock:/tmp/docker.sock"
    command:  -ip 192.168.1.183 consul://192.168.1.183:8500

  test_server_1:
    image: test-server:latest
    environment:
      - SERVICE_8080_NAME=test-server-http-service
      - SERVICE_8080_TAGS=test-server-http-service-03
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/health
      - SERVICE_25000_NAME=test-server-thrift-service
      - SERVICE_25000_TAGS=test-server-thrift-service-03
      - SERVICE_25000_CHECK_INTERVAL=10s
      - SERVICE_25000_CHECK_TIMEOUT=2s
      - SERVICE_25000_CHECK_TCP=/
    ports:
      - "16000:8080"
      - "30000:25000"

  test_server_2:
    image: test-server:latest
    environment:
      - SERVICE_8080_NAME=test-server-http-service
      - SERVICE_8080_TAGS=test-server-http-service-04
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/health
      - SERVICE_25000_NAME=test-server-thrift-service
      - SERVICE_25000_TAGS=test-server-thrift-service-04
      - SERVICE_25000_CHECK_INTERVAL=10s
      - SERVICE_25000_CHECK_TIMEOUT=2s
      - SERVICE_25000_CHECK_TCP=/
    ports:
      - "18000:8080"
      - "32000:25000"

  test_client_1:
    image: test-client:latest
    environment:
      - SERVICE_8080_NAME=my-web-server
      - SERVICE_8080_TAGS=test-client-http-service-02
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/features
    ports:
      - "80:8080"
複製程式碼
  • 主機:192.168.1.185

docker-compose.yml

version: '2'
services:
  consul_client_03:
    image: consul:latest
    ports:
      - "8300:8300"
      - "8301:8301"
      - "8301:8301/udp"
      - "8302:8302"
      - "8302:8302/udp"
      - "8400:8400"
      - "8500:8500"
      - "8600:8600"
    command: consul agent -retry-join 192.168.1.181 -advertise 192.168.1.185 -node consul_client_03 -data-dir /tmp/data-dir -client 0.0.0.0 -ui

  registrator:
    image: gliderlabs/registrator:latest
    volumes:
      - "/var/run/docker.sock:/tmp/docker.sock"
    command:  -ip 192.168.1.185 consul://192.168.1.185:8500

  test_server_1:
    image: test-server:latest
    environment:
      - SERVICE_8080_NAME=test-server-http-service
      - SERVICE_8080_TAGS=test-server-http-service-05
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/health
      - SERVICE_25000_NAME=test-server-thrift-service
      - SERVICE_25000_TAGS=test-server-thrift-service-05
      - SERVICE_25000_CHECK_INTERVAL=10s
      - SERVICE_25000_CHECK_TIMEOUT=2s
      - SERVICE_25000_CHECK_TCP=/
    ports:
      - "16000:8080"
      - "30000:25000"

  test_server_2:
    image: test-server:latest
    environment:
      - SERVICE_8080_NAME=test-server-http-service
      - SERVICE_8080_TAGS=test-server-http-service-06
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/health
      - SERVICE_25000_NAME=test-server-thrift-service
      - SERVICE_25000_TAGS=test-server-thrift-service-06
      - SERVICE_25000_CHECK_INTERVAL=10s
      - SERVICE_25000_CHECK_TIMEOUT=2s
      - SERVICE_25000_CHECK_TCP=/
    ports:
      - "18000:8080"
      - "32000:25000"

  test_client_1:
    image: test-client:latest
    environment:
      - SERVICE_8080_NAME=my-web-server
      - SERVICE_8080_TAGS=test-client-http-service-03
      - SERVICE_8080_CHECK_INTERVAL=10s
      - SERVICE_8080_CHECK_TIMEOUT=2s
      - SERVICE_8080_CHECK_HTTP=/features
    ports:
      - "80:8080"
複製程式碼

注意:我們使用的第三方映象 liberalman/nginx-consul-templateNginx 會把名稱為 my-web-server服務容器作為後臺轉發的目標伺服器,因此,在 test-client 的配置項中,需要指定 SERVICE_XXX_NAMEmy-web-server。當然你也可以自己製作映象指定模板

(b). 在三臺主機上使用 docker-compose 啟動多容器應用:

docker-compose up -d
複製程式碼

以主機 192.168.1.182 為例 (其餘兩臺類似),控制檯日誌顯示,建立並啟動 docker-compose.yml 檔案配置的5個容器例項

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

(c). 檢視正常啟動的容器程式,觀察到 Consul、一臺test-client 和 兩臺test-server的容器都正常啟動。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

(d). 在 b 操作中的控制檯輸出可以看到:docker-compose 並非按照 docker-compose.yml 檔案中服務配置的先後順序啟動。 registrator 容器的啟動依賴於 consul 容器,而此時 consul 還並未啟動,就出現了 registrator 優先啟動而異常退出的現象。解決方法是再執行一次 docker-compose up -d 命令。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

(e). 再次檢視容器程式,此時 Registrator 容器就已經正常啟動了。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

(f). 以相同的方式在其餘兩臺主機上重複以上操作,再次訪問 http://IP:8500 檢視 Consul Server節點資訊服務註冊列表

  • Consul 叢集節點資訊,包括兩臺 Consul Server 節點和一臺 Consul Client 節點,節點右側可以看到所有的服務註冊列表和相關的健康檢查結果

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

  • nginx 服務狀態列表,服務名稱 nginx-consul-template,提供 http 服務,共有2個服務例項:

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

  • test-client 服務狀態列表,服務名稱為 my-web-server,提供 http 服務,共有3個服務例項:

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

  • test-server 服務狀態列表,服務名稱為 test-server-http-servicetest-server-thrift-service,分別對應6個 http 服務例項和 6個 thrift 服務例項:

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

三臺 Consul Client 主機上的容器服務例項均正常啟動,服務註冊和發現執行正常!

4. 結果驗證

4.1. Nginx負載均衡

4.1.1. 訪問Nginx

Nginx 預設訪問埠號為80,任選一臺 Nginx 訪問,比如: http://192.168.1.181/swagger-ui.html

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

請求轉發至 Test ClientSwagger頁面,表明 nginx配置檔案 nginx.confConsul-template 成功修改。

4.1.2. 進入Nginx容器

執行 docker ps 檢視 nginx-consul-template 的容器 ID,比如這裡是:4f2731a7e0cb。進入 nginx-consul-template 容器。

docker-enter 4f2731a7e0cb
複製程式碼

檢視容器內部的程式列表:

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

特別留意以下一行程式命令,這裡完成了三步重要的操作:

consul-template -consul-addr=consul:8500 -template /etc/consul-templates/nginx.conf.ctmpl:/etc/nginx/conf.d/app.conf:nginx -s reload
複製程式碼
  1. Consul-template 利用 Consul 上的服務資訊Nginx配置檔案模板 /etc/consul-templates/nginx.conf.ctmpl 進行重新解析渲染
  2. 渲染生成的 nginx 配置檔案為 /etc/nginx/conf.d/app.conf
  3. 進一步執行 nginx -s reload 重新載入 app.conf,更新路由轉發列表

檢視 app.conf 的配置項,發現三個 test-client 節點的 IP:port 都加入了路由轉發列表中。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

退出並關閉主機 192.168.1.182 上的 test-client 容器。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

再次檢視 app.conf,可以發現路由節點 192.168.1.182:80 已經從 Nginx路由轉發列表剔除掉了。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

同樣的,重新啟動 test-client 恢復容器,又可以發現 Nginx路由轉發列表 再次自動將其新增!

4.2. 服務負載均衡

4.2.1. 介面測試

test-client 通過 http 通訊方式請求任意一臺 test-server,返回響應結果 (請求處理時間 ms )。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

test-client 通過 thrift 通訊方式請求任意一臺 test-server,返回響應結果 (請求處理時間 ms )。

基於Docker + Consul + Nginx + Consul-template的服務負載均衡實現

4.2.3. 日誌分析

服務的負載均衡並不是很好觀察,這裡直接擷取了一段 test-client服務快取列表動態定時重新整理時列印的日誌:

2018-02-09 13:15:55.157  INFO 1 --- [erListUpdater-1] t.c.l.ThriftConsulServerListLoadBalancer : Refreshed thrift serverList: [
test-server-thrift-service: [
	ThriftServerNode{node='consul_client_01', serviceId='test-server-thrift-service', tags=[test-server-thrift-service-01], host='192.168.1.182', port=30000, address='192.168.1.182', isHealth=true},
	ThriftServerNode{node='consul_client_01', serviceId='test-server-thrift-service', tags=[test-server-thrift-service-02], host='192.168.1.182', port=32000, address='192.168.1.182', isHealth=true},
	ThriftServerNode{node='consul_client_02', serviceId='test-server-thrift-service', tags=[test-server-thrift-service-03], host='192.168.1.183', port=30000, address='192.168.1.183', isHealth=true},
	ThriftServerNode{node='consul_client_02', serviceId='test-server-thrift-service', tags=[test-server-thrift-service-04], host='192.168.1.183', port=32000, address='192.168.1.183', isHealth=true},
	ThriftServerNode{node='consul_client_03', serviceId='test-server-thrift-service', tags=[test-server-thrift-service-05], host='192.168.1.185', port=30000, address='192.168.1.185', isHealth=true},
	ThriftServerNode{node='consul_client_03', serviceId='test-server-thrift-service', tags=[test-server-thrift-service-06], host='192.168.1.185', port=32000, address='192.168.1.185', isHealth=true}
],
test-server-http-service: [
	ThriftServerNode{node='consul_client_01', serviceId='test-server-http-service', tags=[test-server-http-service-01], host='192.168.1.182', port=16000, address='192.168.1.182', isHealth=true},
	ThriftServerNode{node='consul_client_01', serviceId='test-server-http-service', tags=[test-server-http-service-02], host='192.168.1.182', port=18000, address='192.168.1.182', isHealth=true},
	ThriftServerNode{node='consul_client_02', serviceId='test-server-http-service', tags=[test-server-http-service-03], host='192.168.1.183', port=16000, address='192.168.1.183', isHealth=true},
	ThriftServerNode{node='consul_client_02', serviceId='test-server-http-service', tags=[test-server-http-service-04], host='192.168.1.183', port=18000, address='192.168.1.183', isHealth=true},
	ThriftServerNode{node='consul_client_03', serviceId='test-server-http-service', tags=[test-server-http-service-05], host='192.168.1.185', port=16000, address='192.168.1.185', isHealth=true},
	ThriftServerNode{node='consul_client_03', serviceId='test-server-http-service', tags=[test-server-http-service-06], host='192.168.1.185', port=18000, address='192.168.1.185', isHealth=true}
],
my-web-server: [
	ThriftServerNode{node='consul_client_01', serviceId='my-web-server', tags=[test-client-http-service-01], host='192.168.1.182', port=80, address='192.168.1.182', isHealth=true},
	ThriftServerNode{node='consul_client_02', serviceId='my-web-server', tags=[test-client-http-service-02], host='192.168.1.183', port=80, address='192.168.1.183', isHealth=true},
	ThriftServerNode{node='consul_client_03', serviceId='my-web-server', tags=[test-client-http-service-03], host='192.168.1.185', port=80, address='192.168.1.185', isHealth=true}
]]
複製程式碼

服務例項

  • test-server-http-service 所有健康的服務例項:
服務IP地址 服務埠 服務標籤
192.168.1.182 16000 test-server-http-service-01
192.168.1.182 18000 test-server-http-service-02
192.168.1.183 16000 test-server-http-service-03
192.168.1.183 18000 test-server-http-service-04
192.168.1.185 16000 test-server-http-service-05
192.168.1.185 18000 test-server-http-service-06
  • test-server-thrift-service 所有健康的服務例項:
服務IP地址 服務埠 服務標籤
192.168.1.182 30000 test-server-thrift-service-01
192.168.1.182 32000 test-server-thrift-service-02
192.168.1.183 30000 test-server-thrift-service-03
192.168.1.183 32000 test-server-thrift-service-04
192.168.1.185 30000 test-server-thrift-service-05
192.168.1.185 32000 test-server-thrift-service-06
  • my-web-server 所有健康的服務例項:
服務IP地址 服務埠 服務標籤
192.168.1.182 80 test-client-http-service-01
192.168.1.183 80 test-client-http-service-02
192.168.1.185 80 test-client-http-service-03

spring-cloud-starter-thrift 採用的輪詢的轉發策略,也就是說 my-web-server 會按次序迴圈往來地將 http 或者 rpc 請求分發到各自的 6服務例項完成處理。


總結

本文提供了一套基於微服務服務註冊與發現體系容器高可用 (HA) 解決方案,引入了接入層服務層自動負載均衡的實現,詳細給出了實踐方案技術手段


歡迎關注技術公眾號: 零壹技術棧

零壹技術棧

本帳號將持續分享後端技術乾貨,包括虛擬機器基礎,多執行緒程式設計,高效能框架,非同步、快取和訊息中介軟體,分散式和微服務,架構學習和進階等學習資料和文章。

相關文章