1 ngnix可以提供的服务
- web 服务.
- 负载均衡 (反向代理)
- web cache(web 缓存)
2 ngnix的应用场合
- 静态服务器。(图片,视频服务)另一个lighttpd。并发几万,html,js,css,flv,jpg,gif等。
- 动态服务,nginx——fastcgi 的方式运行PHP,jsp。(PHP并发在500-1500,MySQL 并发在300-1500)。
- 反向代理,负载均衡。日pv2000W以下,都可以直接用nginx做代理。
- 缓存服务。
3 Apache select模型和 nginx epoll 模型对比讲解
- 传统Apache都是多进程或者多线程来工作, apche 对于套接字的I/O,读或者写,但是读或者写都是阻塞的,阻塞意味着进程就得挂起进入sleep状态,那么一旦连接数很多,Apache必然要生成更多的进程来响应请求,一旦进程多了,CPU对于进程的切换就频繁了,很耗资源和时间,所以就导致apache性能下降了,说白了就是处理不过来这么多进程了。其实仔细想想,如果对于进程每个请求都没有阻塞,那么效率肯定会提高很多。
- Nginx采用epoll模型,异步非阻塞。对于Nginx来说,把一个完整的连接请求处理都划分成了事件,一个一个的事件。比如accept(), recv(),磁盘I/O,send()等,每部分都有相应的模块去处理,一个完整的请求可能是由几百个模块去处理。真正核心的就是事件收集和分发模块,这就是管理所有模块的核心。只有核心模块的调度才能让对应的模块占用CPU资源,从而处理请求。拿一个HTTP请求来说,首先在事件收集分发模块注册感兴趣的监听事件,注册好之后不阻塞直接返回,接下来就不需要再管了,等待有连接来了内核会通知你(epoll的轮询会告诉进程),cpu就可以处理其他事情去了。一旦有请求来,那么对整个请求分配相应的上下文(其实已经预先分配好),这时候再注册新的感兴趣的事件(read函数),同样客户端数据来了内核会自动通知进程可以去读数据了,读了数据之后就是解析,解析完后去磁盘找资源(I/O),一旦I/O完成会通知进程,进程开始给客户端发回数据send(),这时候也不是阻塞的,调用后就等内核发回通知发送的结果就行。整个下来把一个请求分成了很多个阶段,每个阶段都到很多模块去注册,然后处理,都是异步非阻塞。异步这里指的就是做一个事情,不需要等返回结果,做好了会自动通知你。
4 ngnix 配置文件
main{ #(全局设置)
http{ #服务器
upstream{} #(负载均衡服务器设置:主要用于负载均衡和设置一系列的后端服务器)
server{ #(主机设置:主要用于指定主机和端口)
location{} #(URL匹配特点位置的设置)
}
}
}
-
main 全局配置
user www www; worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000; error_log /var/logs/nginx_error.log crit; pid /usr/local/webserver/nginx/nginx.pid; worker_rlimit_nofile 65535;-
user www www;: 指定nginx进程使用什么用户启动
-
worker_processes 4; : 指定启动多少进程来处理请求,一般情况下设置成CPU的核数,如果开启了ssl和
gzip更应该设置成与逻辑CPU数量一样甚至为2倍,可以减少I/O操作。
grep ^processor /proc/cpuinfo | wc -l查看CPU核数。 -
worker_cpu_affinity 0001 0010 0100 1000;: 在高并发情况下,通过设置将CPU和具体的进程绑定来降低由于多核CPU切换造成的寄存器等现场重建带来的性能损耗。如worker_cpu_affinity 0001 0010 0100 1000; (四核)。
-
error_log /var/logs/nginx_error.log crit;: error_log是个主模块指令,用来定义全局错误日志文件。日志输出级别有debug、info、notice、warn、error、crit可供选择,其中,debug输出日志最为最详细,而crit输出日志最少。
-
pid /usr/local/webserver/nginx/nginx.pid;: 指定进程pid文件的位置。
-
worker_rlimit_nofile 65535;: 用于指定一个nginx进程可以打开的最多文件描述符数目,这里是65535,需要使用命令“ulimit -n 65535”来设置。
-
-
events模块
events{ use epoll; worker_connections 65536; }- use epoll;use是个事件模块指令,用来指定Nginx的工作模式。Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll。其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平台上,而kqueue用在BSD系统中。对于Linux系统,epoll工作模式是首选。在操作系统不支持这些高效模型时才使用select。
- worker_connections 65536;每一个worker进程能并发处理(发起)的最大连接数(包含与客户端或后端被代理服务器间等所有连接数)。nginx作为反向代理服务器,计算公式 最大连接数 = worker_processes * worker_connections/4,所以这里客户端最大连接数是65536,这个可以增到到8192都没关系,看情况而定,但不能超过后面的worker_rlimit_nofile。当nginx作为http服务器时,计算公式里面是除以2。进程的最大连接数受Linux系统进程的最大打开文件数限制,在执行操作系统命令ulimit -n 65536后worker_connections的设置才能生效。
-
http服务器
http{ include mime.types; default_type application/octet-stream; #charset gb2312; }- include是个主模块指令,实现对配置文件所包含的文件的设定,可以减少主配置文件的复杂度。类似于Apache中的include方法。
- default_type属于HTTP核心模块指令,这里设定默认类型为二进制流,也就是当文件类型未定义时使用这种方式,例如在没有配置PHP环境时,Nginx是不予解析的,此时,用浏览器访问PHP文件就会出现下载窗口。
- charset gb2312; 指定客户端编码格式。
server_names_hash_bucket_size 128; client_header_buffer_size 32k; large_client_header_buffers 4 128k; client_max_body_size 10m; client_body_buffer_size 128k; sendfile on ; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65 : client_body_timeout 60s; send_timeout 60s;server_names_hash_bucket_size 128;: 服务器名字的hash表大小。client_header_buffer_size 32k;:用来指定来自客户端请求头的header buffer 大小。对于大多数请求,1K的缓存已经足够了,如果自定义了消息头或有更大的cookie,可以增大缓存区大小。large_client_header_buffers 4 128k;:用来指定客户端请求中较大的消息头的缓存最大数量和大小,4为个数,128k为大小,最大缓存为4个128KB。client_max_body_size 8m;: 客户端请求的最大的单个文件字节数。client_max_body_size 10m;: 允许客户端请求的最大单文件字节数。如果有上传较大文件,请设置它的限制值。client_body_buffer_size 128k;: 缓冲区代理缓冲用户端请求的最大字节数。sendfile on ;: 开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,减少用户空间到内核空间的上下文切换。对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。开启tcp_nopush on;和tcp_nodelay on;防止网络阻塞。keepalive_timeout 65 :: 长连接超时时间,单位是秒,这个参数很敏感,涉及浏览器的种类、后端服务器的超时设置、操作系统的设置,可以另外起一片文章了。长连接请求大量小文件的时候,可以减少重建连接的开销,但假如有大文件上传,65s内没上传完成会导致失败。如果设置时间过长,用户又多,长时间保持连接会占用大量资源。client_body_timeout 60s;: 用于设置客户端请求主体读取超时时间,默认是60s。如果超过这个时间,客户端还没有发送任何数据,nginx将返回Request time out(408)错误。send_timeout :: 用于指定响应客户端的超时时间。这个超时仅限于两个连接活动之间的时间,如果超过这个时间,客户端没有任何活动,Nginx将会关闭连接。
-
HTTP参数之gzip模块设置
gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.1; gzip_comp_level 6; gzip_types text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml; gzip_vary on;gzip on;开启gzip压缩输出gzip_min_length 1k;最小压缩文件大小,页面字节数从header头的Content-Length中获取。默认值为0,不管多大页面都压缩,建议设置成大于1K的字节数,小于1K可能会越压越大。gzip_buffers 4 16k;压缩缓冲区,表示申请四个16K的内存作为压缩结果流缓存,默认是申请与原始数据大小相同的内存空间来存储gzip压缩结果。gzip_http_version 1.1;用于设置识别HTTP协议版本,默认是1.1,目前主流浏览器都已成指出。(默认1.1,前端如果是squid2.5请使用1.0)gzip_comp_level 6;压缩等级,1压缩比最小,处理速度最快,9压缩比最大,传输速度快,但是消耗CPU资源。gzip_types text/plain application/x-javascript text/css application/xml;压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。gzip_vary on;和http头有关系,会在响应头加个 Vary: Accept-Encoding ,可以让前端的缓存服务器缓存经过gzip压缩的页面,例如,用Squid缓存经过Nginx压缩的数据。gzip_proxied any;Nginx作为反向代理的时候启用,决定开启或者关闭后端服务器返回的结果是否压缩,匹配的前提是后端服务器必须要返回包含”Via”的 header头。limit_zone crawler $binary_remote_addr 10m;开启限制IP连接数的时候需要使用
-
nginx 配置虚拟主机
http服务上支持若干虚拟主机。每个虚拟主机一个对应的server配置项,配置项里面包含该虚拟主机相关的配置。在提供mail服务的代理时,也可以建立若干server。每个server通过监听地址或端口来区分。
server{ listen 80 default; server_name _; index index.html index.htm index.php; root /data/htdocs/www; #server_name_in_redirect off; location ~ .*\.(php|php5)?${ #fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fcgi.conf; } location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)${ expires 30d; } location ~ .*\.(js|css)?${ expires 1h; } }listen 80;监听端口,默认80,小于1024的要以root启动。可以为listen *:80、listen 127.0.0.1:80等形式。server_name blog.biglittleant.cn;服务器名,如localhost、www.example.com,可以通过正则匹配。root /var/www/html定义服务器的默认网站根目录位置。如果locationURL匹配的是子目录或文件,root没什么作用,一般放在server指令里面或/下。index index.jsp index.html index.htm定义路径下默认访问的文件名,一般跟着root放。
-
location语法规则
location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
=表示精确匹配。只有请求的url路径与后面的字符串完全相等时,才会命中。~表示该规则是使用正则定义的,区分大小写。~*表示该规则是使用正则定义的,不区分大小写。^~表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找。
-
使用正则定义的location在配置文件中出现的顺序很重要。因为找到第一个匹配的正则后,查找就停止了,后面定义的正则就是再匹配也没有机会了。
-
使用精确匹配可以提高查找的速度。例如经常请求
/的话,可以使用=来定义location。 -
访问控制 allow/deny
Nginx 的访问控制模块默认就会安装,而且写法也非常简单,可以分别有多个allow,deny,允许或禁止某个ip或ip段访问,依次满足任何一个规则就停止往下匹配。如:
location /nginx-status { stub_status on; access_log off; allow 192.168.10.100; allow 172.29.73.0/24; deny all; } -
URL尾部的/需不需要
- location中的字符有没有
/都没有影响。也就是说/user/和/user是一样的。 - 如果URL结构是
https://domain.com/的形式,尾部有没有/都不会造成重定向。因为浏览器在发起请求的时候,默认加上了/。虽然很多浏览器在地址栏里也不会显示/。这一点,可以访问baidu验证一下。 - 如果URL的结构是
https://domain.com/some-dir/。尾部如果缺少/将导致重定向。因为根据约定,URL尾部的/表示目录,没有/表示文件。所以访问/some-dir/时,服务器会自动去该目录下找对应的默认文件。如果访问/some-dir的话,服务器会先去找some-dir文件,找不到的话会将some-dir当成目录,重定向到/some-dir/,去该目录下找默认文件。可以去测试一下你的网站是不是这样的。
- location中的字符有没有
-
通用配置文件
user www www; worker_processes 2; error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; pid logs/nginx.pid; events { use epoll; worker_connections 2048; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; # tcp_nopush on; keepalive_timeout 65; # gzip压缩功能设置 gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.1; gzip_comp_level 6; gzip_types text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml; gzip_vary on; # http_proxy 设置 client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 75; proxy_send_timeout 75; proxy_read_timeout 75; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; proxy_temp_path /usr/local/nginx/proxy_temp 1 2; # 设定负载均衡后台服务器列表 upstream backend { #ip_hash; server 192.168.10.100:8080 max_fails=2 fail_timeout=30s ; server 192.168.10.101:8080 max_fails=2 fail_timeout=30s ; } # 很重要的虚拟主机配置,多个虚拟机可以复制修改此部分 server { listen 80; server_name test.example.com; root /apps/oaapp; charset utf-8; access_log logs/host.access.log main; #对 / 所有做负载均衡+反向代理 location / { root /apps/oaapp; index index.php index.html index.htm; proxy_pass http://backend; proxy_redirect off; # 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP 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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; } #静态文件,nginx自己处理,不去backend请求后端的服务 location ~* /download/ { root /data/app/nginx/downloads; } location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ { root /data/app/nginx/images; expires 7d; } location /nginx_status { stub_status on; access_log off; allow 192.168.10.0/24; deny all; } location ~ ^/(WEB-INF)/ { deny all; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } -
日志配置
日志级别: debug < info < notice < warn < error < crit < alert < emerg
$remote_addr, $http_x_forwarded_for 记录客户端IP地址
$remote_user记录客户端用户名称
$request记录请求的URL和HTTP协议(GET,POST,DEL,等)
$status记录请求状态
$body_bytes_sent发送给客户端的字节数,不包括响应头的大小; 该变量与Apache模块mod_log_config里的“%B”参数兼容。
$bytes_sent发送给客户端的总字节数。
$connection连接的序列号。
$connection_requests 当前通过一个连接获得的请求数量。
$msec 日志写入时间。单位为秒,精度是毫秒。
$pipe如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。
$http_referer 记录从哪个页面链接访问过来的
$http_user_agent记录客户端浏览器相关信息
$request_length请求的长度(包括请求行,请求头和请求正文)。
$request_time 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$time_iso8601 ISO8601标准格式下的本地时间。
$time_local通用日志格式下的本地时间。
仅记录固定 IP 的错误:
当你设置日志级别成 debug,如果你在调试一个在线的高流量网站的话,你的错误日志可能会记录每个请求的很多消息,这样会变得毫无意义。
在events{...}中配置如下内容,可以使 Nginx 记录仅仅来自于你的 IP 的错误日志。
events {
debug_connection 1.2.3.4;
}
常用例子:
main格式:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'$upstream_addr $upstream_response_time $request_time ';
access_log logs/access.log main;
json格式
log_format logstash_json '{"@timestamp":"$time_iso8601",'
'"host": "$server_addr",'
'"client": "$remote_addr",'
'"size": $body_bytes_sent,'
'"responsetime": $request_time,'
'"domain": "$host",'
'"url":"$request_uri",'
'"referer": "$http_referer",'
'"agent": "$http_user_agent",'
'"status":"$status",'
'"x_forwarded_for":"$http_x_forwarded_for"}';
-
负载均衡配置
轮询:每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
upstream backserver { server 192.168.0.14; server 192.168.0.15; }权重:权重越高,在被访问的概率越大,如上例,分别是30%,70%。
upstream backserver { server 192.168.0.14 weight=3; server 192.168.0.15 weight=7; }ip_hash:我们可以采用ip_hash指令解决这个问题,如果客户已经访问了某个服务器,当用户再次访问时,会将该请求通过哈希算法,自动定位到该服务器。 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
upstream backserver { ip_hash; server 127.0.0.1:9090 down; (down 表示单前的server暂时不参与负载) server 127.0.0.1:8080 weight=2 ; (weight 默认为1.weight越大,负载的权重就越大) server 127.0.0.1:6060 max_fails=3 ;(允许请求失败的次数,默认是1) server 127.0.0.1:6061 fail_timeout=3 ;(在经历了max_fails次失败后,暂停服务的时间。) server 127.0.0.1:7070 backup; (其它所有的非backup机器down或者忙的时候,请求backup机器) }fair:按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backserver { server server1; server server2; fair; }url_hash:按访问url的hash结果来分配请求,使每个url定向到同一个(对应的)后端服务器,后端服务器为缓存时比较有效。
upstream backserver { server squid1:3128; server squid2:3128; hash $request_uri; hash_method crc32; }配置实例:
worker_processes 4; events { # 最大并发数 worker_connections 4096; } http{ # 待选服务器列表 upstream myproject{ # ip_hash指令,将同一用户引入同一服务器。 ip_hash; server 125.219.42.4 fail_timeout=60s; server 172.31.2.183; } server{ # 监听端口 listen 80; # 根目录下 location / { # 选择哪个服务器列表 proxy_pass http://myproject; } } }