初识 Nginx:Nginx 入门与实践

参考公众号文:感谢科普~

Nginx入门与实践

快速入门Nginx【正向反向代理,负载均衡的概念,学会Nginx的安装和常用命令,并在实际中去应用Nginx】

几乎所有的项目部署,都会用到 Nginx。Nginx 重点:配置 nginx.conf 文件。

大部分公司的线上项目部署主要用到 Nginx 的功能有如下:

  • 正向、反向代理

  • 过滤 IP

  • 负载均衡

Nginx官网:https://nginx.org/

1. Nginx 是什么

Nginx 是一个高性能的 HTTP 和反向代理服务器,是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,支持热部署,几乎可以做到 7 * 24 小时不间断运行,即使运行几个月也不需要重新启动,还能在不间断服务的情况下对软件版本进行热更新。

Nginx 的特点/优势:占用内存少、并发能力强、能支持高达 5w 个并发连接数。

所以 Nginx 一般被用来当做服务器的第一道门,其应用场景有:

  • 正向、反向代理

  • 过滤 IP,白名单

  • 负载均衡

  • 静态资源服务

2. 基础概念

2.1. 正向代理和反向代理

正向代理 是一个位于客户端和原始服务器之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定原始服务器,然后代理向原始服务器转交请求并将获得的内容返回给客户端。

  • 代理服务器和客户端处于同一个局域网内。

反向代理 实际运行方式是代理服务器接受网络上的连接请求。它将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给网络上请求连接的客户端 。

反向代理客户端无法感知代理,因为客户端访问网络不需要配置,只要把请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据,然后再返回到客户端。此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器 IP 地址。一般在处理跨域请求的时候比较常用。

  • 代理服务器和原始服务器处于同一个局域网内。

2.2. 负载均衡

单个机器性能有限,无法承受巨大的请求压力 =》 产生集群的概念:我们可以增加服务器的数量,构建集群,将请求分发到各个服务器上(每台服务器的代码都是一样的),将原来请求集中到单个服务器的情况改为负载分发到多个不同服务器,这就是 负载均衡 ,核心是「分摊压力」。

如何分发压力?=》 Nginx 也可以配置规则,比如说权重、轮询、hash 等等。

2.3. 动静分离

动静分离 =》加快网站的访问速度。像大图片、视频、CSS 这种静态资源,如果都放在同一个服务器,在请求的时候就会造成带宽压力,如果把这些静态资源分散到不同的服务器,配合 CDN,就可以减少服务器的压力。

=》由于 Nginx 的高并发和静态资源缓存等特性,经常将静态资源部署在 Nginx 上

  • 如果请求的是静态资源,直接到静态资源目录获取资源;

  • 如果是动态资源的请求,则利用 反向代理 的原理,把请求转发给对应后台应用去处理,从而实现动静分离。

3. Nginx 常用命令总结

nginx -v										# 查看nginx版本(或nginx -V)
start nginx										# Windows 启动nginx
nginx											# Linux 启动nginx服务
nginx -s stop									# 停止nginx/关闭nginx服务 =》 立即停止 Nginx 进程 立即关闭所有连接,正在处理的请求会被中断,可能导致部分请求失败
nginx -s quit									# 停止nginx/关闭nginx服务 =》 优雅地停止 Nginx 进程 等待当前正在处理的请求完成后再停止,确保没有请求被中断
nginx -s reload									# 重启nginx => 无需停止服务,因此可以在不中断正在处理的请求的情况下更新配置,一般可以实现无缝更新
nginx -t										# 测试配置是否有语法错误(或nginx -T)
nginx -h										# 帮助命令
ps aux | grep nginx								# 查看进程

4. *Nginx 配置文件

Nginx 典型配置:

#-----------全局块 START-----------
user  nobody;                        						# 运行用户,默认即是nginx,可以不进行设置
worker_processes  1;                						# Nginx 进程数,一般设置为和 CPU 核数一样
worker_processes auto;                						# Nginx 进程数 与当前 CPU 物理核心数一致
error_log  /var/log/nginx/error.log warn;   				# Nginx 的错误日志存放目录,日志级别是warn
pid        /var/run/nginx.pid;      						# Nginx 服务启动时的 pid 存放位置
worker_rlimit_nofile 20480; 								# 可以理解成每个 worker 子进程的最大连接数量。
#-----------全局块 END-----------
# --------------------------------------------------------------------------------
# events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接
# --------------------------------------------------------------------------------
#-----------events块 START-----------
events {
  accept_mutex on;   										# 设置网路连接序列化,防止惊群现象发生,默认为on
  multi_accept on;  										# 设置一个进程是否同时接受多个网络连接,默认为off
  # 事件驱动模型有 select|poll|kqueue|epoll|resig|/dev/poll|eventport
  use epoll;   												# 使用epoll的I/O模型,建议使用默认
  worker_connections 1024;   								# 每个进程允许最大并发数
}
#-----------events块 END-----------
# --------------------------------------------------------------------------------
# 配置使用最频繁的部分,代理、缓存、日志定义等绝大多数功能和第三方模块的配置都在这里设置
# --------------------------------------------------------------------------------
http {   
  # 设置日志自定义格式
  log_format  myFormat  '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
  access_log  /var/log/nginx/access.log  myFormat;   		# Nginx访问日志存放位置,并采用上面定义好的格式
  sendfile            on;   								# 开启高效传输模式
  tcp_nopush          on;   								# 减少网络报文段的数量
  tcp_nodelay         on;															
  keepalive_timeout   65;   								# 保持连接的时间,也叫超时时间,单位秒
  types_hash_max_size 2048;
  include             /etc/nginx/mime.types;      			# 文件扩展名与类型映射表
  default_type        application/octet-stream;   			# 默认文件类型
  include /etc/nginx/conf.d/*.conf;   						# 使用include引入其他子配置项,不存在会报错 */
  server {
    keepalive_requests 120; 								# 单连接请求上限次数。
    listen       80;       									# 配置监听的端口
    server_name  localhost 127.0.0.1 baimuxym.cn;    		# 配置监听的域名或者地址,可多个,用空格隔开
    location / {
    		root   /usr/share/nginx/html;  					# 网站根目录
    		index  index.html index.htm;   					# 默认首页文件
    		deny 172.18.5.54   						 		# 禁止访问的ip地址,可以为all
    		allow 172.18.5.53;						 		# 允许访问的ip地址,可以为all
		}
    # 图片防盗链
    location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
    		valid_referers none blocked 192.168.0.2;  		# 只允许本机 IP 外链引用
    		if ($invalid_referer){
    			return 403;
			}
		}
    # 新增内容,可以在自己的server单独配置错误日志
    error_log    logs/error.log    error;					#  error_log  <FILE>  <LEVEL>; 关键字 <日志文件> <错误日志>
    error_page 500 502 503 504 /50x.html;  					# 默认50x对应的访问页面
    error_page 400 404 error.html;   						# 默认40x对应的访问页面
	}
}

4.1. location 配置

server 块可以包含多个 location 块,location 指令用于匹配 uri,location 语法如下:

location [ = | ~ | ~* | ^~ ]  /uri/  {
  ...
}
  • = 开头表示精确匹配,如果匹配成功,不再进行后续的查找;

  • ^ 以 xxx 开头的匹配

  • $ 以 xxx 结尾的匹配

  • * 代表任意字符

  • ^~ 匹配开头以 xxx 的路径,理解为匹配 url 路径即可。nginx 不对 url 做编码,因此请求为 /static/20%/HaC,可以被规则 ^~ /static/ /HaC 匹配到(注意是空格)

  • ~ 开头表示区分大小写的正则匹配

  • ~* 开头表示不区分大小写的正则匹配

  • ! 表示不包含 xxx 就匹配

  • / 通用匹配,任何请求都会匹配到。

~*~ 优先级都比较低,如有多个 location 的正则能匹配的话,则使用正则表达式最长的那个;

如果 uri 包含正则表达式,则必须要有 ~~* 标志。

示例:

#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
#这里是直接转发给后端应用服务器了,也可以是一个静态首页
# 第一个必选规则
location = / {
    #反向代理
    proxy_pass http://127.0.0.1:8080/index
}
# 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {                              //以xx开头
    root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {     //以xx结尾
    root /webroot/res/;
}
#第三个规则就是通用规则,用来转发动态请求到后端应用服务器
#非静态文件请求就默认是动态请求,自己根据实际把握
location / {
    proxy_pass http://tomcat:8080/
}

5. 负载均衡与限流

5.1. 负载均衡

在头部使用 upstream 即可使用负载均衡,Nginx 默认提供的负载均衡策略:

⒈轮询(默认)round_robin:每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。

⒉IP 哈希 ip_hash:每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 共享的问题。当然,实际场景下,一般不考虑使用 ip_hash 解决 session 共享。

  • 还有相似的 url_hash,通过请求 url 进行 hash,再通过 hash 值选择后端 server

⒊最少连接 least_conn:下一个请求将被分派到活动连接数量最少的服务器

⒋权重 weight:weight 的值越大分配到的访问概率越高,主要用于后端每台服务器性能不均衡的情况下,达到合理的资源利用率。

⒌fair(第三方),按后端服务器的响应时间分配,响应时间短的优先分配,依赖第三方插件 nginx-upstream-fair,需要先安装;

