nginx+upsync+consul 构建动态nginx配置系统
参考:
http://www.php230.com/weixin1456193048.html 【upsync模块说明、性能评测】
https://www.jianshu.com/p/76352efc5657
https://www.jianshu.com/p/c3fe55e6a5f2
根源问题
nginx reload是有一定损耗的,如果你使用的是长连接的话,那么当reload nginx时长连接所有的worker进程会进行优雅退出,并当该worker进程上的所有连接都释放时,进程才真正退出。
Consul+Consul-template的问题
动态nginx负载均衡的配置,可以通过Consul+Consul-template方式,但是这种方案有个缺点:每次发现配置变更都需要reload nginx,而reload是有一定损耗的。而且,如果你需要长连接支持的话,那么当reloadnginx时长连接所在worker进程会进行优雅退出,并当该worker进程上的所有连接都释放时,进程才真正退出(表现为worker进程处于worker process is shutting down)。因此,如果能做到不reload就能动态更改upstream,那么就完美了。
解决办法
对于社区版nginx目前有三个选择方式:
- Tengine 的Dyups模块。
- 微博的Upsync+Consul 实现动态负载均衡。
- 使用OpenResty的balancer_by_lua,而又拍云使用其开源的slardar(Consul + balancer_by_lua)实现动态负载均衡。
本文使用upsync模块来解决配置文件修改后,reload nginx进程造成性能下降的问题。
Upsync介绍
Nginx 以其超高的性能与稳定性,在业界获得了广泛的使用,微博的七层就大量使用了 Nginx 。结合 Nginx 的健康检查模块,以及动态 reload 机制,可以近乎无损的服务的升级上线与扩容。这个时候扩容的频次比较低,大多数情况下是有计划的扩容。
Upsync,开发了模块 nginx-upsync-module,它的功能是拉取 consul 的后端 server 的列表,并更新 Nginx 的路由信息。此模块不依赖于任何第三方模块。 consul 作为 Nginx 的 db,利用 consul 的 KV 服务,每个 Nginx work 进程独立的去拉取各个 upstream 的配置,并更新各自的路由。流程图如下:
应用案例:
模块已经应用在微博的各类业务中,下面图表对比分析使用模块前后的 QPS 与耗时变化。
从数据可以得出,reload 操作时造成 nginx 的请求处理能力下降约 10%,Nginx 本身的耗时会增长 50%+。若是频繁的扩容缩容,reload 操作造成的开销会更加明显。
upsync模块+consul 来实现动态负载均衡
这里我们使用的是upsync模块+consul 来实现动态负载均衡。操作笔记如下:
consul的命令很简单,官方文档有详细的样例供参考,这里略过。
实验环境:
3台centos7.3机器
cat /etc/hosts 如下:
192.168.5.71 node71
192.168.5.72 node72
192.168.5.73 node73
consul 我们使用3节点都是server角色。如果集群内某个节点宕机的话,集群会自动重新选主的。
nginx-Upsync模块:新浪微博开源的,,它的功能是拉取 consul 的后端 server 的列表,并更新 Nginx 的路由信息。且reload对nginx性能影响很少。
1、安装nginx+ nginx-upsync-module(3台机器上都执行安装)
nginx-upsync-module模块: https://github.com/weibocom/nginx-upsync-module
nginx版本:1.13.8
yum install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel -y
cd /root/
git clone https://github.com/weibocom/nginx-upsync-module.git
# 建议使用git clone代码编译,刚开始我使用release的tar.gz 编译nginx失败了
groupadd nginx
useradd -g nginx -s /sbin/nologin nginx
mkdir -p /var/tmp/nginx/client/
mkdir -p /usr/local/nginx
tar xf nginx-1.13.8.tar.gz
cd /root/nginx-1.13.8
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_flv_module --with-http_stub_status_module --with-http_gzip_static_module --with-http_realip_module --http-client-body-temp-path=/var/tmp/nginx/client/ --http-proxy-temp-path=/var/tmp/nginx/proxy/ --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi --http-scgi-temp-path=/var/tmp/nginx/scgi --with-pcre --add-module=/root/nginx-upsync-module
make && make install
echo 'export PATH=/usr/local/nginx/sbin:$PATH' >> /etc/profile
source /etc/profile
2、配置nginx虚拟主机
在node1上配置虚拟主机:
cat /usr/local/nginx/conf/nginx.conf 内容如下:
user nginx;
worker_processes 4;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
server {
listen 80;
server_name 192.168.5.71;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
}
创建网页文件:
echo 'node71' > /usr/share/nginx/html/index.html
在node3上启动虚拟主机:
cat /usr/local/nginx/conf/nginx.conf 内容如下:
user nginx;
worker_processes 4;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
server {
listen 80;
server_name 192.168.5.73;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
}
创建网页文件:
echo 'node73' > /usr/share/nginx/html/index.html
在node2上配置虚拟主机:
此处的node2作为LB负载均衡+代理服务器使用
cat /usr/local/nginx/conf/nginx.conf 内容如下:
user nginx;
worker_processes 1;
error_log logs/error.log notice;
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'$upstream_addr $upstream_status $upstream_response_time $request_time';
access_log logs/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
upstream pic_backend {
# 兜底假数据
# server 192.168.5.72:82;
# upsync模块会去consul拉取最新的upstream信息并存到本地的文件中
upsync 192.168.5.72:8500/v1/kv/upstreams/pic_backend upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
upsync_dump_path /usr/local/nginx/conf/servers/servers_pic_backend.conf;
}
# LB对外信息
server {
listen 80;
server_name 192.168.5.72;
location = / {
proxy_pass http://pic_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header real $upstream_addr;
}
location = /upstream_show {
upstream_show;
}
location = /upstream_status {
stub_status on;
access_log off;
}
}
# 兜底的后端服务器
server {
listen 82;
server_name 192.168.5.72;
location / {
root /usr/share/nginx/html82/;
index index.html index.htm;
}
}
}
创建网页文件:
mkdir /usr/share/nginx/html82 -p
echo 'fake data in SLB_72' > /usr/share/nginx/html82/index.html
创建upsync_dump_path(consul、upsync存放upstream主机信息使用到这个目录)
mkdir /usr/local/nginx/conf/servers/
3、安装consul(3台机器上都执行安装)
cd /root/
mkdir /usr/local/consul/
unzip consul_1.0.0_linux_amd64.zip
mv consul /usr/local/consul/
mkdir /etc/consul.d
cd /usr/local/consul/
echo 'export PATH=/usr/local/consul/:$PATH' >> /etc/profile
source /etc/profile
node71上:
/usr/local/consul/consul agent -server -bootstrap-expect 3 -ui -node=node71 -config-dir=/etc/consul.d --data-dir=/etc/consul.d -bind=192.168.5.71 -client 0.0.0.0
node72上:
/usr/local/consul/consul agent -server -bootstrap-expect 3 -ui -node=node72 -config-dir=/etc/consul.d --data-dir=/etc/consul.d -bind=192.168.5.72 -client 0.0.0.0 -join 192.168.5.71
意思是把本节点加入到192.168.5.71这个ip的节点中
node73上:
/usr/local/consul/consul agent -server -bootstrap-expect 3 -ui -node=node73 -config-dir=/etc/consul.d --data-dir=/etc/consul.d -bind=192.168.5.73 -client 0.0.0.0 -join 192.168.5.71
意思是把本节点加入到192.168.5.71这个ip的节点中
这样的话,就在3台主机前台启动了consul程序。
可以在任一台主机上执行:
consul members 列出当前集群的节点状态
consul info 列出当前集群的节点详细信息 (输出信息太多,自己运行时候看去吧)
访问consul自带的web界面
http://192.168.5.71/upstream_show (3个节点都开了webui,因此我们访问任意节点都行)
在任一节点上执行如下命令,即可添加2个key-value信息:
curl -X PUT -d '{"weight":10, "max_fails":2, "fail_timeout":10, "down":0}' http://192.168.5.71:8500/v1/kv/upstreams/pic_backend/192.168.5.71:80
curl -X PUT -d '{"weight":10, "max_fails":2, "fail_timeout":10, "down":0}' http://192.168.5.71:8500/v1/kv/upstreams/pic_backend/192.168.5.73:80
在web界面,就可看到如下所示:
删除的命令是:
curl -X DELETE http://192.168.5.71:8500/v1/kv/upstreams/pic_backend/192.168.5.71:80
curl -X DELETE http://192.168.5.71:8500/v1/kv/upstreams/pic_backend/192.168.5.73:80
调整后端服务的参数:
curl -X PUT -d '{"weight":10, "max_fails":2, "fail_timeout":10, "down":0}' http://192.168.5.71:8500/v1/kv/upstreams/test/192.168.5.71:80
4、测试consul+nginx调度
在node1、node2、node3上都执行 /usr/local/nginx/sbin/nginx 启动nginx服务
访问http://192.168.5.72/upstream_show
访问http://192.168.5.72/upstream_status
刚才我们在第三步的时候,执行了如下2条命令,自动在consul里面加了2行内容。
curl -X PUT -d '{"weight":10, "max_fails":2, "fail_timeout":10, "down":0}' http://192.168.5.71:8500/v1/kv/upstreams/pic_backend/192.168.5.71:80
curl -X PUT -d '{"weight":10, "max_fails":2, "fail_timeout":10, "down":0}' http://192.168.5.71:8500/v1/kv/upstreams/pic_backend/192.168.5.73:80
我们node2的nginx在启动的时候,会去nginx.conf里面配置的consul地址去寻找对应的upstream信息。同时会dump一份upstream的配置到/usr/local/nginx/conf/servers目录下。
[root@node72 /usr/local/nginx/conf/servers ]# cat servers_pic_backend.conf
server 192.168.5.73:80 weight=10 max_fails=2 fail_timeout=10s;
server 192.168.5.71:80 weight=10 max_fails=2 fail_timeout=10s;
我们可以写个curl脚本测试下,如下
for i in {1..100} ;do curl http://192.168.5.72/; done > /root/log
grep -c node71 /root/log ;grep -c node73 /root/log
可以看到curl是轮询请求到后端的node1和node3上去的。
或者使用for i in {1..100} ;do curl -s -I http://192.168.5.72/|tail -2 |head -1; done
如果要下线后端主机进行发布的话,只要把down参数置为1即可,类似如下:
curl -X PUT -d '{"weight":2, "max_fails":2, "fail_timeout":10, "down":1}' http://192.168.5.71:8500/v1/kv/upstreams/test/192.168.5.73:80
如果发布完成并验证后,需要上线,可以再次把down参数置为0:
curl -X PUT -d '{"weight":2, "max_fails":2, "fail_timeout":10, "down":0}' http://192.168.5.71:8500/v1/kv/upstreams/test/192.168.5.73:80
如果调整在线调整后端服务的upstream参数:
curl -X PUT -d '{"weight":2, "max_fails":2, "fail_timeout":10, "down":0}' http://192.168.5.71:8500/v1/kv/upstreams/test/192.168.5.73:80
说明:
1、每次去拉取 consul 都会设置连接超时,由于 consul 在无更新的情况下默认会 hang 五分钟,所以响应超时配置时间应大于五分钟。大于五分钟之后,consul 依旧没有返回,便直接做超时处理。
2、由于upsync模块会在pull新数据时候,自动在本地存一份upstream配置的副本。因此即便我们上面的3个consul进程全部宕掉了,nginx服务短时间内也不会受到影响。只要我们的监控完善及时将consul进程启动即可。
此外,还可使用nginx +consulconsul-template这种架构来控制nginx的配置
具体可以参考:
https://www.jianshu.com/p/9976e874c099
https://www.jianshu.com/p/a4c04a3eeb57?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
https://www.cnblogs.com/MrCandy/p/7152312.html
https://github.com/hashicorp/consul-template
官方提供的nginx参考模板:https://github.com/hashicorp/consul-template/blob/master/examples/nginx.md
转自:https://blog.51cto.com/lee90/2056182
nginx+upsync+consul 构建动态nginx配置系统的更多相关文章
- 通过Nginx、Consul、Upsync实现动态负载均衡和服务平滑发布
前提 前段时间顺利地把整个服务集群和中间件全部从UCloud迁移到阿里云,笔者担任了架构和半个运维的角色.这里详细记录一下通过Nginx.Consul.Upsync实现动态负载均衡和服务平滑发布的核心 ...
- 转:NGNIX模块开发——nginx的配置系统
From:http://tengine.taobao.org/book/chapter_02.html nginx的配置系统 nginx的配置系统由一个主配置文件和其他一些辅助的配置文件构成.这些配置 ...
- ECS centos6.8系统下从nginx安装到简单网站上线配置操作的完整记录
1.准备工作 1.1已购买阿里云云服务器ECS 1.2域名已购买并解析成功 1.3安装有远程链接工具Xshell和文件传输工具Xftf,并链接上ECS实例 2.安装nginx(在Xshell操作) 2 ...
- nginx的配置系统
nginx的配置系统由一个主配置文件和其他一些辅助的配置文件构成.这些配置文件均是纯文本文件,全部位于nginx安装目录下的conf目录下. 配置文件中以#开始的行,或者是前面有若干空格或者TAB,然 ...
- docker:nginx+confd动态生成配置
docker:nginx+confd动态生成配置 当我们项目越来越多时手动去服务器修改nginx配置是一件很麻烦而且可能出错的事情.我们可以通过nginx+confd+配置中心实现一套方案避免出错并减 ...
- linux系统中Nginx+FFmPeg+vlc实现网页视频播放配置过程
linux系统中Nginx+FFmPeg实现网页监控视频播放配置过程 1.安装好的nginx上添加模块nginx-http-fiv-module-master 此模块是rtmp模块的升级版,有它所有的 ...
- 15、基于consul+consul-template+registrator+nginx实现自动服务发现
一.架构图 二.组件介绍 1.Registrator Registrator:一个由Go语言编写的,针对docker使用的,通过检查本机容器进程在线或者停止运行状态,去注册服务的工具.所以我们要做的实 ...
- 2-4、nginx特性及基础概念-nginx web服务配置详解
Nginx Nginx:engine X 调用了libevent:高性能的网络库 epoll():基于事件驱动event的网络库文件 Nginx的特性: 模块化设计.较好扩展性(不支持模块动态装卸载, ...
- 使用Nginx、Keepalived构建文艺负载均衡
面对网站服务器端负载增大的问题,是"拿15万¥买一台服务器"来解决,还是靠"加三倍服务器"来解决?还是用其它一些办法? 对于一个访问量日益增加的网站架构而言,从 ...
随机推荐
- HDU 6583 Typewriter(后缀自动机)
Typewrite \[ Time Limit: 1500 ms\quad Memory Limit: 262144 kB \] 题意 给出一个字符串 \(s\),现在你需要构造出这个字符串,你每次可 ...
- Traefik 2.0 发布了
Traefik 2.0 发布了,包含了很多不错的行特性 tcp 路由(同时也支持sni 路由) 参考配置 tcp: routers: to-db-1: entrypoints: - web-secur ...
- [CQOI2007]涂色paint(BZOJ 1260)题解
题目描述 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字符串表示这个目标:RGBGR. 每次你可以把一段连续的木版涂成一个 ...
- 【题解】洛谷 P1080 国王游戏
目录 题目 思路 \(Code\) 题目 P1080 国王游戏 思路 贪心+高精度.按\(a \times b\)从小到大排序就可以了. \(Code\) #include<bits/stdc+ ...
- 面试题必备-web页面基础
html标签是由<>包围的关键词 html标签是成对出现的 有部分标签是没有结束标签的,叫单标签, 页面中所有的内容,都是要放在HTML标签中的 HTML标签分三部分: 标签名称 标签内容 ...
- Web Components 入门实例教程
转自阮一峰http://www.ruanyifeng.com/blog/2019/08/web_components.html 组件是前端的发展方向,现在流行的 React 和 Vue 都是组件框架. ...
- XMLHttpRequest用法介绍
前言: 传统的Web应用请求服务器返回的一般是是完整的HTML页面,这样往往就需要页面进行刷新操作,不仅耗时而且用户体验度也不好.最典型的代表就是form表单登录操作了.如果登录失败往往是跳转到原网页 ...
- java.lang.IllegalArgumentException: host parameter is null
即 URL 应为 http://www.baidu.com 但是实际配置成了 www.baidu.com 所以出现此错误
- springboot(1)@SpringBootApplication
首先来看下Spring Boot项目中的运行类,基本上每个项目都会有该启动类: @SpringBootApplication public class Application { public sta ...
- Salt Highstate数据结构定义
作者言 这篇文档详细解释了SLS文件中,每个部分的名称与含义,以及SLS中的数据处理后的数据结构. 我只是SaltStack的初学者,如果文中有错误的地方,请不吝赐教.在学习的过程,我做了一些实验,犯 ...