介绍
Nginx 是开源、高性能、高可靠的HTTP服务器,也可作为反向代理服务器,邮件服务器,支持热部署,占用内存少、并发能力强、能支持高达 5w 个并发连接数,最重要的是Nginx 是免费的并可以商业化,配置使用也比较简单。支持FastCGI、SSL、Virtual Host、URL Rewrite、Gzip等功能。并且支持很多第三方的模块扩展。
Nginx常用功能
Nginx在做反向代理时,提供性能稳定,并且能够提供配置灵活的转发功能。Nginx可以根据不同的正则匹配,采取不同的转发策略,比如图片文件结尾的走文件服务器,动态页面走web服务器。并且Nginx对返回结果进行错误页跳转,异常判断等。如果被分发的服务器存在异常,他可以将请求重新转发给另外一台服务器,然后自动去除异常服务器。
正向代理和反向代理
反向代理(Reverse Proxy)对应的是正向代理(Forward Proxy),他们的区别:
正向代理: 内网服务器主动要去请求外网的地址或服务,所进行的一种行为。内网服务>代理服务器>外网
反向代理:外网要访问内网服务而进行的一种行为。 外网>代理服务器>内网服务
负载均衡
请求爆发式增长的情况下,单个机器性能再强劲也无法满足要求了,这个时候集群的概念产生了,单个服务器解决不了的问题,可以使用多个服务器,然后将请求分发到各个服务器上,将负载分发到不同的服务器,这就是负载均衡,核心是「分摊压力」。Nginx 实现负载均衡,一般来说指的是将请求转发给服务器集群。
动静分离
为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度,降低原来单个服务器的压力。
一般来说,都需要将动态资源和静态资源分开,由于 Nginx 的高并发和静态资源缓存等特性,经常将静态资源部署在 Nginx 上。如果请求的是静态资源,直接到静态资源目录获取资源,如果是动态资源的请求,则利用反向代理的原理,把请求转发给对应后台应用去处理,从而实现动静分离。
使用前后端分离后,可以很大程度提升静态资源的访问速度,即使动态服务不可用,静态资源的访问也不会受到影响。
Master-Worker模式
启动Nginx后,其实就是在80端口启动了Socket服务进行监听
[root@service nginx]# ps -ef|grep nginx |
Master进程:
读取并验证配置文件nginx.conf,管理worker进程。1024以下的端口只有root用户可以使用
Worker进程:
真正处理请求的进程,是以普通用户的身份进行运行的,这样就可以极大增加程序的安全性。就算是万一有一个进程被劫持,那也不会有管理员权限.注意Worker进程的个数由配置文件决定,一般和CPU个数相关(有利于进程切换),配置几个就有几个Worker进程。
热部署原理:
修改配置文件nginx.conf后,重新加载,master进程会进行语法错误的判断。如果存在语法错误的话,返回错误,不进行装载,如果配置文件没有语法错误,那么ngnix也不会将新的配置调整到所有worker中。而是,先不改变已经建立连接的worker,等待worker将所有请求结束之后,将原先在旧的配置下启动的worker杀死,然后使用新的配置创建新的worker。
配置
nginx 配置文件主要分成四部分:
main
(全局设置): 设置的指令影响其他所有部分的设置server
(主机设置):主要用于制定虚拟主机域名 IP 和端口号upstream
(上游服务器设置):设置一系列的后端服务器,设置反向代理及后端服务器的负载均衡location
(URL匹配特定位置后的设置):用于匹配网页位置(比如,根目录“/”,“/images”,等等)。
他们之间的关系:server 继承 main,location 继承 server;upstream 既不会继承指令也不会被继承。
配置文件的语法规则:
1.配置文件由指令与指令块构成; |
Nginx 的配置:
#定义Nginx运行的用户和用户组 |
server 块可以包含多个 location 块,location 指令用于匹配 uri,语法:
location [ = | ~ | ~* | ^~] uri { |
指令后面:
1.=
精确匹配路径,用于不含正则表达式的 uri 前,如果匹配成功,不再进行后续的查找;
2.^
用于不含正则表达式的 uri; 前,表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找;
3. 表示用该符号后面的正则去匹配路径,区分大小写;
4.~*
表示用该符号后面的正则去匹配路径,不区分大小写。跟 ~ 优先级都比较低,如有多个location的正则能匹配的话,则使用正则表达式最长的那个;
如果 uri 包含正则表达式,则必须要有 ~ 或 ~* 标志。
常用的全局变量
全局变量名 | 功能 |
---|---|
$host | 请求信息中的 Host,如果请求中没有 Host 行,则等于设置的服务器名,不包含端口 |
$request_method | 客户端请求类型,如 GET、POST |
$remote_addr | 客户端的 IP 地址 |
$args | 请求中的参数 |
$arg_PARAMETER | GET 请求中变量名 PARAMETER 参数的值,例如:$http_user_agent(Uaer-Agent 值), $http_referer… |
$content_length | 请求头中的 Content-length 字段 |
$http_user_agent | 客户端agent信息 |
$http_cookie | 客户端cookie信息 |
$remote_addr | 客户端的IP地址 |
$remote_port | 客户端的端口 |
$http_user_agent | 客户端agent信息 |
$server_protocol | 请求使用的协议,如 HTTP/1.0、HTTP/1.1 |
$server_addr | 服务器地址 |
$server_name | 服务器名称 |
$server_port | 服务器的端口号 |
$scheme | HTTP 方法(如http,https) |
配置正向代理
代理服务器:
server { |
linux客户端
一次代理,直接在shell执行: |
配置代理后,查看出口是否变为白名单ip
export http_proxy=http://192.168.10.117:8088 |
配置反向代理
server { |
可以将请求转发到另一个服务器上,也可以根据访问的路径跳转到不同端口的服务中。
比如我们监听 9001 端口,然后把访问不同路径的请求进行反向代理:
#把访问 http://127.0.0.1:9001/a 的请求转发到 http://127.0.0.1:8080 |
配置负载均衡
Nginx 提供了好几种分配方式,默认为轮询,就是轮流来。有以下几种分配方式:
1.轮询,默认方式,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务挂了,能自动剔除;
http { |
2.weight,权重分配,指定轮询几率,权重越高,在被访问的概率越大,用于后端服务器性能不均的情况;
http { |
3.ip_hash,对客户端请求的ip进行hash操作,然后根据hash结果将同一个客户端ip的请求分发给同一台服务器进行处理,可以解决session不共享的问题。
http { |
4.fair(第三方),按后端服务器的响应时间分配,响应时间短的优先分配,依赖第三方插件 nginx-upstream-fair,需要先安装;
http { |
5.backup,携带backup代表此server为备用,nginx只有在转发到主server出现问题,才会切换到backup的server
http { |
开启gzip
gzip 是一种常用的网页压缩技术,传输的网页经过 gzip 压缩之后大小通常可以变为原来的一半甚至更小(官网原话),更小的网页体积也就意味着带宽的节约和传输速度的提升,特别是对于访问量巨大大型网站来说,每一个静态资源体积的减小,都会带来可观的流量与带宽的节省。
使用 gzip 不仅需要 Nginx 配置,浏览器端也需要配合,需要在请求消息头中包含 Accept-Encoding: gzip(IE5 之后所有的浏览器都支持了,是现代浏览器的默认设置)。一般在请求 html 和 css 等静态资源的时候,支持的浏览器在 request 请求静态资源的时候,会加上 Accept-Encoding: gzip 这个 header,表示自己支持 gzip 的压缩方式,Nginx 在拿到这个请求的时候,如果有相应配置,就会返回经过 gzip 压缩过的文件给浏览器,并在 response 相应的时候加上 content-encoding: gzip 来告诉浏览器自己采用的压缩方式(因为浏览器在传给服务器的时候一般还告诉服务器自己支持好几种压缩方式),浏览器拿到压缩的文件后,根据自己的解压方式进行解析。
gzip on; |
配置 HTTPS
server { |
跨域 CORS 配置
使用反向代理解决跨域
在前端服务地址为 prod.nmk0718.com
的页面请求 api.nmk0718.com
的后端服务导致的跨域,可以这样配置:
server { |
这样前端调用prod.nmk0718.com的接口会被转发后api.nmk0718.com,前后端都是prod.nmk0718.com的情况下就不存在跨域了
配置 header 解决跨域
在请求的接口location中加入以下配置进行解决跨域
|
http请求转发到https
配置完 HTTPS 后,浏览器还是可以访问 HTTP 的地址的,可以做一个 301 跳转,把对应域名的 HTTP 请求重定向到 HTTPS 上
server { |
转发websocket
http { |
静态文件转发
#请求/web时访问的文件为/home/test/index.html |
静态文件缓存
由于图片、字体、音频、视频等静态文件在打包的时候通常会增加了 hash,所以缓存可以设置的长一点,先设置强制缓存,再设置协商缓存;如果存在没有 hash 值的静态文件,建议不设置强制缓存,仅通过协商缓存判断是否需要使用缓存
location ~ .*\.(css|js|jpg|png|gif|swf|woff|woff2|eot|svg|ttf|otf|mp3|m4a|aac|txt)$ { |
重定向
#转发 域名/api/后的任意字符 到 https://www.nmk0718.com/api/后面 |
操作命令
使用nginx -h 查看完整的nginx命令
[root@deployment nginx]# ./sbin/nginx -h |
proxy_pass中url末尾带/与不带/的区别
proxy_pass配置中url末尾带/时,nginx转发时,会将原uri去除location匹配表达式后的内容拼接在proxy_pass中url之后。
测试地址:http://192.168.171.129/test/tes.jsp |
proxy_pass配置中url末尾不带/时,如url中不包含path,则直接将原uri拼接在proxy_pass中url之后;如url中包含path,则将原uri去除location匹配表达式后的内容拼接在proxy_pass中的url之后。
测试地址:http://192.168.171.129/test/tes.jsp |
适配 PC 或移动设备
根据用户设备不同返回不同样式的站点,以前经常使用的是纯前端的自适应布局,但无论是复杂性和易用性上面还是不如分开编写的好,比如我们常见的淘宝、京东……这些大型网站就都没有采用自适应,而是用分开制作的方式,根据用户请求的 user-agent 来判断是返回 PC 还是 H5 站点。
使用$http_user_agent
全局变量来判断用户请求的 user-agent
,指向不同的 root 路径,返回对应站点。
server { |
泛域名转发
正则匹配
实现效果:把二级或者三级域名链接重写到我们希望的路径,让后端就可以根据路由解析不同的规则:
test1.nmk0718.com/api?name=a 自动转发到 127.0.0.1:8080/test1/api?name=a; |
通配符匹配
实现效果:国内机器想访问谷歌接口,在能访问到外网的机器内部署nginx转发该访问
在http层增加配置dns解析
http { |
在conf文件中配置google的泛域名转发
server { |
配置后,本地需要访问什么域名,就需要绑定一个host
#nginx机器ip google域名 |
访问http://www.google.com 和 http://mail.google.com 的接口都可转发
如需集群内使用,可配置k8s的coredns配合使用
server_name与host匹配优先级:
完全匹配
通配符在前的,如*.test.com
在后的,如www.test.*
正则匹配,如~^.www.test.com$
如果都不匹配
优先选择listen配置项后有default或default_server的
找到匹配listen端口的第一个server块
泛域名路径分离
这是一个非常实用的技能,经常有时候我们可能需要配置一些二级或者三级域名,希望通过 Nginx 自动指向对应目录,比如:
test1.nmk0718.com 自动指向 /usr/share/nginx/html/test1 服务器地址; |
1.为了使 Nginx 配置更易于维护,建议为每个服务创建一个单独的配置文件,存储在 /etc/nginx/conf/website 目录,根据需求可以创建任意多个独立的配置文件。
2.独立的配置文件,建议遵循以下命名约定 <服务>.conf,比如域名是www. nmk0718.com”,那么你的配置文件的应该是这样的./etc/nginx/conf/website/www. nmk0718.com.conf,如果部署多个服务,也可以在文件名中加上 Nginx 转发的端口号。
3.Nginx 日志相关目录,内以 域名.type.log 命名(比如www. nmk0718.com.access.log 和 www. nmk0718.com.error.log )位于 /var/log/nginx/ 目录中,为每个独立的服务配置不同的访问权限和错误日志文件,这样查找错误时,会更加方便快捷。
日志相关目录,内以 域名.type.log 命名(比如 www. nmk0718.com.access.log 和 www. nmk0718.com.error.log )位于 /var/log/nginx/ 目录中,为每个独立的服务配置不同的访问权限和错误日志文件,这样查找错误时,会更加方便快捷。
转发物理机:容器流量10:1
转发思路:user>master-nginx>upstream>slave-nginx或ingress
最后效果:用户访问域名,域名进入nginx的upstream 10次有1次进入ingress转发给容器,另外就此转发给slave-nginx,再转给物理机
master-nginx
#物理机双节点 |
slave-nginx
upstream nmk{ |
后端健康检查
nginx自带健康检查的缺陷:
- Nginx只有当有访问时后,才发起对后端节点探测。
- 如果本次请求中,节点正好出现故障,Nginx依然将请求转交给故障的节点,然后再转交给健康的节点处理。所以不会影响到这次请求的正常进行。但是会影响效率,因为多了一次转发
- 自带模块无法做到预警
- 被动健康检查
使用第三访模块nginx_upstream_check_module:
- 区别于nginx自带的非主动式的心跳检测,淘宝开发的tengine自带了一个提供主动式后端服务器心跳检测模块
- 若健康检查包类型为http,在开启健康检查功能后,nginx会根据设置的间隔向指定的后端服务器端口发送健康检查包,并根据期望的HTTP回复状态码来判断服务是否健康。
- 后端真实节点不可用,则请求不会转发到故障节点
- 故障节点恢复后,请求正常转发
主动地健康检查,nignx定时主动地去ping后端的服务列表,当发现某服务出现异常时,把该服务从健康列表中移除,当发现某服务恢复时,又能够将该服务加回健康列表中。淘宝有一个开源的实现nginx_upstream_check_module模块
github地址:https://github.com/yaoweibin/nginx_upstream_check_module |
安装nginx_upstream_check_module
安装扩展模块,需要编译安装的nginx,版本自己选择
获取安装包 |
服务治理的一个重要任务是感知服务节点变更,完成服务自动注册及异常节点的自动摘除。这就需要服务治理平台能够:及时
、准确
的感知service节点的健康状况。
Nginx 提供了三种HTTP服务健康检查方案供用户选择:
- TCP层默认检查方案:
定时与后端服务建立一条tcp连接
,链接建立成功则认为服务节点是健康的。 - HTTP层默认检查方案:
TCP层检查有一定的局限性:- 很多HTTP服务是带状态的,端口处于listen状态并不能代表服务已经完成预热;
- 不能真实反映服务内部处理逻辑是否产生拥堵。
- 这时可以选择
http层
健康检查,会向服务发送一个http请求GET / HTTP/1.0\r\n\r\n
,返回状态是2xx或3xx时认为后端服务正常。
- 自定义方案:(nginx_upstream_check_module模块)
可根据下文描述自定义检查方案。
指令
Syntax: check
interval=milliseconds [fall=count] [rise=count] [timeout=milliseconds] [default_down=true|false] [type=tcp|http|ssl_hello|mysql|ajp] [port=check_port]
Default: 如果没有配置参数,默认值是:interval=30000 fall=5 rise=2 timeout=1000 default_down=true type=tcp
Context:upstream
指令后面的参数意义是:
interval
:向后端发送的健康检查包的间隔。fall
(fall_count): 如果连续失败次数达到fall_count,服务器就被认为是down。rise
(rise_count): 如果连续成功次数达到rise_count,服务器就被认为是up。timeout
: 后端健康请求的超时时间。default_down
: 设定初始时服务器的状态,如果是true,就说明默认是down的,如果是false,就是up的。默认值是true,也就是一开始服务器认为是不可用,要等健康检查包达到一定成功次数以后才会被认为是健康的。type
:健康检查包的类型,现在支持以下多种类型tcp
:简单的tcp连接,如果连接成功,就说明后端正常。ssl_hello
:发送一个初始的SSL hello包并接受服务器的SSL hello包。http
:发送HTTP请求,通过后端的回复包的状态来判断后端是否存活。mysql
: 向mysql服务器连接,通过接收服务器的greeting包来判断后端是否存活。ajp
:向后端发送AJP协议的Cping包,通过接收Cpong包来判断后端是否存活。
port
: 指定后端服务器的检查端口。你可以指定不同于真实服务的后端服务器的端口,比如后端提供的是443端口的应用,你可以去检查80端口的状态来判断后端健康状况。默认是0,表示跟后端server提供真实服务的端口一样。该选项出现于Tengine-1.4.0。
Syntax: check_http_expect_alive
[ http_2xx | http_3xx | http_4xx | http_5xx ]
Default:http_2xx | http_3xx
Context:upstream
该指令指定HTTP回复的成功状态,默认认为2XX和3XX的状态是健康的。
Syntax: check_http_send
http_packet
Default:"GET / HTTP/1.0\r\n\r\n"
Context:upstream
该指令可以配置http健康检查包发送的请求内容。为了减少传输数据量,推荐采用"HEAD"
方法。
当采用长连接进行健康检查时,需在该指令中添加keep-alive请求头,如:"HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
。
同时,在采用"GET"
方法的情况下,请求uri的size不宜过大,确保可以在1个interval
内传输完成,否则会被健康检查模块视为后端服务器或网络异常。
完整参数配置:
http://tengine.taobao.org/document_cn/http_upstream_check_cn.html
官方示例:
http { |
使用demo:
upstream apiservice{ |
访问健康检测的页面
可看到服务为up,把服务下线后再次查看
服务为down,此时后端服务已下线
server number是后端服务器的数量 |
四层负载均衡
七层负载均衡:只识别域名,是http层。
四层负载均衡:不识别域名,是tcp层,类似于端口转发。
可用于ftp,sftp,database等端口的转发
查看当前模块
[root@service nginx]# ./sbin/nginx -V |
进入源码目录,重新编译
cd /usr/local/nginx-1.16.1 |
示例配置:
stream段的配置要与http段在同级
http { |
测试连接是否正常
nginx增加kafka模块
模块地址
https://github.com/brg-liuwei/ngx_kafka_module/tree/master |
下载源码
wget http://nginx.org/download/nginx-1.20.1.tar.gz |
配置编译使用的模块
./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_auth_request_module --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E' --with-compat --with-stream_ssl_preread_module --with-threads --add-dynamic-module=/root/ngx_kafka_module |
编译
make |
此处不进行install安装
进入编译的目录
cd objs |
拷贝so文件到原目录进行加载
cp *.so /usr/lib64/nginx/modules/ |
再次测试
the "ssl" directive is deprecated, use the "listen ... ssl" directive instead |
注释配置文件中的ssl on;同时在listen 443; 后面加上 ssl
listen 443 ssl; |
再次测试
version 1.20.1 of nginx.pm is required, but 1.12.2 was found |
find nginx.pm发现,这个perl文件,在make install的时候,也会安装,如果不指定安装目录,这个文件会默认安装到/usr/local/lib64/perl5/nginx.pm。
而nginx.pm里面记录了nginx的版本号。所以,如果启动nginx的时候,运行的nginx与nginx.pm版本号不一致就有问题
在测试的机器进行上述操作并进行install安装,把perl5下载到本服务器,把本地的目录进行备份,使用下载的perl5文件夹
再次测试
[root@idt01 objs]# nginx -t |
./configure: error: C compiler cc is not found
yum -y install gcc gcc-c++ autoconf automake make |
./configure: error: the invalid value in –with-ld-opt=”-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E”
yum -y install redhat-rpm-config.noarch |
./configure: error: the HTTP rewrite module requires the PCRE library.
yum -y install pcre-devel |
./configure: error: SSL modules require the OpenSSL library.
yum -y install openssl openssl-devel |
./configure: error: the HTTP XSLT module requires the libxml2/libxslt
yum -y install libxml2 libxml2-dev libxslt-devel |
./configure: error: the HTTP image filter module requires the GD library.
yum -y install gd-devel |
./configure: error: perl module ExtUtils::Embed is required
yum -y install perl-devel perl-ExtUtils-Embed |
./configure: error: the GeoIP module requires the GeoIP library.
yum -y install GeoIP GeoIP-devel GeoIP-data |
./configure: error: the Google perftools module requires the Google perftools
yum -y install gperftools |
[root@rancher modules]# nginx -t
nginx: [emerg] dlopen() “/usr/lib64/nginx/modules/ngx_http_kafka_module.so” failed (librdkafka.so.1: cannot open shared object file: No such file or directory) in /usr/share/nginx/modules/mod-kafka.conf:1
https://www.jianshu.com/p/635e8cde4cbc
参考文档:
https://blog.csdn.net/stormwolf/article/details/123371698
http://t.zoukankan.com/damon-blogs-p-14158831.html
为了使 Nginx 配置更易于维护,建议为每个服务创建一个单独的配置文件,存储在 /usr/local/nginx/website 目录,根据需求可以创建任意多个独立的配置文件。
独立的配置文件,建议遵循以下命名约定 <域名>.conf,比如域名是 nmk0718.com,那么你的配置文件的应该是这样的 /usr/local/nginx/website/www.nmk0718.com.conf,把location单独抽出放在/usr/local/nginx/include/www.nmk0718.com.conf中进行存储.再通过include进行引用
新增服务时,只需更改include中的配置文件机即可
[root@deployment nginx]# ll conf/website/ |
Nginx 日志相关目录,内以 域名.type.log 命名(比如www.nmk0718.com.access.log 和www.nmk0718.com.error.log )位于 /usr/local/nginx/log/ 目录中,为每个独立的服务配置不同的访问权限和错误日志文件,这样查找错误时,会更加方便快捷。
参考文档:
https://blog.csdn.net/Janson_Lin/article/details/105954705
https://www.cnblogs.com/cheyunhua/p/14011800.html
https://www.cnblogs.com/cuishuai/p/8073748.html
https://blog.csdn.net/zhanghui200920061988/article/details/105132167