一、Nginx配置、优化

  一)Nginx配置文件详解

  1、Nginx的性能优化

  2、优化后的配置文件

user  nginx nginx;                #运行nginx的用户和组
worker_processes 8; #允许启动的nginx进程数(一般是CPU的倍数)
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000; #为每个nginx进程绑定cpu,将8个nginx进程绑定到8个cpu上

worker_rlimit_nofile 102400; #这个指令是指当一个Nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与Nginx进程数相除,但是Nginx分配请求并不是那么均匀,所以最好与ulimit -n的值保持一致。

client_header_buffer_size 4k; #客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,以便一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k;所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得

open_file_cache max=102400 inactive=20s; #这个将为打开文件指定缓存,默认是没有启用,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没有被请求后删除缓存。

open_file_cache_valid 30s; #这个是指多长时间检查一次缓存的有效信息。

open_file_cache_min_uses 1; #open_file_cache指令中的inactive参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是缓存中打开的,如上例,如果有一个文件在inactive时间内没有使用,它将被移除。


error_log /log/nginx/error.log error; 指定错误日志存放的路径,错误日志记录级别可选项为[ debug |info | notice | warn | error | crit ]

google_perftools_profiles /tmp/tcmalloc; #做了nginx下的Google-perftools优化


events {
use epoll; #使用epoll的I/O模型
multi_accept on; #(告诉nginx收到一个新的连接通知后接受尽可能多的连接)是否允许一次性地响应多个用户请求,
worker_connections 204800; #每个进程允许的最大连接数
}


http {
include mime.types; #加载媒体类型
default_type application/octet-stream;

#charset gb2312 设置使用的字符集,如果一个网站有多种字符集,请不要随便设置,应让程序员在HTML代码中通过Meta标签设置

access_log /dev/null; #不记录全局访问日志

client_max_body_size 8m 设置客户端能够上传的文件大小

sendfile on;
  #sendfile是Linux2.0+退出的一个系统调用,可以避免数据经过用户层,以此可以减少上下文切换次数,和数据拷贝次数。开启这项功能可以优化web服务器,从硬盘读取数据直接传送到网络的性能

tcp_nopush on; #这个参数原理比较复杂,待定

keepalive_timeout 65; #设定长连接超时时长


#压缩配置(主要是为了提高数据传输速度)

gzip on; #开启nginx的gzip压缩,gzip压缩功能就是可以让你节省不少宽带,并加快传输速度,但是会增加服务器CPU的开销。
gzip_disable "msie6"; #禁用IE6的gzip压缩,IE6的某些版本对gzip的压缩支持很不好,会照成页面的假死,测试发现对img进行gzip压缩后会照成IE6的假死。

gzip_proxied any; #对所有的代理结果数据无条件启动压缩
gzip_min_length 1000; #规定大于1K的页面才启动压缩(为了避免页面过小,数据可能会越压越大)
gzip_comp_level 4; #定义gzip的压缩比 1:压缩比最小,处理速度最快,9:压缩比最大但处理最慢(传输快但比较消耗CPU)

gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  #指定需要压缩的MIME类型,"test/html"类型总是会被压缩的。

gzip_vary on;
  #与http头有关系,价格vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持。因此,为了避免浪费不支持的也压缩,需要根据客户端的HTTP头来判断,是否需要压缩(这个理论不太确定),一般用于squid做反向代理是gzip压缩失效。

open_file_cache max=100000 inactive=20s;
  #缓存打开文件描述的文件大小和修改时间信息、存在的目录信息、搜索文件的错误信息:文件不存在 无权限读取等信息。 max指定缓存数量 inactive是指经过多长时间文件没有被请求后删除缓存。
    #这里指定的是20s,所以等到至少20s不访问这个文件,相应缓存的这个文件的更改信息才会被删除

open_file_cache_valid 30s;
#这个是指多长时间检查一次缓存的有效信息。也就是说即使我一直访问这个文件,30s后会检查此文件的更改信息是否改变,发现变化就更新。

open_file_cache_min_uses 2;
#这个指令指定了open_file_cache指令无效的参数中一定的时间范围内可以使用的最小文件数,如果使用更大的值,文件描述符在cached中总是打开状态。

open_file_cache_errors on;
#这个指令是否在搜索一个文件是记录cached错误。

}

   Nginx的正则匹配​

  二)Nginx的日志配置

