nginx动态配置及服务发现那些事
这次的准备闲聊关于nginx服务发现的话题, 按照我以往写⽂章的性⼦,估计会迁移⼀些主题. 毕竟单纯聊nginx和动态服务发现没啥意思,因我以前的⽂章有⼤量的涉及到。
nginx upstream相关
我这⾥就不再精细的讲述nginx的源码, 毕竟我⾃⼰也只是粗略看了点nginx的底层代码. nginx的动态配置肯定是绕不过upstream模块的运作了,他主要的驱动是xxx_pass,⽐如最常⽤的proxy_pass, uwsgi_pass。upstream相关配置结构的建⽴,并不⼀定是⾮要配置upstream这个指令才会去做,有时proxy_pass直接就是跟⼀个ip地址或域名, 他其实隐式的调⽤upstream 。
那么⼀个具体的request过程如何跟upstream配置怎么关联起来的?
⾸先是通过peer.init函数指针初始化,然后根据round robbin算法选择ngx_http_upstream_init_round_robin_peer,每种算法锁出发的函数不⼀样,这是废话。 从配置上看,凡是请求到location /xxx的request请求,他们都关联到同⼀个upstream配置,但是既然⼤家公⽤⼀个结构,那么需不需要互斥呢?如果⼤家都要修改其中的某个成员…
实际上,nginx中⼀个请求不会中多个进程中同时处理,⼀个request⽣⽼病死都在⼀个worker内。 每个
nginx worker都会监听⾃⼰相关的epoll fd事件。 当⼀个worker争取到了nginx listen fd accept的锁,那么他就可以接收新的request请求,这个请求的创建出的fd会压到他本进程的事件⾥。 我想说的是,他不会逃到worker⾥, 因为也没这个必要这么实现,跨多进程传递socket本⾝是个很蛋疼的实现.
nginx relaod相关
那么nginx upstrem阐述完了,我们再聊聊nginx -s reload.
当你增删改upstream配置的时候,如何让nginx不停服务的重载配置? nginx -s reload. reload的实现相对好理解,-s的作⽤是向master进程发送信号。 其实是SIGHUP信号的封装,也就是说我们可以直接通过kill向nginx的pid发送SIGHUP信号来完成reload操作。 master通过ngx_signal_handler处理信号,见到reload就重置ngx_reconfigure = 1.
casengx_signal_value(NGX_RECONFIGURE_SIGNAL):
ngx_reconfigure = 1;
action = ", reconfiguring";
break;
这样当ngx_master_process_cycle的for循环中检测到ngx_reconfigure ==1,就开始做重加载配置的操作,通过
ngx_start_worker_processes开启新进程,⽽之前的进程则通过ngx_signal_worker_processes来发送信号进⾏“优雅”的关闭. 所谓优雅的关闭, 就是让当前真正处理请求的进程等到处理完之后再退出,当然进程不能再次参与accept锁的争夺了. 这样新的请求会拿到listen accept锁,可建⽴reqeust连接.
如何保证已经建连的连接 ?
如果是短连接,那么在请求完之后,worker会主动发送close(),后⾯就把fd事件给踢掉。
那么长连接会怎么办? 这个时候长连接是有两种的, 前者是是client 跟 nginx proxy的连接,后者是proxy跟后端服务的连接,⽐如nginx –> tornado 就属于后者.
nginx proxy主要就是给client提供服务,在对外请求完毕的情况下,右⾯的连接可有可⽆了, 当然我们还是操作proxy给后端服务发送close()关闭连接 。 如果发⽣异常进程退出,后端经过keepalive timeout后进⾏回收资源.
前者的连接就有点意思了, 当你的请求是http1.1长连接时候,不管是单次请求或者是stream这种流式请求,都会在请求完之后退出。 那么对于客户端有什么影响? 客户端会收到fin的tcp关闭请求,配合n
ginx关闭连接之后. 当你再次访问nginx的时候,才会重建⼀个连接…
什么是nginx的动态配置?
到此为⽌, nginx reload 和 upstream 都过了⼀遍. 那么动态配置⼜是什么? 我们什么时候需要动态配置?
我认为nginx的动态配置可以有这么⼏种⽅法.
⼀种是dns动态解析 ,⼀种是模板渲染, ⼀种服务发现动态配置重载.
碰巧,这⼏种配置我都有在线上⽤过,我不会单纯的说谁更好,谁更差,因为每个动态配置⽅法都有他的应⽤场景. ⽐如dns动态解析⾮常适合依赖域名来辨识主机的集服务,多⽤在类aws、阿⾥云这样的云服务. 模板动态配置⽅法更适合那种⼤型的运维平台管理体系. 服务发现配置适合那种docker化的服务, 或者类似的微服务框架体系.
第⼀种, dns动态解析
我们通常在配置nginx upstream的时候都会使⽤ip地址. 对于那种依赖域名的集服务,⾮常适合这样的配置. 因为你修改了⼀组域名的配置,你如果nginx域名来解析, 就不再重新配置了。 这个dns服务器
肯定不能是公⽹. 内⽹必须配置⼀个⾼性能的dns服务,⽐如dnsmasq, bind. 另外我们需要注意dns缓存的问题, nginx默认会根据dns server返回的ttl来设置记录的失效时间, 推荐配置成5s . 如果ttl太⼩,dns 也会成为⼀个瓶颈点.
dns的缺点也明显,那就是ip级别,很多时候⼀台服务器我们会开N个port, 动态的域名只能跟踪ip的级别, 这样显得很不灵活。 由于nginx dns动态解析多适⽤于云主机环境,云主机⼀般是⼀两个核,所以这是可以接受的.
如果你使⽤skydns的化,也可以实现我们后⾯讲述的动态服务发现.
我们可以简单的配置dns模式.:
resolver 10.0.0.1;
set ParseError: KaTeX parse error: Expected '}', got 'EOF' at end of input: …
proxy_passblog;
}
也可以配置更加的丰富. 我这边⽤的是tengine。
upstream backend {
dynamic_resolve fallback=stale fail_timeout=30s;
server a;
server b;
}
server {
proxy_pass backend;
}
nginx plus版的配置. 相对来说,nginx plus的功能更加丰富点,但是需要收费,我在free期间测试过该功能,通过.
#
parse error怎么解决resolver 10.0.0.1;
{
zone upstream_dynamic 64k;
ample:8080 fail_timeout=5s slow_start=30s;
ample resolve;
ample service=http resolve;
}
server {
location / {
proxy_pass ;
health_check;
}
}
第⼆种,动态模板解析
我在上⾯有说过动态模板解析的场景⼀般是那种运维平台系统, 我曾经在全⽹集调度平台,智能dns管理系统中使⽤过这种⽅法, 他的优点在于系统的集中式管理,本⾝来说这种管理⽅式只是把⼿动的操作变成⾃动化⽽已,但这种配置⽅式相当的稳定,只是每次渲染模板后都需要nginx -s reload.
另外他的开发成本还是不低的,⼩公司hold不住的,⼀般各⼤公司的运维平台多使⽤这种⽅式.
简单说下他的实现,⽐如python语⾔,我们可以使⽤jinja2、mako的模板引擎,动态的根据你提供变量渲染配置.
第三种,服务发现模式.
服务发现是这次的重点,博客⾥有聊过etcd、zookeeper、consul 这三种服务发现的使⽤及坑. 那么跟nginx是怎么实现的动态加载配置? 他跟nginx -s reload不⼀样, reload会重新开⼀组进程来接收请求,让⽼进程完事后再退出. 切记,如果你线上流量较⼤,不要频繁的reload, 因为nginx新⽼配置交替的时候会掉15%左右的qps .
其实并不⼀定要按照reload的路⼦⾛,我们可以针对nginx进⾏改造。 让他可以主动去拉取最新的服务发现⾥的主机. 在github中的不少nginx服务发现的实现,他们不会新开进程,⽽是在在master进程中注册⼀个定时器,该事件会触发watch,当发现version的版本号发⽣变更时,就知道主机列表发⽣了变化,进⽽重载配置. 那么如何让worker进程也使⽤新的配置? 这时候可能不会使⽤共享变量,因为读写都要加锁,及其影响速度. 所以每个worker都会缓存⼀份location upstream的配置,每个worker也会有个定时器,他的事件共享内存的upstream有⽆变化…
优点是什么? 服务发现模式特别适合微服务,更⽚⾯的说 docker服务化. 因为docker可以更加弹性的扩展缩减集的计算架构. 当docker容器起来后,直接给consul注册⼀个槽位,间隔性的发送健康⼼跳. 我们不需要管nginx的配置,nginx会⾃⼰动态的重载最新的配置. 当我们把docker容器⼲掉了,由于consul有配置过期⾃动清理记录,很⼤程度保证consul服务发现列表的 “纯洁性” .
⼀个nginx consul的场景图:
下图是etcd的服务发现流程. 服务的提供者会注册到服务注册中⼼上,请求者在请求之前会访问⼀次注册中⼼,从⾥⾯取出主机记录才会进⼀步访问.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论