浅析代理
Nginx功能
- 正向代理:客户端不知道服务端,也就是说客户端需要配置代理服务器来,代理服务器再去访问真正的服务端。挂梯子就是正向代理的应用。
- 反向代理:服务端不知道客户端,客户端不需要进行任何配置,用户只请求反向代理地址,反向代理服务器选择目标服务器,获取数据返回客户端。
- 负载均衡:在反向代理中,我们可以使用负载均衡去将请求分配到不同的服务器上。
- 动静分离:Nginx将接到的请求分为动态请求和静态请求,这在实际的应用中对应了前后端。
Nginx原理
Master - Worker 模式
在启动Nginx后,我们通过ps -ef可以发现有关nginx的进程有一个master process和n个worker process,并且我们查看nginx监听的端口,可以看到监听了80端口。
-
Master process: master进程的作用主要是读取并且验证nginx.conf, 并且管理worker进程,给worker进程传递消息。
-
Worker process: 每一个Worker进程都维护了一个线程去处理连接和请求(避免一个线程造成的线程切换问题),一般cpu几核就有几个worker进程。
- 所有的worker进程都是从master进程fork()过来的,worker进程提供好listenfd的接口, 为了保证只有一个进程处理连接,所有的Worker进程在注册listenfd接口读取事件前抢互斥锁accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里面调用accept接受连接,开始处理请求。
- Nginx采取上面的这种进程模型的好处:
- 独立进程不需要加锁,省去锁的开销
- 独立进程互不影响,服务不会中断
- 独立进程异常退出,只影响该进程的请求
- Cache Manager process: 除了上面两个进程外,我们还可以看到Cache Manager process, 与之对应的还有Cache Loader process(在nginx服务启动的时候由主进程生成,缓存数据加载完成后退出), Cache Manager process负责缓存索引的还礼,通过缓存机制,可以提高对请求的响应效率。
模块化
Nginx从功能上可以分为:
- Handlers: 处理请求,进行输出内容和修改headers等,一般只有一个
- Filters: 接收请求进行链式修改
- Proxies: Nginx的Htpp Upstream等模块,主要和后端进行交互,实现服务代理和负载均衡等
Nginx(内核)本身做的工作实际很少,当它接到一个 HTTP 请求时,它仅仅是通过查找配置文件将此次请求映射到一个 location block,而此 location 中所配置的各个指令则会启动不同的模块去完成工作,因此模块可以看做 Nginx 真正的劳动工作者。通常一个 location 中的指令会涉及一个 Handler 模块和多个 Filter 模块(当然,多个location可以复用同一个模块)。Handler模块负责处理请求,完成响应内容的生成,而 Filter 模块对响应内容进行处理。
Nginx配置
代理案例
- 修改线上后端服务地址为本地服务地址,方便调试
当我们想要线上页面点击请求的是本地启动的服务时,可以这样配置,找到想要修改的服务,例如xxx,重点在于最后一句代理转发,将原来的线上地址换成本地服务地址即可。
|
|
然后执行nginx -t检查配置文件,nginx -s reload热重启即可,这时候线上页面点击的请求都会到达本地的后端,方便调试。
- http请求代理+负载均衡
需求:http请求,没有上下文,需要增加负载均衡
实际修改:
Step1: 新增upstream配置,负载均衡的策略使用默认的。nginx.conf中已经include,所以不需要再include
|
|
Step2: include_http.conf添加新配置,以getBook请求为例:
|
|
-t, -s reload重启即可,则http://运管ip/getBook最终的请求将会被平均的转发到113和20两台服务器上。
- GET请求修改uri中的参数,例如: https://10.195.185.113/getBook?book=xx&userToken=xx&appToken=xx
|
|
除了上述的一些简单的配置,其它复杂的配置大家可以看看使用lua来修改。
Nginx相关配置
- tcp_nodelay
Nagle Algorithm: John Nagle的名字来命名的,John Nagle在1984年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题(RFC 896)。如果每次发送一个1 byte的数据包,实际大小需要40(20ip header bytes + 20 tcp header bytes) + 1 byte = 41bytes,Nagle算法解决了该问题,如果包的大小满足MSS,那么可以立即发送,否则放入缓冲区,等到已经发送的包被确认了之后继续发送。
DelayedAcknowledgment: 如果需要单独确认每个包的大小的话,那么整个网络当中将充斥着无数的ACK,降低网络性能,DelayedAcknowledgment规定: 不再针对单个包发送ACK确认,而是一次确认两个包,或者在发送相应数据的时候捎带这发送ACK,又或者出发超时时间后再发送ACK。
上述的两个解决网络性能问题的方法如果在一起使用,会触发延迟问题,如果TCP client端启用了Nagle Algorithm, Server启用 Delayed ACK,并且发送的数据包比较小,Client端需要等待Server端对上一个packet的Ack才能发送当前Packet,Server延迟发送Ack,那整个通信将会被延迟。
- 数据量小,交互多的情况需禁用Nagle算法和Delay,TCP_NODELAY: on
- 数据量大,交互少需要开启,这种情况典型的应用是文件服务器
- 仅长连接使用
- tcp_nopush
tcp_nopush就是开启linux中的TCP_CORK(塞子), 类似于在发送数据管道处插一个cork,阻塞所有数据,直到取消cork,全部发送阻塞数据。
tcp_nopush和sendfile一起使用。
- sendfile
正常网络文件传输过程:
file -> 硬盘 -> kernel buffer -> user buffer -> kernel socket buffer -> 协议栈
senfile网络文件传输过程:
file -> 硬盘 -> kernel buffer(快速拷贝到kernel socket buffer) -> 协议栈
性能提升
写在最后
nginx整体非常强大,尤其是openresty的加持,如果大家有兴趣可以多了解了解。