|
|
# Nginx
|
|
|
|
|
|
## Nginx工作模式?
|
|
|
|
|
|
Nginx采用master-worker模式,nginx启动成功后,会有一个master进程和至少一个worker进程;master进程负责处理系统信号、加载配置、管理worker进程;worker进程负责处理具体的业务逻辑。
|
|
|
|
|
|
nginx采用了异步非阻塞的工作方式,epoll模型:当有i/o事件产生时,epoll就会告诉进程哪个连接由i/o事件产生,然后进程就会处理这个事件。nginx配置use epoll后,以异步非阻塞的方式工作,能够处理百万计的并发连接。
|
|
|
|
|
|
master-worker模式的优缺点:
|
|
|
|
|
|
- 稳定性高
|
|
|
|
|
|
一个worker进程挂掉后master进程会立即启动一个新的worker进程,保证worker进程数量不变,降低服务中断的概率
|
|
|
|
|
|
- 高性能
|
|
|
|
|
|
Nginx 启动 N 个 worker, 并将 worker 和 cpu 进行绑定,每个 worker 有自己的 epoll 和 定时器,由于没有进程、线程切换开销,性能非常好。配合Linux的cpu亲和性的匹配中,可以充分利用多核cpu的优势,提升性能
|
|
|
|
|
|
- 支持平滑重启
|
|
|
|
|
|
处理信号、配置重新加载等可以做到尽可能不中断服务
|
|
|
|
|
|
|
|
|
## Nginx Location 路径匹配规则是怎么样的?
|
|
|
|
|
|
对于请求: http://example.com/static/img/logo.jpg
|
|
|
|
|
|
1. 如果命中精确匹配,例如:
|
|
|
|
|
|
```
|
|
|
location = /static/img/logo.jpg {
|
|
|
|
|
|
}
|
|
|
```
|
|
|
|
|
|
则优先精确匹配,并终止匹配。
|
|
|
|
|
|
2. 如果命中多个前缀匹配,例如:
|
|
|
|
|
|
```
|
|
|
location /static/ {
|
|
|
|
|
|
}
|
|
|
|
|
|
location /static/img/ {
|
|
|
|
|
|
}
|
|
|
```
|
|
|
|
|
|
则记住最长的前缀匹配,即上例中的 /static/img/,并继续匹配
|
|
|
|
|
|
3. 如果最长的前缀匹配是优先前缀匹配,即:
|
|
|
|
|
|
```
|
|
|
location /static/ {
|
|
|
|
|
|
}
|
|
|
|
|
|
location ^~ /static/img/ {
|
|
|
|
|
|
}
|
|
|
```
|
|
|
|
|
|
4. 否则,如果命中多个正则匹配,即:
|
|
|
|
|
|
```
|
|
|
location /static/ {
|
|
|
|
|
|
}
|
|
|
|
|
|
location /static/img/ {
|
|
|
|
|
|
}
|
|
|
|
|
|
location ~* /static/ {
|
|
|
|
|
|
}
|
|
|
|
|
|
location ~* /static/img/ {
|
|
|
|
|
|
}
|
|
|
```
|
|
|
|
|
|
则忘记上述 2 中的最长前缀匹配,使用第一个命中的正则匹配,即上例中的 location ~* /static/ ,并终止匹配(命中多个正则匹配,优先使用配置文件中出现次序的第一个)
|
|
|
|
|
|
5. 否则,命中上述 2 中记住的最长前缀匹配
|
|
|
|
|
|
## Nginx的负载均衡策略有哪些?
|
|
|
|
|
|
负载均衡策略 | 说明
|
|
|
--- | ---
|
|
|
轮询(rr) | 负载均衡默认策略
|
|
|
weight | 权重方式,权重越高分配到需要处理的请求越多,此策略比较适合服务器的硬件配置差别比较大的情况。此策略可以与least_conn和ip_hash结合使用。
|
|
|
ip_hash | 依据ip分配方式,基于客户端IP的分配方式,确保了相同的客户端的请求一直发送到相同的服务器,实现会话粘滞目的
|
|
|
least_conn | 最少连接方式,把请求转发给连接数较少的后端服务器,可以达到更好的负载均衡效果
|
|
|
fair(第三方) | 响应时间方式
|
|
|
url_hash(第三方) | 依据URL分配方式
|
|
|
|
|
|
## nginx基于权重轮询平滑算法是怎么实现的?
|
|
|
|
|
|
常规的基于权重的轮询调度算,假定a, b, c三台机器的负载能力分别是4:2:1,则可以给它们分配的权限为4, 2, 1。 这样轮询完一次后,a被调用4次,b被调用2次,c被调用1次。
|
|
|
|
|
|
对于普通的基于权重的轮询算法,可能会产生以下的调度顺序{a, a, a, a, b, b, c}。这样的调度顺序其实并不友好,它会一下子把大压力压到同一台机器上,这样会产生一个机器一下子很忙的情况。 于是乎,就有了平滑的基于权重的轮询算法。
|
|
|
|
|
|
所谓平滑就是调度不会集中压在同一台权重比较高的机器上。这样对所有机器都更加公平。 比如,对于{a:5, b:1, c:1},产生{a, a, b, a, c, a, a}的调度序列就比{c, b, a, a, a, a, a} 更加平滑。
|
|
|
|
|
|
**算法逻辑:**
|
|
|
|
|
|
算法执行2步,选择出1个当前节点。
|
|
|
|
|
|
1. 用上次选择后的权重加上每个节点配置的权重,作为节点当前权重值,第一选择的时候,上次选择后的权重都是0
|
|
|
2. 选择当前权重值最大的节点为选中节点,并把它的当前值减去所有节点的权重总和,作为选择后的权重值
|
|
|
|
|
|
例如{a:5, b:1, c:1}三个节点。一开始我们初始化三个节点的当前值为{0, 0, 0}。 选择过程如下表:
|
|
|
|
|
|
|
|
|
轮数 | 当前权重 | 选择节点 | 选择后的权重
|
|
|
--- | --- | --- | ---
|
|
|
0 | - | - | {0, 0, 0}
|
|
|
1 | {5, 1, 1} | a | {-2, 1, 1}
|
|
|
2 | {3, 2, 2} | a | {-4, 2, 2}
|
|
|
3 | {1, 3, 3} | b | {1, -4, 3}
|
|
|
4 | {6, -3, 4} | a | {-1, -3, 4}
|
|
|
5 | {4, -2, 5} | c | {4, -2, -2}
|
|
|
6 | {9, -1, -1} | a | {2, -1, -1}
|
|
|
7 | {7, 0, 0} | a | {0, 0, 0}
|
|
|
|
|
|
我们可以发现,a, b, c选择的次数符合5:1:1,而且权重大的不会被连接选择。7轮选择后, 当前值又回到{0, 0, 0},以上操作可以一直循环,一样符合平滑和基于权重。
|
|
|
|
|
|
## nginx四层、七层负载均衡的有什么区别?
|
|
|
|
|
|
四层就是基于IP+端口的负载均衡,通过虚拟IP+端口接收请求,然后再分配到真实的服务器;nginx修改数据包里面的目标和源IP和端口,然后把数据包发向目标服务器,服务器处理完成后,nginx再做一次修改,返回给请求的客户端。
|
|
|
|
|
|
七层通过虚拟的URL或主机名接收请求,然后再分配到真实的服务器。七层就是基于URL等应用层信息的负载均衡。Nginx需要读取并解析http请求内容,然后根据具体内容(url,参数,cookie,请求头)然后转发到相应的服务器,转发的过程是:建立和目标机器的连接,然后转发请求,收到响应数据在转发给请求客户端。
|
|
|
|
|
|
七层负载均衡是:
|
|
|
|
|
|
|
|
|
```
|
|
|
# cat /etc/nginx/conf.d/test.conf
|
|
|
upstream phpserver {
|
|
|
server192.168.2.3;
|
|
|
server192.168.2.4;
|
|
|
}
|
|
|
upstream htmlserver {
|
|
|
server192.168.2.1;
|
|
|
server192.168.2.2;
|
|
|
}
|
|
|
|
|
|
# /etc/nginx/nginx.conf
|
|
|
location / {
|
|
|
root /usr/share/nginx/html;
|
|
|
index index.html index.htm;
|
|
|
if ($request_uri ~*\.html$){
|
|
|
proxy_pass http://htmlserver;
|
|
|
}
|
|
|
if ($request_uri~* \.php$){
|
|
|
proxy_pass http://phpserver;
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
四层负载均衡:
|
|
|
|
|
|
```
|
|
|
# vim nginx.conf
|
|
|
worker_processes 1;
|
|
|
events {
|
|
|
worker_connections 1024;
|
|
|
}
|
|
|
stream { # 类似于7层的http段
|
|
|
upstream ssh_proxy {
|
|
|
hash $remote_addr consistent;
|
|
|
server 192.168.56.2:22;
|
|
|
server 192.168.56.3:22;
|
|
|
}
|
|
|
server {
|
|
|
listen 2222;
|
|
|
proxy_connect_timeout 1s;
|
|
|
proxy_timeout 3s;
|
|
|
proxy_pass ssh_proxy;
|
|
|
}
|
|
|
}
|
|
|
```
|