使用nginx的負載均衡機制實現用戶無感更新服務

  • 2020 年 2 月 13 日
  • 筆記

知識改變命運,擼碼使我快樂,2020繼續遊走在開源界 點贊再看,養成習慣 給我來個Star吧,點擊了解基於新一代接口服務框架 「ApiBoot」 的前後分離( 「Vue + ElementUI」 )管理平台基礎解決方案腳手架示例。

前言

用戶請求的轉發是接口服務在部署時必須要做的一步。

請求轉發的步驟大約分為如下幾步:

  1. 域名解析到轉發服務器
  2. 轉發服務器會根據權重(weight)、備用(backup)配置轉發到統一網關
  3. 如果統一網關存在灰度的配置,需要根據身份或者頭信息過濾請求
  4. 轉發到具體的業務服務

目前市面上優秀的請求轉發有很多種,比如:NginxF5KongTengine等,其中Tengine是阿里巴巴基於Nginx進行封裝,我們本章的內容基於Nginx進行講解,我們先來準備下nginx的測試環境。

準備環境

如果你的測試環境沒有安裝Nginx,下面我通過兩種方式來說下具體的安裝過程。

使用Brew安裝Nginx

如果你是OSX系統,可以直接使用brew管理工具進行安裝,這種方式比較簡單,自動從遠程服務器下載最新穩定的版本進行解壓、配置環境等。

# 安裝nginx  ➜  ~ brew install nginx

靜靜等待~

安裝完成後,我們先來修改下端口號(brew安裝包把默認的監聽端口號改為了8080,一般在使用解壓的方式安裝時監聽端口都是80)。

我們需要先找到nginx.conf這個文件的位置:

➜  ~ sudo find / -name nginx.conf  /usr/local/etc/nginx/nginx.conf

找到文件後,我們通過sudo vi /usr/local/etc/nginx/nginx.conf命令來修改默認的端口號,位置如下:

server {          listen       80;          server_name  localhost;          #...  }        

修改後保存退出。

最後不要忘記重啟Nginx服務。

➜  ~ brew services restart nginx

解壓包方式

首先去nginx官方提供 http://nginx.org/download 的下載地址去挑選自己中意的版本,下面以1.17.7版本示例:

點擊下載完成後解壓安裝即可(注意編譯環境,可能會缺少一些依賴庫,本機安裝對應的依賴就可以了)

# 解壓nginx  tar -xvf nginx-1.17.7.tar.gz  # 進入目錄  cd nginx-1.17.7  # 配置  ./configure --prefix=/usr/local/nginx  # 編譯  sudo make  # 安裝  sudo make install  # 進入nginx執行目錄  cd /usr/local/nginx/sbin  # 啟動nginx  ./nginx

安裝完成如果訪問 http://127.0.0.1 可以看到Welcome to nginx!字樣,說明我們已經安裝成功了。

示例項目

為了演示更新服務用戶無痛感知,我們先來創建一個簡單的SpringBoot示例項目,在項目內添加一個測試接口,項目pom.xml依賴如下所示:

<dependencies>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-web</artifactId>    </dependency>  </dependencies>

示例接口

創建一個名為TestController的測試控制器,如下所示:

/**   * 測試控制器   *   * @author 恆宇少年   */  @RestController  @RequestMapping(value = "/test")  public class TestController {      @Autowired      private ServerProperties serverProperties;        @GetMapping      public String hello() {          return "請求分發到了,端口號:" + serverProperties.getPort() + "的服務,接口訪問成功.";      }  }

配置轉發

我們測試所需要的請求接口已經準備好了,接下來需要在訪問nginx時將請求轉發到我們測試的接口,配置轉發時需要用到nginx的兩個關鍵字,分別是upstreamlocation

  • upstream:服務器組,配置請求分發到組內多台服務器。
  • location:轉發的路徑前綴,如:"/user/",當我們訪問http://127.0.0.1/user/1時,就會執行該location的轉發業務。

upstream轉發流程如下圖所示:

image

配置UpStream

nginx.conf文件http內添加轉發的服務器組(upstream),如下所示:

# 負載配置  upstream test {      server 127.0.0.1:8080 weight=1;      server 127.0.0.1:9090 weight=2;      server 127.0.0.1:9000 backup;  }

配置Location

在上面已經配置好了服務器組,我們需要把名為test的服務器組作為代理的方式配置在location,在locationserver下新增一個location,如下所示:

# 配置"/lb/"路徑的請求全部轉發到本地8080端口  location /lb/ {      proxy_pass http://test/;      proxy_set_header Host $host;      proxy_set_header X-Real-IP $remote_addr;      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;      proxy_connect_timeout       50;      proxy_read_timeout          50;      proxy_send_timeout          50;  }

重啟Nginx

我這裡是使用brew的方式安裝的nginx,所以重啟的命令如下所示:

brew services restart nginx

如果你是安裝包的方式安裝:

# 進入安裝包目錄  cd /usr/local/nginx/sbin  # 重載  ./nginx -s reload

權重配置

nginx中有一個權重的概念,根據權重值的大小來控制請求流量,當權重的配值越大時,流量分發就會越多,我們在test服務器組內配置權重解釋:

  • server 127.0.0.1:8080 weight 1; 權重佔比為1/3,每3次請求會轉發1次到這台服務器上。
  • server 127.0.0.1:9090 weight 2; 權重佔比為2/3,每3次請求會轉發2次到這台服務器上。

備用配置

當我們在upstream內的server尾部添加backup時,表示這台服務器是備用服務器,只有其他服務器都停機時才會啟用,我們更新時其實就利用的這一點。

運行測試

為了演示方便我們直接將本章測試項目package打包後,通過--server.port來指定運行的端口號來模擬多台服務器的場景。

# 啟動127.0.0.1:8080服務器  java -jar target/use-nginx-loadbalance-upgrade-service-0.0.1-SNAPSHOT.jar --server.port=8080  # 啟動127.0.0.1:9090服務器  java -jar target/use-nginx-loadbalance-upgrade-service-0.0.1-SNAPSHOT.jar --server.port=9090  # 啟動127.0.0.1:9000備用服務器  java -jar target/use-nginx-loadbalance-upgrade-service-0.0.1-SNAPSHOT.jar --server.port=9000

注意:使用多個終端窗口運行服務。

nginx.conf>server中配置location的轉發條件為/lb/路徑前綴,所以我們訪問 http://127.0.0.1/lb/test (由於nginx監聽的端口號是80,所以通過nginx訪問轉發時不需要攜帶端口號)就會被轉發到test服務器組內的服務器上。

測試點:權重轉發

curl http://localhost/lb/test  端口號:8080,接口訪問成功.    curl http://localhost/lb/test  端口號:9090,接口訪問成功.    curl http://localhost/lb/test  端口號:9090,接口訪問成功.    curl http://localhost/lb/test  端口號:8080,接口訪問成功. 

根據訪問的結果來看,8080端口號的服務是每3次中請求了1次,而9090則是每3次中請求了2次,這一點正是符合我們配置的權重(weight),測試通過。

測試點:備用生效

我們把80809090這兩個服務都停掉,再次訪問 http://127.0.0.1/lb/test

curl http://localhost/lb/test  端口號:9000,接口訪問成功.    curl http://localhost/lb/test  端口號:9000,接口訪問成功.    curl http://localhost/lb/test  端口號:9000,接口訪問成功.

可以看到我們的備用服務器啟用了,已經把全部的請求流量轉發到9000這台服務上,測試通過。

敲黑板,劃重點

當我們把80809090都停掉時,備用服務器會啟用,這時我們就可以來更新80809090這兩個服務的運行代碼,更新完成後重啟,只要80809090這兩台服務器有一台處於運行狀態,nginx就不會把流量分發到備用的9000,以此類推把全部的服務都更新完成。

代碼示例

如果您喜歡本篇文章請為源碼倉庫點個Star,謝謝!!! 本篇文章示例源碼可以通過以下途徑獲取,目錄為use-nginx-loadbalance-upgrade-service

作者個人 博客 使用開源框架 ApiBoot 助你成為Api接口服務架構師