与Nginx日志相关的指令主要有两条,一条是log_format,用来设置日志的格式。另外一条是access_log,用来指定日志文件的存放路径、格式和缓存大小。两条指令在Nginx配置文件中的位置可以在http{....}之间,也可以在虚拟主机之间,即server{....}之间。


用log_format指令设置日志格式,语法如下:
log_format name format [format ...]
其中name表示定义的格式名称,format表示定义的格式样式。log_format有一个默认的、无需设置的combined日志格式设置,combined的日志格式如下:
log_format combined '$remote_addr - $remote_user [$time_local]'
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agetn"';

可以自定义一份日志的记录格式,不过要注意,log_format指令设置的name名称在Nginx配置文件中是不能重复的。

如果Nginx服务器作为Web服务器,位于负载均衡设备、Squid反向代理的之后,就不能获取到客户端的真实IP地址了。原因是经过反向代理后,由于在客户端和Web服务器之间增加了中间层,因此Web服务器无法直接拿到客户端的IP,通过$remote_addr变量拿到的将是反向代理服务器的IP地址。但是,反向代理服务器在转发请求的HTTP头信息中,可以增加X-Forwarded-For信息,用以记录原有的客户端IP地址和原来客户端请求的服务器地址。这个时候要用log_format指令来设置日志格式,让日志记录X-Forwarded-For信息中的IP地址,即客户的真实IP,设置如下
log_format mylogformat '$http_x_forwarded_for - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"'

 log_format main '[$time_iso8601] $remote_addr - $remote_user "$request" '
    '$status $request_time $upstream_response_time $upstream_addr $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for" "$scheme://$host$uri" "$http_x_connecting_for" "$http_real_ip"';

 log_format main01 '[$time_iso8601] $remote_addr - $remote_user "$request" '
    '$status $request_time $upstream_response_time $upstream_addr $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for" "$scheme://$host$uri" "$args" "$http_x_connecting_for" "$http_real_ip"';

日志格式样式中,
$remote_addr和$http_x_forwarded_for:用于记录IP地址;
$remote_user:用于记录远程客户端用户名称
$time_local用于记录访问时间与时区;
$request用于记录请求URL与HTTP协议
$status 用于记录请求状态
$body_bytes_sent 用于记录发送给客户端的文件主体内容大小
$http_referer 用于记录是从哪个页面链接访问过来的;
$http_user_agent用于记录客户端浏览器的相关信息。


access_log指令的语法如下:
access_log path [format [buffer=size | off]]
path:指定日志路径
format:指定日志格式
buffer:指定日志内存缓冲区大小

如:access_log /log/access.log mylogformat buffer=32k;
  access_log /opt/logs/nginx/www.test.com_access.log main;

  2、缓存设置

​  http://nginx.org/en/docs/http/ngx_http_core_module.html​

  示例一:

location = /images/default.gif {
expires 30s; # 30m:30 分钟,2h:2 小时,30d:30 天
}

  示例二:

location ~* \.(jpg|jpeg|gif|bmp|png){
expires 1d;#缓存1天
}

  expires 的上下文包括 location、if in location

  304 也是一种很好的缓存手段

  原理是: 服务器响应文件内容是,同时响应etag标签(内容的签名,内容一变,他也变), 和 last_modified_since 2个标签值

浏览器下次去请求时,头信息发送这两个标签, 服务器检测文件有没有发生变化,如无,直接头信息返回 etag,last_modified_since
浏览器知道内容无改变,于是直接调用本地缓存.
这个过程,也请求了服务器,但是传着的内容极少.
对于变化周期较短的,如静态html,js,css,比较适于用这个方式

  三)Nginx日志分割

  Nginx的信号控制

TERM,INT 快速关闭;
QUIT 从容关闭
HUP 平滑重启,重新加载配置文件
USR1 重新打开日志文件,在切割日志时用途较大
USR2 平滑升级可执行程序
WINCH 从容关闭工作进程

  Nginx的日志切割、归档(编写bash脚本实现),晚上0点定时执行

