负载组件-Nginx

正向和反向代理

正向代理代理的对象是客户端,反向代理代理的对象是服务端

正向代理

我们常说的代理也就是只正向代理,正向代理是一个位于客户端和最终目标服务器之间的服务器,为了从最终目标服务器取得内容,客户端向代理发送一个请求并指定目标,然后代理向原始服务器转交请求并将获得的内容返回给客户端.客户端必须要进行一些特别的设置才能使用正向代理.
他的工作原理就像一个跳板,简单的说,我是一个用户,我访问不了某网站,但是我能访问一个代理服务器这个代理服务器呢,他能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容代理服务器去取回来,然后返回给我

代理软件推荐: Cisco AnyConnect

反向代理

反向代理正好相反,反向代理隐藏了真实的服务端,客户端向反向代理服务器发送请求,反向代理服务器会帮我们把请求转发到真实的服务器那里去,再有反向代理服务器将结果转交给客户端.
比如我们拨打10086客服电话,可能一个地区的10086客服有几个或者几十个,你永远都不需要关心在电话那头的是哪一个,你关心的是你的问题能不能得到专业的解答,你只需要拨通了10086的总机号码,电话那头总会有人会回答你,只是有时慢有时快而已.那么这里的10086总机号码就是我们说的反向代理.客户不知道真正提供服务人的是谁.

代理软件推荐: Nginx(轻量级的Web服务器、反向代理服务器)

Nginx进程模式

Nginx支持Single模式Master + Worker模式.
Nginx通常工作在Master + Worker模式下, 启动后会有一个master进程和多个worker进程.

查看CPU总核数

1
2
[root@icloud-store ~]# cat /proc/cpuinfo | grep processor | wc -l
1

查看CPU个数

1
2
[root@icloud-store ~]# cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l
1

配置Work进程数

通过nginx.conf文件中worker_process设置.

1
2
[root@icloud-store ~]# cat /usr/local/nginx/conf/nginx.conf | grep worker_process
worker_processes 1;

建议设置为CPU核数,高并发场合可以考虑设置成核数*2

Master&Worker进程作用

Master进程作用

读取并验证配置文件nginx.conf; 管理worker进程;

Worker进程的作用

每一个Worker进程都维护一个线程(避免线程切换)处理连接和请求;Worker进程的个数由配置文件决定,一般和CPU个数相关(有利于进程切换),配置几个就有几个Worker进程.

Master进程主要用来管理worker进程,包含接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下)会自动重新启动新的worker进程.而基本的网络事件,则是放在worker进程中来处理了,多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的,一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求.

示例图:

Nginx热部署

热部署就是配置文件nginx.conf修改后,不需要停用Nginx,不需要中断请求,就能让配置文件生效.
Nginx热部署在修改配置文件nginx.conf后,重新生成新的worker进程,当然会以新的配置进行处理请求,而且新的请求必须都交给新的worker进程,至于老的worker进程,等把那些以前的请求处理完毕后,kill掉即可.

启停参数

  • -c:使用指定的配置文件而不是conf目录下的nginx.conf.
  • -t:测试配置文件是否有语法错误.
  • -s reload: 重载
  • -s stop: 停止
1
2
3
4
5
6
7
8
9
10
11
[root@icloud-store ~]# ps aux | grep nginx
root 86982 0.0 0.0 112664 972 pts/0 S+ 03:56 0:00 grep --color=auto nginx
root 125221 0.0 0.0 74808 1228 ? Ss 2017 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
root 125222 0.0 0.1 75580 2376 ? S 2017 0:00 nginx: worker process
[root@icloud-store ~]# vim /usr/local/nginx/conf/nginx.conf
[root@icloud-store ~]# service nginx reload
Reloading nginx configuration (via systemctl): [ OK ]
[root@icloud-store ~]# ps aux | grep nginx
root 15324 0.0 0.1 75624 2356 ? S 05:45 0:00 nginx: worker process
root 15345 0.0 0.0 112664 972 pts/0 R+ 05:46 0:00 grep --color=auto nginx
root 125221 0.0 0.1 75624 2532 ? Ss 2017 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

可以看到我们修改配置文件触发热部署,时master进程的id前后都是15221、而worker进程的id从125222变成了15324.

Nginx 负载均衡

