使用nginx的负载均衡机制实现用户无感更新服务
域名解析到转发服务器
转发服务器会根据权重(weight)、备用(backup)配置转发到统一网关
如果统一网关存在灰度的配置,需要根据身份或者头信息过滤请求
转发到具体的业务服务
请求转发
有很多种,比如:
Nginx
、
F5
、
Kong
、
Tengine
等,其中
Tengine
是阿里巴巴基于
Nginx
进行封装,我们本章的内容基于
Nginx
进行讲解,我们先来准备下
nginx
的测试环境。
Nginx
,下面我通过两种方式来说下具体的安装过程。
OSX
系统,可以直接使用
brew
管理工具进行安装,这种方式比较简单,自动从远程服务器下载最新稳定的版本进行解压、配置环境等。
# 安装nginx
➜ ~ brew install nginx
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
版本示例:
http://nginx.org/download/nginx-1.17.7.tar.gz
# 解压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
Welcometo 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
的两个关键字,分别是
upstream
、
location
。
upstream:服务器组,配置请求分发到组内多台服务器。
location:转发的路径前缀,如:"/user/",当我们访问
http://127.0.0.1/user/1
时,就会执行该location
的转发业务。
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;
}
test
的服务器组作为代理的方式配置在
location
,在
location
的
server
下新增一个
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;
}
brew
的方式安装的
nginx
,所以重启的命令如下所示:
brew services restart nginx
安装包
的方式安装:
# 进入安装包目录
cd /usr/local/nginx/sbin
# 重载
./nginx -s reload
nginx
中有一个权重的概念,根据权重值的大小来控制请求流量,当权重的配值越大时,流量分发就会越多,我们在
test
服务器组内配置权重解释:
server127.0.0.1:8080weight1;
权重占比为1/3
,每3次请求会转发1次到这台服务器上。server127.0.0.1:9090weight2;
权重占比为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
),测试通过。
测试点:备用生效
8080
、
9090
这两个服务都停掉,再次访问 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
这台服务上,测试通过。
8080
、
9090
都停掉时,备用服务器会启用,这时我们就可以来更新
8080
、
9090
这两个服务的运行代码,更新完成后重启,只要
8080
、
9090
这两台服务器有一台处于运行状态,
nginx
就不会把流量分发到备用的
9000
,以此类推把全部的服务都更新完成。