1 #!/bin/bash
2
3
4 log_base='/opt/logs/nginx'
5 top_level_domain='test.com'
6 log_archive_time=$(date -d yesterday +"%Y")/$(date -d yesterday +"%m")
7 yesterday_time=$(date -d yesterday +"%Y%m%d")
8 nginx_pid_dir='/usr/local/nginx/logs/nginx.pid'
9 server_name_pre="user api"
10
11
12 for i in ${server_name_pre}
13 do
14 server_name=${i}.${top_level_domain}
15 mkdir -p ${log_base}/${server_name}/${log_archive_time}
16 cd ${log_base}/${server_name}
17 mv ${server_name}-access.log ./${log_archive_time}/${server_name}-access_${yesterday_time}.log
18 kill -USR1 `cat ${nginx_pid_dir}`
19 done

  四)location和rewrite配置

  1、location的匹配方式

1 =用于普通uri前,要求精确匹配,如果匹配成功,则停止搜索并用当前location处理此请求
2 ~ 表示uri包含正则,并且区分大小写
3 ~*表示uri包含正则,但不区分大小写
4 ^~表示在普通uri前要求Nginx服务器找到普通uri匹配度最高的那个location后,立即处理此请求,并不再进行正则匹配
5

  location的命中过程是怎样的?

  1. 先判断精准命中,若命中,立即返回结果并结束解析过程
  2. 判断普通命中,若有多个命中,记录下来最长的命中结果(注意:记录但不结束,最长的为准)
  3. 继续判断正则表达式的解析结果,按配置里的正则表达式顺序为准,由上到下开始匹配,一旦匹配成功一个,立即返回结果,并结束解析过程

  延伸分析:

  1. 普通命中,顺序无所谓,是因为按命中的长短来确定的
  2. 正则命中,顺序有所谓,因为是从前到后命中的

 

Nginx配置、优化_客户端

   2、rewrite重写

  官网文档:​​http://nginx.org/en/docs/http/ngx_http_rewrite_module.html​

  rewrite功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。rewrite只能放在server{},location{},if{}中,并且只能对域名后边的除去传递的参数外的字符串起作用,例如​​http://seanlook.com/a/we/index.PHP?id=1&u=str​​​ 只对​​/a/we/index.php​​​重写。语法​​rewrite regex replacement [flag];​

    1、标志位
1 last : 相当于Apache的[L]标记,表示完成rewrite
2 break : 停止执行当前虚拟主机的后续rewrite指令集
3 redirect : 返回302临时重定向,地址栏会显示跳转后的地址
4

  因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。这里 last 和 break 区别有点难以理解:

1 last一般写在server和if中,而break一般使用在location中
2 last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
3
    2、if指令与全局变量

  if判断指令

  语法为​​if(condition){...}​​,对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件(conditon)可以是如下任何内容:

  • 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
  • 直接比较变量和内容时,使用​​=​​​或​​!=​
  • ​~​​​正则表达式匹配,​​~*​​​不区分大小写的匹配,​​!~​​区分大小写的不匹配
1 -f和!-f用来判断是否存在文件
2 -d和!-d用来判断是否存在目录
3 -e和!-e用来判断是否存在文件或目录
4

  全局变量

1 $args : #这个变量等于请求行中的参数,同$query_string
2 $content_length : 请求头中的Content-length字段。
3 $content_type : 请求头中的Content-Type字段。
4 $document_root : 当前请求在root指令中指定的值。
5 $host : 请求主机头字段,否则为服务器名称。
6 $http_user_agent : 客户端agent信息
7 $http_cookie : 客户端cookie信息
8 $limit_rate : 这个变量可以限制连接速率。
9 $request_method : 客户端请求的动作,通常为GET或POST。
10 $remote_addr : 客户端的IP地址。
11 $remote_port : 客户端的端口。
12 $remote_user : 已经经过Auth Basic Module验证的用户名。
13 $request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。
14 $scheme : HTTP方法(如http,https)。
15 $server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
16 $server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。
17 $server_name : 服务器名称。
18 $server_port : 请求到达服务器的端口号。
19 $request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
20 $uri : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
21
    3、常用的正则
1 . : 匹配除换行符以外的任意字符
2 ? : 重复0次或1次
3 + : 重复1次或更多次
4 * : 重复0次或更多次
5 \d :匹配数字
6 ^ : 匹配字符串的开始
7 $ : 匹配字符串的介绍
8 {n} : 重复n次
9 {n,} : 重复n次或更多次
10 [c] : 匹配单个字符c
11 [a-z] : 匹配a-z小写字母的任意一个

  小括号()之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容。正则里面容易让人困惑的是\转义特殊字符。

  3、解决跨域问题

apis {
rewrite ^.+apis/?(.*)$ /$1 break;
include uwsgi_params;
proxy_pass http://b.com:;

  五)架构篇

  1、相同server_name多个虚拟主机优先级访问

    