轮询

轮询即Round Robin,根据Nginx配置文件中的顺序,依次把客户端的Web请求分发到不同的后端服务器.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http{
upstream sampleapp {
server 192.168.0.107:8080;
server 192.168.0.109:8080;
}
....
server{
listen 80;
...
server sampleapp;
location / {
proxy_pass http://sampleapp;
}
}

最少连接

Web请求会被转发到连接数最少的服务器上.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http{
upstream sampleapp {
least_conn;
server 192.168.0.107:8080;
server 192.168.0.109:8080;
}
....
server{
listen 80;
...
location / {
proxy_pass http://sampleapp;
}
}

IP地址哈希

前述的两种负载均衡方案中,同一客户端连续的Web请求可能会被分发到不同的后端服务器进行处理,因此如果涉及到会话Session,那么会话会比较复杂.常见的是基于数据库的会话持久化.要克服上面的难题,可以使用基于IP地址哈希的负载均衡方案.这样的话,同一客户端连续的Web请求都会被分发到同一服务器进行处理.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http{
upstream sampleapp {
ip_hash;
server 192.168.0.107:8080;
server 192.168.0.109:8080;
}
....
server{
listen 80;
...
location / {
proxy_pass http://sampleapp;
}
}

基于权重

基于权重的负载均衡即Weighted Load Balancing,这种方式下,我们可以配置Nginx把请求更多地分发到高配置的后端服务器上,把相对较少的请求分发到低配服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http{
upstream sampleapp {
server 192.168.0.107:8080 weight=2;
server 192.168.0.108:8080;
server 192.168.0.109:8080 weight=1 max_fails=2 fail_timeout=30s;
}
....
server{
listen 80;
...
location / {
proxy_pass http://sampleapp;
}
}

上面的例子在服务器地址和端口后weight=2的配置,这意味着,每接收到3个请求,前2个请求会被分发到第一个服务器,第3个请求会分发到第二个服务器,[权重越大命中越高]其它的配置同轮询配置.

Nginx事件模型

Nginx的worker进程个数与CPU绑定、worker进程内部包含一个线程高效回环处理请求, 这的确有助于效率,但这是不够的, 在高并发场景下,要同时处理那么多的请求, 要知道, 有的请求需要发生IO,可能需要很长时间, 如果等着它,就会拖慢worker的处理速度.

Nginx采用了Linux的epoll模型,epoll模型基于事件驱动机制,它可以监控多个事件是否准备完毕,如果OK,那么放入epoll队列中,这个过程是异步的.worker只需要从epoll队列循环处理即可.

相关文档 https://www.zhihu.com/question/22062795

事件模型介绍

Nginx的连接处理机制在不同的操作系统会采用不同的I/O模型

  • 在Linux下,Nginx使用epoll的I/O多路复用模型,

  • 在FreeBSD中使用kqueue的I/O多路复用模型,

  • 在solaris中使用/dev/poll方式的I/O多路复用模型,

  • 在Windows中使用的是icop.

时间模型配置

1
2
3
4
5
[root@icloud-store ~]# cat /usr/local/nginx/conf/nginx.conf  | grep epoll  -2
events {
use epoll;
worker_connections 1024;
}
  • use 是一个事件模块指令,用来指定Nginx的工作模式.

  • worker_connections定义每个进程(process)的最大连接数,这个连接包括了所有连接,如代理服务器连接、客户端的连接、实际的并发连接.

1
Nginx总并发连接 = worker * worker_connections

Nginx应用

根据特定IP来实现分流

将IP地址的最后一段最后一位为0或2或6的转发至www.y-zone.top来执行, 否则转发至www.y-zone2.top来执行.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
upstream www.y-zone.top {
server 192.168.1.100: 8080;
}

upstream www.y-zone2.top {
server 192.168.1.200: 8080;
}

server {
listen 80;
server_name www.y-zone.top;
location / {
if ($remote_addr~ * ^ (.*)\.(.*)\.(.*)\.*[026] $) {
proxy_pass http: //www.y-zone.top;
break;
}
proxy_pass http: //www.y-zone2.top;
}
}

将IP地址前3段为112.18.96.*转发至hi-linux-01.com来执行,否则转发至hi-linux-02.com来执行.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
upstream www.y-zone.top {
server 192.168.1.100: 8080;
}

upstream www.y-zone2.top {
server 192.168.1.200: 8080;
}

server {
listen 80;
server_name www.y-zone.top;
location / {
if ($remote_addr ~* ^(112)\.(18)\.(96)\.(.*)$) {
proxy_pass http: //www.y-zone.top;
break;
}
proxy_pass http: //www.y-zone2.top;
}
}

根据指定范围IP来实现分流

将IP地址的最后一段为1-100的转发至www.y-zone.top来执行,否则转发至www.y-zone2.top执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
upstream www.y-zone.top {
server 192.168.1.100: 8080;
}

upstream www.y-zone2.top {
server 192.168.1.200: 8080;
}

server {
listen 80;
server_name www.y-zone.top;
location / {
if ($remote_addr ~* ^(.*)\.(.*)\.(.*)\.[1, 100]$) {
proxy_pass http: //www.y-zone.top;
break;
}
proxy_pass http: //www.y-zone2.top;
}
}

根据forwarded地址分流

将IP地址的第1段为212开头的访问转发至www.y-zone.top来执行,否则转发至www.y-zone2.top执行.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server 192.168.1.100: 8080;
}

upstream www.y-zone2.top {
server 192.168.1.200: 8080;
}

server {

listen 80;
server_name www.y-zone.top;

location / {
if ($http_x_forwarded_for ~* ^(212)\.(.*)\.(.*)\.(.*)$) {
proxy_pass http: //www.y-zone.top;
break;
}
proxy_pass http: //www.y-zone2.top;
}

}

if指令的作用

if指令会就检查后面表达式的值是否为真(true)。如果为真则执行后面大括号中的内容;

以下是一些条件表达式的常用比较方法:

  1. 变量的完整比较可以使用=或!=操作符

  2. 部分匹配可以使用~或~*的正则表达式来表示

  3. ~表示区分大小写

  4. ~*表示不区分大小写(nginx与Nginx是一样的)

  5. !~与!~*是取反操作,也就是不匹配的意思

  6. 检查文件是否存在使用-f或!-f操作符

  7. 检查目录是否存在使用-d或!-d操作符

  8. 检查文件、目录或符号连接是否存在使用-e或!-e操作符

  9. 检查文件是否可执行使用-x或!-x操作符

  10. 正则表达式的部分匹配可以使用括号,匹配的部分在后面可以用$1~$9变量代替

Nginx 301跳转到带www域名

前提: 在域名解析中添加 domain.com 和 www.domain.com 指向你的主机IP地址.

方法一: 打开 nginx.conf 文件找到你的server配置段

1
2
3
4
5
server {
listen 80;
server_name www.domain.com domain.com;
if ($host != 'www.domain.com' ) { rewrite ^/(.*)$ http://www.domain.com/$1 permanent ;
}

方法二: 在配置文件里面写两个server,domain.com指向www.domain.com

1
2
3
4
5
6
7
8
9
server {
listen 80;
server_name www.domain.com;


server {
server_name domain.com;
rewrite ^(.*) http://www.domain.com/$1 permanent;
}

Nginx启用压缩

在nginx.conf文件的http模块新增以下内容

1
2
3
4
5
gzip             on;
gzip_min_length 10k; # 设置允许压缩的页面最小字节数
gzip_comp_level 6;
gzip_vary on;
gzip_types text/plain text/css application/javascript application/json application/xml text/xml image/png image/gif image/jpeg;

说明:如果不指定类型,Nginx仍然不会压缩

Nginx开启Http2

Nginx 调优配置

Nginx高可用

可以使用Keepalived+Nginx实现高可用, Keepalived是一个高可用解决方案,主要是用来防止服务器单点发生故障,可以通过和Nginx配合来实现Web服务的高可用.(其实Keepalived不仅仅可以和Nginx配合,还可以和很多其他服务配合)

Keepalived + Nginx实现高可用的思路:

  • 请求不要直接打到Nginx上,应该先通过Keepalived(这就是所谓虚拟IP,VIP)

  • Keepalived应该能监控Nginx的生命状态(提供一个用户自定义的脚本,定期检查Nginx进程状态,进行权重变化,从而实现Nginx故障切换)

Keepalived + Nginx高可用搭建

参考文档