nginx技术总结
Nginx技术总结
1,概述
Nginx 是由俄罗斯人 Igor Sysoev 设计开发的,开发工作从2002 年开始,第一次公开发布在 2004 年 10 月 4 日。
官方网站为:http://nginx.org/ 。它是一款免费开源的高性能 HTTP 代理服务器及反向代理服务器(Reverse Proxy)产品,同时它还可以提供 IMAP/POP3 邮件代理服务等功能。它高并发性能很好,官方测试能够支撑 5 万的并发量;运行时内存和 CPU 占用率低,配置简单,容易上手,而且运行非常稳定。
2,功能
- http服务器
- 反向代理
- 负载均衡
3,部署与命令
我这边使用的是docker容器化启动
# 先启动一个容器用于下载相关配置文件,方便后续修改
docker run --name ac-nginx -p 8080:8080 -p 16666:80 -d nginx
# 复制文档
docker cp -a ac-nginx:/etc/nginx/ /opt/docker/nginx/conf/
docker cp ac-nginx:/usr/share/nginx/html /opt/docker/nginx/
# 删除老容器
docker rm -f ac-nginx
# 容器启动 设置host网络模式,与宿主机的网络保持一致,方便后续监听容器外部的宿主端口
docker run --network host --name ac-nginx \
-v /opt/docker/nginx/conf/nginx:/etc/nginx \
-v /opt/docker/nginx/html:/usr/share/nginx/html \
-v /opt/docker/nginx/log:/var/log/nginx \
–restart=always \
-d nginx
# 查看日志
docker logs -f --tail 1000 ac-nginx
# 命令(因为使用的是docker所以它这边的命令与docker一致)
docker restart ac-nginx # 重启
docker stop ac-nginx # 关闭
docker start ac-nginx #启动
样例地址: http://47.98.35.29/
4,配置
4.1,全局块
从配置文件开始到 events 块之间的内容,主要会设置一些影响nginx 服务器整体运行的配置指令,主要包括配置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以及配置文件的引入等。
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
worker_processes,工作进程数
- 1.默认:worker_processes: 1
- 2.调大:worker_processes: CPU核心数,(双核4线程,可以设置为4)
4.2,events 块
events {
worker_connections 1024;
}
worker_connections,单个工作进程可以允许同时建立外部连接的数量,数字越大,能同时处理的连接越多
- 1.默认:worker_connections: 1024
- 2.调大:worker_connections: 100000,(调大到10万连接)
配置解析:
- connections不是随便设置的,而是与两个指标有重要关联,一是内存,二是操作系统级别的“进程最大可打开文件数”。
- 内存:每个连接数分别对应一个read_event、一个write_event事件,一个连接数大概占用232字节,2个事件总占用96字节,那么一个连接总共占用328字节,通过数学公式可以算出100000个连接数大概会占用 31M = 100000 * 328 / 1024 / 1024,当然这只是nginx启动时,connections连接数所占用的nginx。
- 进程最大可打开文件数:进程最大可打开文件数受限于操作系统,可通过 ulimit -n 命令查询,以前是1024,现在是65535,
- nginx提供了worker_rlimit_nofile指令,这是除了ulimit的一种设置可用的描述符的方式。 该指令与使用ulimit对用户的设置是同样的效果。此指令的值将覆盖ulimit的值,如:worker_rlimit_nofile 20960;
备注:在项目中有遇到过相关的问题,今年过年期间公司在浙江的某个地级市的健康码服务调用并发量达到瓶颈,公司临时组织大佬们出力出策,临时提高并发性能(不增加机器的前提下),经过一大波缓存、代码逻辑、反参精简等优化后,并发量虽然提高近一些,但是还是没有达到预期的性能提高程度,当时想的是肯定有什么服务出现了瓶颈!
当时我刚好年前通过jmeter测试过相关组件的接口性能,发现了这样的一个问题,直接访问组件端口的服务并发量要远远大于通过nginx反向代理的服务!通过nginx转发1000并发异常率基本都是48%左右,直接调用组件端口异常率为0%
最后是修改worker_connections参数直接改为了65535,并发量就突破瓶颈达到预期了!
4.3,http 块
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream acfileserver{
server 127.0.0.1:11001 weight=1;
}
server {
listen 80; # 直接访问ip,其实访问的就是ip:80
server_name localhost;
location / {
root html;
index index.html index.htm; # 设置主页
}
error_page 500 502 503 504 /50x.html; # 错误页
location = /50x.html {
root html;
}
}
include /etc/nginx/conf.d/*.conf; # 包含/etc/nginx/conf.d目录下正则匹配到的子配置项
}
4.3.1,http全局块
http全局块配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。
4.3.2,server 块
这块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的,该技术的产生是为了节省互联网服务器硬件成本。后面会详细介绍虚拟主机的概念。
每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机。
而每个 server 块也分为全局 server 块,以及可以同时包含多个 locaton 块。
1、全局 server 块
最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或IP配置。
2、location 块
一个 server 块可以配置多个 location 块。
这块的主要作用是基于 Nginx 服务器接收到的请求字符串(例如 server_name/uri-string),对虚拟主机名称(也可以是IP别名)之外的字符串(例如 前面的 /uri-string)进行匹配,对特定的请求进行处理。地址定向、数据缓存和应答控制等功能,还有许多第三方模块的配置也在这里进行。
4.3.3,upstream块
upstream acfileserver{
server 127.0.0.1:11001 weight=1;
}
主要用于后续的负载配置,详情见后文
4.4,子级配置文件
其本质就是4.3.2~3的配置可以放在外部的其他文件,配置一样
样例:
upstream acfileserver{
server 127.0.0.1:11001 weight=1;
}
server {
listen 8099;
server_name localhost;
client_max_body_size 4096m;
proxy_send_timeout 600;
proxy_read_timeout 600;
proxy_connect_timeout 600;
location /acfileserver{ # 代理后端
proxy_set_header Host $host:8099;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cookie_path /acfileserver /acfileserver;
proxy_set_header Cookies $http_cookies;
proxy_buffer_size 128k;
proxy_buffers 8 128k;
proxy_busy_buffers_size 128k;
proxy_pass http://acfileserver/acfileserver;
}
location /static/{
alias /usr/share/nginx/html/; # 设置静态文件路径
index hello.html hello.html; # 设置首页
}
}
5,功能与配置
5.1,负载均衡
nginx的负载均衡策略有5种:
轮询、、权重、ip_hash、least_conn 、请求头(基于域名、开发语言、浏览器、源ip)
5.1.1,轮询(默认)
最基本的配置方法,它是upstream的默认策略,每个请求会按时间顺序逐一分配到不同的后端服务器。
参数 | 描述 |
---|---|
fail_timeout | 与max_fails结合使用 |
max_fails | 设置在fail_timeout参数设置的时间内最大失败次数,如果在这个时间内,所有针对该服务器的请求都失败了,那么认为该服务器会被认为是停机了 |
fail_time | 服务器会被认为停机的时间长度,默认为10s。 |
backup | 标记该服务器为备用服务器。当主服务器停止时,请求会被发送到它这里。 |
down | 标记服务器永久停机了。 |
- 在轮询中,如果服务器down掉了,会自动剔除该服务器。
- 缺省配置就是轮询策略。
- 此策略适合服务器配置相当,无状态且短平快的服务使用。
5.1.2,权重
在轮询策略的基础上制定沦陷的几率。例如
# 这边会按照权重将请求转发到具体的服务器,优先转发至127.5.7.1服务器
upstream acfileserver{
server 127.5.7.1:11001 weight=10;
server 127.5.7.2:11001 weight=1;
server 127.5.7.3:11001 weight=1;
}
这里例子中,weight参数用于制定轮询的几率,weight默认值为1;weight的数值和被访问的几率成正比。
- 权重越高分配到需要处理的请求越多。
- 此策略可以与least_conn和ip_hash结合使用。
- 此策略比较适合服务器的硬件配置差别比较大的情况。
5.1.3,ip_hash
ip_hash负载均衡器按照客户端IP地址的分配方式,可以确保相同客户端的请求一直发送到相同的服务器。这样每个访客都固定访问一个后端服务器。
upstream acfileserver {
ip_hash;
server 127.5.7.1:11001 weight=10;
server 127.5.7.2:11001 weight=1;
server 127.5.7.3:11001 weight=1;
server 127.5.7.3:11001 max_fails=3 fail_timeout=20s;
}
- 在nginx版本1.3.1之前,不能在ip_hash中使用权重(weight)。
- ip_hash不能与backup同时使用。
- 此策略适合有状态服务,比如session。
- 当有服务器需要剔除,必须手动down掉。
5.1.4,least_conn
least_conn 最小连接,把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果
upstream acfileserver {
least_conn;
server 127.5.7.1:11001 weight=10;
server 127.5.7.2:11001 weight=1;
server 127.5.7.3:11001 weight=1;
server 127.5.7.3:11001 max_fails=3 fail_timeout=20s;
}
- 此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。
5.1.5,基于请求头
下面的几种都是根据请求头中的信息来进行分发的策略
- 基于域名
http {
upstream web1 { # 名为web1的反向代理群组
server 192.168.31.42;
server 192.168.31.52;
}
upstream web2 { # 名为web2的反向代理群组
server 192.168.31.43;
server 192.168.31.53;
}
server { # web1虚拟主机
listen 80;
server_name www.web1.com; # 基于域名分发必须有域名
location / {
proxy_pass http://web1;
}
}
server { # web2虚拟主机
listen 80;
server_name www.web2.com; # 基于域名分发必须有域名
location / {
proxy_pass http://web2;
}
}
}
- 基于开发语言
# 192.168.31.40分发器上nginx配置
http {
upstream php {
server 192.168.31.42;
}
upstream html {
server 192.168.31.43;
}
server {
location ~* \.php$ { # 以php结尾的
proxy_pass http://php;
}
location ~* \.html$ { # 以html结尾的
proxy_pass http://html;
}
}
}
- 基于浏览器
upstream elinks { server 192.168.31.42; }
upstream chrome { server 192.168.31.43; }
upstream any { server 192.168.31.42:81; }
server {
listen 80;
server_name www.web1.com;
location / {
proxy_pass http://any;
if ( $http_user_agent ~* Elinks ) {
proxy_pass http://elinks;
}
if ( $http_user_agent ~* chrome ) {
proxy_pass http://chrome;
}
}
}
- 基于源ip,在什么地方登陆则获取哪个地方的数据(就近原则获取服务资源)
upstream bj.server {
server 192.168.31.42; # web01
}
upstream sh.server {
server 192.168.31.43; # web02
}
upstream default.server {
server 192.168.31.42:81; # web03
}
geo $geo { # IP库
default default;
192.168.31.241/32 bj; # 北京
192.168.31.242/32 sh; # 上海
}
server {
listen 80;
server_name www.web1.com;
location / {
proxy_pass http://$geo.server$request_uri;
}
}
5.2,HTTP服务器
Nginx是一个HTTP服务器,可以将服务器上的静态文件(如HTML、图片)通过HTTP协议展现给客户端。
hello.html上传至指定目录(/usr/share/nginx/html/)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>hello world</title>
</head>
<body>
这是一个欢迎页!
</body>
</html>
添加静态访问信息
server {
listen 8099;
server_name hello;
client_max_body_size 4096m;
proxy_send_timeout 600;
proxy_read_timeout 600;
proxy_connect_timeout 600;
location /static/{
alias /usr/share/nginx/html/;
index hello.html hello.html;# 配置了一个默认首页
}
}
样例:
静态网页 http://47.98.35.29:8099/static/
图片 http://47.98.35.29:8099/static/哈儿的移动城堡.jpg
5.3,反向代理
5.3.1,代理
我们需要对外沟通某个服务,由于各种原因(网络隔离、或者协议复杂等等原因),不想直接对接这些服务,由此出现了网络的代理需求。
5.3.2,正向&反向代理
正向代理:客户端想访问某个服务器A,但是没有办法直接连接,由于将客户端代理给另外一台服务器B,由服务器B去访问服务器A,获取到服务器A的资源后在返回给客户端。给我的感觉有点像是之前春运的黄牛票贩子,他们代替你去给你买票,为你(客户端)服务。服务端无感知
反向代理:客户端像访问服务A,但是服务A之前的域名或者地址、或者机器更换了!服务A的公司为了不在这个期间丢失用户,它专门起了一个代理服务器B,将客户端来的请求转发到新的环境上去。有点像保险公司请了销售团队来保障服务A的业绩,为(服务端)服务。客户端无感知
客户端反向代理样例:
# acfileserver.conf
# 直接放置于容器中的/etc/nginx/conf.d目录下会自动生效(类推于宿主机)
# 负载均衡 weight 是权重值
upstream acfileserver{
server 127.0.0.1:11001 weight=1;
}
server {
listen 8099;
server_name localhost;
client_max_body_size 4096m;
proxy_send_timeout 600;
proxy_read_timeout 600;
proxy_connect_timeout 600;
location /acfileserver{
proxy_set_header Host $host:8099;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cookie_path /acfileserver /acfileserver;
proxy_set_header Cookies $http_cookies;
proxy_buffer_size 128k;
proxy_buffers 8 128k;
proxy_busy_buffers_size 128k;
proxy_pass http://acfileserver/acfileserver;
}
}
样例地址:
真实地址 http://47.98.35.29:11001/acfileserver/swagger-ui.html
代理地址 http://47.98.35.29:8099/acfileserver/swagger-ui.html#/
参考链接:
盲点知识(2022.03.09):
- epoll、poll、kqueue