Nginx配置、优化_客户端_02

  启动时,会有warn,但不影响使用

  效果:会按照文件优先读取的顺序,成效的是第一个匹配到的配置。

  2、location匹配优先级

  • =          进行普通字符精确匹配,也就是完全匹配(优先级最高,匹配到就不再继续往下匹配)
  • ^~        表示普通字符匹配,使用前缀匹配(优先级最高,匹配到就不再继续往下匹配)
  • ~ \~*    表示执行一个正则(优先级比较低,继续往下匹配,若下面有更精确的匹配,会使用下面的配置;若没有就使用自身的配置)  ~区分大小写
    范例

  

Nginx配置、优化_nginx_03

  3、try_files的使用

  按顺序检查文件是否存在:存在直接访问,不存在后面的配置生效

  

Nginx配置、优化_nginx_04

    1、范例

  

Nginx配置、优化_客户端_05

    2、使用场景:缓存——缓存不存在,访问后面

  4、alias和root的区别

    访问加载的路径不同

    1、root

  

Nginx配置、优化_缓存_06

    2、alias

  

Nginx配置、优化_缓存_07

   5、传递用户的真实IP地址

 

  

Nginx配置、优化_nginx_08

  在第一层代理设置一个变量:set x_real_ip=$remote_addr

  6、其他

    1、Nginx:413 request entity too large
  • 用户上传文件限制:client_max_body_size
    2、502  badgateway
  • 后端服务无响应
    3、504 gateway time-out
  • 后端服务执行超时

  六)性能优化

  1、性能优化考虑点

    1、当前系统瓶颈

    观察指标、压力测试(接口压力测试)

    2、理解业务模式

    接口业务类型、系统层次结构

    3、性能与安全(权衡利弊)

    防火墙配置

   2、系统于Nginx的性能优化

    1、文件句柄

  Linux\Unix一切皆文件,文件句柄就是一个索引

    2、设置方式

  系统全局性修改、用户局部性修改、进程局部性修改

  /etc/security/limits.conf (修改完立即生效)

#用户局部修改
root soft nofile 65536
root hard nofile 65536
#全局
* soft nofile 65536
* hard nofile 65536
* soft nproc 65536
* hard nproc 65536
* soft memlock unlimited
* hard memlock unlimited

  进程限制

worker_rlimit_nofile 10240;

 

  3、系统与Nginx的性能优化

    1、CPU的亲和

  

  查看物理CPU

cat /proc/cpuinfo|grep "physical id"|sort|uniq|wc

  查看每个CPU的核心

cat /proc/cpuinfo|grep "cpu cores"|sort|uniq|wc

  设置Nginx的CPU worker(建议和CPU的核数相同)

worker_processes 16;
worker_cpu_affinity auto; #Nginx1.9.x开始支持

events {
  use epoll;
  worker_connections 10240; #建议改大
}

  查看Nginx进程使用CPU核数情况

ps -eo pid,args,psr|grep

  七)基于Nginx架构的安全篇

  1、常见的恶意行为

  • 网页行为:爬虫行为和恶意抓取、资源盗用(要分清允许和不允许的内容,采取不同的策略)
  • 基础防盗链功能:目的不让恶意用户能轻易的爬取网站对外数据
  • secure_link_module——对数据安全性提高加密验证和失效性,适合如核心重要数据
  • access_module:对后台、部分用户服务的数据提供IP防控

  2、常见的应用层攻击手段

  • 后台密码撞库——通过猜测密码字典不断对后台系统登录性尝试,以获取后台密码
  • 方法一:后台登录密码复杂度
  • 方法二:access_module——对后台提供IP防控
  • 方法三:预警机制:Nginx+lua
  • 文件上传漏洞——利用这些可以上传的接口将恶意代码植入服务器中,再通过url去访问以执行代码
  • SQL注入——利用未过滤/未审核用户输入的攻击方法,让应用运行本不应该运行的SQL代码

  

Nginx配置、优化_缓存_09

  

Nginx配置、优化_客户端_10

  

Nginx配置、优化_缓存_11

  sql中 #是注释

  3、Nginx防攻击策略

  

Nginx配置、优化_缓存_12

  4、场景:Nginx+lua的安全waf防火墙

   项目地址16年:​​https://github.com/loveshell/ngx_lua_waf​