前面的博客介绍了怎么编译支持http3的nginx,并添加了upsync模块。为了在生产环境验证QUIC,我在aws搭建了一个Nginx + upsync + consul的集群 ,支持动态负载均衡。
consul介绍
consul是HashiCorp公司(曾经开发过vgrant) 推出的一款开源工具, 基于go语言开发, 轻量级, 用于实现分布式系统的服务发现与配置。
consul内置有KV存储, 服务注册/发现, 健康检查, HTTP+DNS API, Web UI等多种功能。
架构说明:
- Consul 集群由Consul Agent的节点组成, 在集群中有两种角色: Server和 Client 。
- Server和Client只是Consul的两种角色,二者之间并没有什么区别,只是人为的角色划分。
- Consul Server : 用于维护Consul 集群的状态信息, 实现数据一致性。 多个server之中会基于Raft协议选举出一个leader。 多个Server节点上的Consul数据信息保持强一致性。 在局域网内与本地客户端通讯,通过广域网与其他数据中心通讯。
Consul Client: 只维护自身的状态, 并将HTTP和DNS接口请求转发给服务端。 - Consul 支持多数据中心, 多个数据中心要求每个数据中心都要安装一组Consul集群,多个数据中心间基于gossip protocol协议来通讯
搭建方案 :
consul server 存储tomcat服务器的信息
consul client 端负责对服务器进行健康检查并同步到server
nginx间隔时间动态获取最新的consul server配置信息, 这样nginx 就可以实现动态负载均衡了。
AWS部署流程
我是使用的AWS来部署的实例,这里也简单记录下vpc和实例的构建过程
一.VPC,子网,网关,路由表创建
- 创建VPC ,选择IPv4 CIDR
- 创建四个子网 两个公有子网和两个私有子网(分别处于不同的可用区域–为了DR): quic-subnet1,quic-subnet2,quic-internal1,quic-internal2
- 创建互联网网关并关联到对应的VPC; 在主路由表里添加互联网网关的路由,然后关联主路由表到对应的公有子网
- 创建弹性ip后并创建对应的NAT网关(在quic-subnet1上),创建路由表(路由target为nat)并关联到私有子网
二.创建实例
- 创建安全组
1) 堡垒机 开放22端口的SSH访问
2) nginx-quic的安全组
3) tomcat集群的安全组
4) consul-server的安全组 - 创建堡垒机实例,并分配弹性IP (quic-subnet1上)
- 分别创建quic-nginx-upsync-1,quic-nginx-upsync-2,quic-tomcat-1,consul-server1,consul-server2的实例
- 创建网络负载均衡器和目标群组(因为使用的quic,所以负载均衡器协议是TCP_UDP)
注意:由于AWS申请了5个弹性IP之后,再申请分配就会提示到达上限,需要将之前的弹性IP先取消关联,分配给新的实例
consul 集群部署
consul server : 172.33.36.48, 172.33.63.50 (这里我只部署了两台,实际是3server + 4 client)
consul client (和tomcat在一台机子上) : 172.33.35.141
wget https://releases.hashicorp.com/consul/1.7.5/consul_1.7.5_linux_amd64.zip
## sudo -i 切换到root用户下
unzip consul_0.7.5_linux_amd64.zip
分别在consul server 172.33.36.48, 172.33.63.50 上编写配置文件
{
"server": true,
"ui": true,
"data_dir": "/opt/consul_dir/data",
"datacenter": "dc1",
"node_name": "server1",
"log_level": "info",
"bind_addr": "172.33.36.48",
"client_addr": "172.33.36.48",
"retry_join": ["172.33.36.48","172.33.63.50"]
}
{
"server": true,
"ui": true,
"data_dir": "/opt/consul_dir/data",
"datacenter": "dc1",
"node_name": "server2",
"log_level": "info",
"bind_addr": "172.33.63.50",
"client_addr": "172.33.63.50",
"retry_join": ["172.33.36.48","172.33.63.50"]
}
在consul client 172.33.35.141上编写配置文件 , 搭建其他client的时候只要把配置文件上的bind_addr, client_addr 修改为对应IP即可
{
"server": false,
"ui": true,
"data_dir": "/opt/consul_dir/data",
"datacenter": "dc1",
"node_name": "client1",
"log_level": "info",
"bind_addr": "172.33.35.141",
"client_addr": "172.33.35.141",
"retry_join": ["172.33.36.48","172.33.63.50"],
"service": {
"id": "1",
"name": "quic",
"address": "172.33.35.141",
"port": 8080,
"check": {
"id": "quic",
"name": "HTTPAPI on port 8080",
"http": "http://172.33.35.141:8080/quic/api/checkHealth",
"interval": "10s",
"timeout": "1s"
}
}
}
为了方便启动,编写了两个shell脚本
## consul server的启动脚本
#!/bin/sh
cd /opt
nohup ./consul agent -bootstrap-expect=1 -config-dir=/opt/consul_dir/server.json >> /opt/logs/consul.log 2>&1 &
## consul client的启动脚本
#!/bin/sh
cd /opt
nohup ./consul agent -config-dir=/opt/consul_dir/client.json >> /opt/logs/consul.log 2>&1 &
通过端口映射,可以看到consul的三个节点都正常启动了,也选举出了leader
添加nginx upstream服务信息到consul
我们可以使用linux命令方式发送put请求:
curl -X PUT http://172.33.36.48:8500/v1/kv/upstreams/quic/172.33.35.141:8080
请求发送成功后就可以在consul web 界面看到对应的服务器信息了
部署Nginx
前面一篇博客已经在自己的服务器上成功安装了nginx(添加了quiche和upsync模块)。只要把安装目录/opt/server下的nginx打包部署到aws实例的相应目录下就可以了
最后只需要修改下nginx的配置文件就可以了
在nginx.conf里通过include引入如下配置文件,这样我们只需要修改conf.d里的配置文件就可以了,这样就可以避免修改原来的配置文件
server {
listen 80;
# nginx服务器的ip地址
server_name 172.33.17.51;
location / {
root html;
index index.html index.htm;
}
}
include /opt/server/nginx/conf/conf.d/*.conf;
# another virtual host using mix of IP-, name-, and port-based configuration
quic.conf
upstream myserver {
server 127.0.0.1:11111;
#超时是6m 间隔是500m
upsync 172.33.36.48:8500/v1/kv/upstreams/quic upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
upsync 172.33.63.50:8500/v1/kv/upstreams/quic upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
#从consul拉取的上游服务器后持久化的位置
upsync_dump_path /opt/data/consul/server.conf;
}
server {
# Enable QUIC and HTTP/3.
listen 443 quic reuseport;
# Enable HTTP/2 (optional).
listen 443 ssl http2;
ssl_certificate /opt/ssl/fullchain.pem;
ssl_certificate_key /opt/ssl/privkey.pem;
# Enable all TLS versions (TLSv1.3 is required for QUIC).
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
# Add Alt-Svc header to negotiate HTTP/3.
add_header alt-svc 'h3-29=":443"; ma=86400';
location /quic {
proxy_pass http://myserver;
}
}
然后通过sbin/nginx -c conf/nginx.conf
命令启动nginx就可以了
绑定域名到对应的负载均衡器
最后只要将域名绑定到对应的负载均衡器上,我们就可以通过域名访问到对应的api了
请求url成功
quic协议的验证在上一篇博客里已经写过了,需要的可以参照该博客
部署过程遇到的问题 :
一开始我的bind_addr和client_addr都写的127.0.0.1,结果出现了如下报错信息。需要将bind_addr的ip改成consul server与其他节点交互的内网ip