负载均衡示例如下:

#----------------------------------------------------------
# 使用 weight 负载均衡策略分发请求到不同的服务
#----------------------------------------------------------
	upstream mysite { 
    	# ip_hash 方式
    	# weight权重分配方式,表示 1:1
        server 127.0.0.1:8090 weight=1; 
        server 127.0.0.1:8091 weight=1;
    }
    server {
        listen       80;
        server_name  hellocoder.com ;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        location / {
         		proxy_pass http://mysite;
        }
    }
#----------------------------------------------------------
# 使用 IP、URL hash 策略
#----------------------------------------------------------
 	upstream mysite { 
    	# ip_hash 策略
    	# ip_hash;
    	# url_hash 策略
    	 hash $request_uri;
        server 127.0.0.1:8090;
        server 127.0.0.1:8091;
    }
在 upstream 内可使用的指令:
- server 定义上游服务器地址;
- zone 定义共享内存,用于跨 worker 子进程;
- keepalive 对上游服务启用长连接;
- keepalive_requests 一个长连接最多请求 HTTP 的个数;
- keepalive_timeout 空闲情形下,一个长连接的超时时长;
- hash 哈希负载均衡算法;
- ip_hash 依据 IP 进行哈希计算的负载均衡算法;
- least_conn 最少连接数负载均衡算法;
- least_time 最短响应时间负载均衡算法;
- random 随机负载均衡算法;

5.2. 限流

ngx_http_limit_req_module 模块提供了漏桶算法 (leaky bucket),可以限制单个 IP 的请求处理频率。

#------------------------------------------------------------------------------------------------
# key: 定义需要限流的对象。
# zone: 定义共享内存区来存储访问信息。
# rate: 用于设置最大访问速率, IP 访问频率。=> rate=5r/s 表示每秒只能处理每个 IP 地址的 5 个请求。
# Nginx 限流是按照毫秒级为单位的,也就是说 1 秒处理 5 个请求会变成每 200ms 只处理一个请求。
# 如果 200ms 内已经处理完 1 个请求,但是还是有有新的请求到达,这时候 Nginx 就会拒绝处理该请求。
#------------------------------------------------------------------------------------------------
# 基于客户端 192.168.1.1 进行限流,定义了一个大小为 10M,名称为 myLimit 的内存区,用于存储 IP 地址访问信息。
http {
    limit_req_zone 192.168.1.1 zone=myLimit:10m rate=5r/s;
}
server {
    location / {
        limit_req zone=myLimit;
        rewrite / http://www.hac.cn permanent;
    }
}

6. Nginx 代理

6.1. 正向代理

比如:我上传了一个静态网站在某个服务器目录,假如我的服务器是 81.71.16.134,那要如何通过我的域名 https://learnjava.baimuxym.cn 访问它呢?

步骤如下:

  1. 首先需要把域名解析到我的 IP

  2. 申请 SSL 证书,配置服务器

  3. 正向代理,监听 443 端口(因为 https 的端口是 443),转发;监听 80 端口,http:// 强制 跳到 https://

  	server {
       	listen       80; 												# 监听端口
       	server_name  learnjava.baimuxym.cn; 							# 请求域名
       	return      301 https://$host$request_uri; 						# 重定向至https访问。
    }
    server {
    		listen 443 ssl; 
    		server_name learnjava.baimuxym.cn; 							# 改为绑定证书的域名
    		ssl on;
    		ssl_certificate /usr/local/nginx/learnjava.baimuxym.cn/1_learnjava.baimuxym.cn_bundle.crt; 	# 改为自己申请得到的 crt 文件的名称或者 pem文件的名称
    		ssl_certificate_key /usr/local/nginx/learnjava.baimuxym.cn/2_learnjava.baimuxym.cn.key; 	# 改为自己申请得到的 key 文件的名称
    		ssl_session_timeout 5m;
    		ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    		ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    		ssl_prefer_server_ciphers on;
    		location / { 													# 匹配所有
    				root  /var/www/web/LearnJavaToFindAJob/docs; 			# 你的静态网站项目路径,刚刚上传的目录
    				index index.html;     									# 首页名称
        }
    }

6.2. 反向代理

反向代理 location不同:

location / {
  proxy_http_version 1.1; 											# 代理使用的http协议																				
  proxy_set_header Host $host; 										# header添加请求host信息
  proxy_set_header X-Real-IP $remote_addr; 							# header增加请求来源IP信息
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 		# 增加代理记录
  proxy_pass http://127.0.0.1:8888;
}

只需要简单使用 proxy_pass 就可以反向代理,可用于跳转到 Tomcat 的服务地址、springbooot 项目的服务地址。