书名
《Complete-NGINX-Cookbook-2019》
简介
- 作者:Derek DeJonghe
- 内容:面向实战的书,通过一个个问题,用提问回答的形式,来介绍nginx的应用、功能、配置。原书以抛出问题,提出解决方案和归纳总结的行文方式,讲解如何配置缓存,负载均衡,安全配置,WAF,云服务器部署和其它 NGINX 的重要特性。
章节(共16章,前4章)
1.基础介绍
2.高性能负载均衡
3.流量管理
4.大规模可扩展的内容缓存
一、基础介绍
要使用nginx,首先要进行安装,书中介绍的是yum自动安装的办法,以centos为例,如下:
- 创建文件:/etc/yum.repos.d/nginx.repo ,内容为:
[nginx]
name=nginx repo
baseurl= http:// nginx.org/packages/main line/OS/OSRELEASE/ $basearch/
gpgcheck=0
enabled=1
2.配置好上述文件内容之后,运行如下命令:
yum -y install nginx
systemctl enable nginx
systemctl start nginx
firewall-cmd --permanent --zone=public --add-port=80/tcp
firewall-cmd --reload
上面创建的文件,是给yum的包管理器提供官方的源码地址,接下来的命令通过yum安装了nginx,设置开机启动,并启动nginx,然后通过firewall防火墙命令开放80端口给tcp协议,最后的命令重启防火墙来提交改变。
安装好之后,可以检查一下安装状态
nginx -v
nginx version: nginx/1.15.3
检查运行状态
$ ps -ef | grep nginx
root 1738 1 0 19:54 ? 00:00:00 nginx: master process
nginx 1739 1738 0 19:54 ? 00:00:00 nginx: worker process
检查代理状态
$curl localhost
如果代理正常,我们会看到nginx的默认欢迎界面。
nginx提供了一组简洁的命令来进行基础控制,如下:
nginx -h 帮助菜单
nginx -v nginx版本信息
nginx -V 注意是大写的V,这个会返回版本信息、构建信息以及配置信息
nginx -t 测试、校验配置信息是否准确
nging -T 注意是大写的T,这个在测试、校验配置信息之后,不会简单的返回正确或错误,同时会将校验后的配置信息输出在屏幕上,方便查找错误。
nginx -s signal 发送信号给nginx主线程。signal有stop,quit,reload和reopen。stop命令会立即终止nginx进程。quit命令会在nginx处理完活跃请求之后结束nginx进程。reload会重新加载配置信息。reopen会重新打开日志文件。
作为静态资源服务
server {
listen 80 default_server;
server_name www.example.com;
location / {
root /usr/share/nginx/html;
# alias /usr/share/nginx/html;
index index.html index.htm;
}
}
server 定义了一个新的服务监听块。告诉nginx监听80端口,并指定此服务为80端口默认服务。server_name指定了要被代理到此服务的请求域名。如果没有default_server这个定义,那么nginx只会将匹配http://www.example.com的请求代理到此服务。
下面的location定义了基于url的代理策略。“/”代表代理所有请求,root告诉nginx去什么位置寻找静态资源文件。请求中的URI会附件在root定义的路径之后,来进行资源的定位。
热加载
nginx -s reload
这个命令可以在不停止nginx服务的情况下优雅的重新加载配置文件,且可保证不丢失任何信息包。
这极大的保证了系统运维的灵活性,可以让我们在不影响用户体验的情况下,进行一些代理机制的调整。
二、高性能负载均衡
如今,所有的软件产品都对用户体验提出了更高的要求。快速的响应时间是第一位的,为了实现这个目的,产品的服务端往往会横向扩展多个相同的服务,这就需要进行不同服务的协调,即负载均衡。
nginx作为负载均衡的载体,不仅仅能实现http层的负载,同时还能实现TCP、UDP等不同协议层的负载,这意味着我们可以将nginx用在不同的服务场景中,非常的灵活和强大。
HTTP负载
upstream backend{
server 192.168.1.1:80 weight=1;
server www.baidu.com weight=2;
}
server{
location / {
proxy_pass http://backend;
}
}
TCP负载
stream{
upstream mysql_read{
server read1.example.com:3306 weight=1;
server read2.example.com:3306 weight=2;
server 10.10.12.34:3306 backup;
}
server{
listen 3306;
proxy_pass mysql_read;
}
}
UDP
stream{
upstream ntp{
server ntp1.example.com:123 weight=1;
server ntp2.example.com:123 weight=2;
}
server{
listen 123 udp;
proxy_pass ntp;
}
}
如果要进行负载平衡的服务需要多个数据包在客户机和服务器之间来回发送,可以指定重用端口参数。这类服务的例子有OpenVPN、互联网语音协议(VoIP)、虚拟桌面解决方案和数据报传输层安全(DTL)。下面是使用NGINX处理OpenVPN连接的示例,并将它们代理到本地运行的OpenVPN服务:
stream{
server{
listen 1195 udp reuseport;
proxy_pass 127.0.0.1:1194;
}
}
这个功能是由nginx的HTTP upstream module来支持的。nginx的设计贯彻模块化设计的思想,每个功能都由一个模块来支撑。模块之间基本是解耦的。
被动健康检查
upstream backend {
server backend1.example.com:1234 max_fails=3 fail_timeout=3s;
server backend2.example.com:1234 max_fails=3 fail_timeout=3s;
}
这个配置,可以被动监控上游服务器的健康状态,设置最大失败重试及失败超时时间,可以监控由nginx转发的,在上游服务器出现错误、无法连接的请求。这不仅仅对用户重要,同时也对整个系统的稳定性很重要,这个功能是在开源软件中默认提供的。
还有一种“主动监控”,可以主动检查上游服务器的健康状况,只不过这个功能并没有在开源部分提供,而是由基于开源nginx的商业软件nginx plus中提供的。我们在阿里云的云负载中(SLB)也可以看到类似的“健康检查”功能。
三、流量管理
nginx可以用来进行流量管理,将不同来源的用户通过IP或者地域等,分流到不同的服务器上。最典型的例子是做A/B Testing。
比如,我们需要将来自客户的请求分发到两个或多个版本的服务上,以此来测试新功能对用户是否有价值。那么可以用如下配置:
split_clients "${remote_addr}AAA" $variant{
20.0% "backendv2";
* "backendv1";
}
上面这个配置是什么意思?做了些什么事情呢?
"${remote_addr}AAA"指定了要解析什么,这里指定要解析远程机器的IP地址加上"AAA",然后split_client模块会使用MurmurHash2对这个值进行哈希处理,得出一个百分比,这个百分比落在20%以内,那么变量$variant的值赋值为“backendv2”,否则赋值为“backendv1”,即如下步骤:
- 对已有的值执行MURMURHASH2算法得到32位的整型数字,记为hash
- 32位无符号整型的最大值是 2^32-1 记为 max
- hash/max 可以得到百分比 percent
- 配置指令中指示了各个百分比构成的范围,及范围对应的值
- percent 落在哪个范围里面,新变量的值就对应它后面的参数
其实就是通过split_clients 模块对ip地址进行了区分,并将希望的结果值保存在一个变量中,然后就可以在之后的处理中使用这个变量,将不同的请求分发到不同的upstream服务器上,如下:
location / {
proxy_pass http://$variant
}
查找原始IP
当需要知道客户端的IP时,我们需要绕过重重代理,nginx提供了这样的功能,如下配置:
load_module "/usr/lib64/nginx/modules/ngx_http_geoip_module.so";
http {
geoip_country /etc/nginx/geoip/GeoIP.dat;
geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
geoip_proxy 10.0.16.0/26;
geoip_proxy_recursive on;
...
}
使用了geoip_proxy相关模块
限制连接数
limit_conn和limit_req可以对客户端访问进行次数和频率限制,善用,可以有效的防御一些cc、ddos攻击。
http {
limit_conn_zone $binary_remote_addr zone=limitbyaddr:10m;
limit_conn_status 429;
...
server {
...
limit_conn limitbyaddr 40;
...
}
}
http {
limit_req_zone $binary_remote_addr
zone=limitbyaddr:10m rate=1r/s;
limit_req_status 429;
...
server {
...
limit_req zone=limitbyaddr burst=10 nodelay;
...
}
}
限制下载带宽
limit_rate、limit_rate_after,可以对每个客户端连接的下行带宽进行限制。
location /download/ {
limit_rate_after 10m;
limit_rate 1m;
}
上面配置的意思是,在下行流量大于10M之后,下行速度变为1m/s。
四、大规模可扩展的内容缓存
缓存通过存储请求响应以在将来再次提供服务来加速内容服务。内容缓存将减少到上游服务器的负载。nginx缓存完整响应而不是运行为同一请求再次计算和查询。缓存提高性能并减少负载,这意味着可以用更少的资源进行更快的响应。
在战略位置扩展和分发缓存服务器会对用户体验产生巨大影响。最好将内容放在靠近消费者的地方,以获得最佳性能。您还可以将内容缓存在靠近用户的位置。这就是内容交付网络(cdn)的模式。使用NGINX,您可以将内容缓存到任何可以放置NGINX服务器的地方,从而有效地创建自己的CDN。使用NGINX缓存,您还可以在上游出现故障时被动缓存和服务缓存的响应。
1. proxy_cache
语法:proxy_cache zone|off
默认为off,即关闭proxy_cache功能,zone为用于存放缓存的内存区域名称。
例:proxy_cache my_zone;
从nginx 0.7.66版本开始,proxy_cache机制开启后会检测被代理端的HTTP响应头中的"Cache-Control"、"Expire"头域。
如,Cache-Control为no-cache时,是不会缓存数据的。
2. proxy_cache_bypass
语法:proxy_cache_bypass string;
该参数设定,什么情况下的请求不读取cache而是直接从后端的服务器上获取资源。
这里的string通常为nginx的一些变量。
例:proxy_cahce_bypass $cookie_nocache $arg_nocache$arg_comment;
意思是,如果$cookie_nocache $arg_nocache$arg_comment这些变量的值只要任何一个不为0或者不为空时,
则响应数据不从cache中获取,而是直接从后端的服务器上获取。
3. proxy_no_cache
语法:proxy_no_cache string;
该参数和proxy_cache_bypass类似,用来设定什么情况下不缓存。
例:proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
表示,如果$cookie_nocache $arg_nocache $arg_comment的值只要有一项不为0或者不为空时,不缓存数据。
4. proxy_cache_key
语法:proxy_cache_key string;
定义cache key,如: proxy_cache_key $scheme$proxy_host$uri$is_args$args; (该值为默认值,一般不用设置)
5. proxy_cache_path
语法:proxy_cache_path path [levels=levels] keys_zone=name:size [inactive=time] [max_size=size]
path设置缓存数据存放的路径;
levels设置目录层级,如levels=1:2,表示有两级子目录,第一个目录名取md5值的倒数第一个值,第二个目录名取md5值的第2和3个值。keys_zone设置内存zone的名字和大小,如keys_zone=my_zone:10minactive设置缓存多长时间就失效,当硬盘上的缓存数据在该时间段内没有被访问过,就会失效了,该数据就会被删除,默认为10s。max_size设置硬盘中最多可以缓存多少数据,当到达该数值时,nginx会删除最少访问的数据。
http
{
...;
proxy_cache_path /data/nginx_cache/ levels=1:2 keys_zone=my_zone:10m inactive=300s max_size=5g;
...;
server
{
listen 80;
server_name www.aminglinux.com;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 2 4k;
proxy_busy_buffers_size 4k;
proxy_temp_path /tmp/nginx_proxy_tmp 1 2;
proxy_max_temp_file_size 20M;
proxy_temp_file_write_size 8k;
location /
{
proxy_cache my_zone;
proxy_pass http://192.168.10.110:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
缓存分片
为了提高缓存效率将缓存分片,如下:
proxy_cache_path /tmp/mycache keys_zone=mycache:10m;
server {
...
proxy_cache mycache;
slice 1m;
proxy_cache_key $host$uri$is_args$args$slice_range;
proxy_set_header Range $slice_range;
proxy_http_version 1.1;
proxy_cache_valid 200 206 1h;
location / {
proxy_pass http://origin:80;
}
}
这个配置会将一个请求分解为多个子请求,每个子请求返回响应内容的一个片段,这会让大文件的缓存更有效率。
nginx提供了丰富且强大的功能,可以应用于实际业务的不同场景,这本书直接面向实际场景中碰到的问题,更像是一本操作手册,对实战有很大帮助。持续的学习中。