1、nginx解读:
Nginx由内核和模块组成,其中,内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端请求映射到一个location block(location是Nginx配置中的一个指令,用于URL匹配),而在这个location中所配置的每个指令将会启动不同的模块去完成相应的工作。
Nginx相对于Apache优点:
- 1)高并发响应性能非常好,官方Nginx处理静态文件并发5w/s
- 2)反向代理性能非常好。(可用于负载均衡)
- 3)内存和cpu占用率低。(为Apache的1/5-1/10)
- 4)功能较Apache少(常用功能均有)
- 5)对php可使用cgi方式和fastcgi方式。
- A、负载均衡
常见负载均衡算法:轮询(rr)、权重(weight)、ip_hash、fair(第三方)、url_hash(第三方)
- 轮询:根据每次请求顺序分配到不同服务器。upstream指令定义一组负载均衡后端服务器
- 权重:根据不同的后端服务器设置不同的权重,当后端服务故障时可以自动剔除该服务器配合max_fails fail_timeout。如果某台服务器在fail_timeout时间内出现max_fail次连接失败,nginx就会认为该服务器出现故障从而踢出去。但是这种给用户感知很不好,最好使用nginx的健康检查模块做到用户无感知。
- ip_hash:根据用户的客户端ip请求分配给后端服务器,由于源ip相同客户端经过ip_hash算法后的值相同,客户端的请求可以分配到后台同一台服务器上。可以解决session的问题,一般用于登录会话。
- fair:按后端服务器的响应时间来分配请求,响应时间短的优先分配。
- url_hash(第三方):根据用户请求的url进行hash,在通过hash值选择后端server。
-
B、反向代理(proxy_pass和upstream)
针对于服务器,代替服务器接收请求,不做任何处理,收到帮你转发到后端处理,保护内部安全隐藏企业的真实ip。 -
C、高可用
高可用、高可用性,针对于WEB网站,服务器系统,数据库的。
高可用不是说网站不宕机,可用率达到及格9,99%、99.9%;衡量的WEB网站高可用是看几个9;
高可用其共同特点有多个(至少2台以上)相同的系统做备份(2台Nginx,2台MYSQL,2台tomcat等,当其中一台服务宕机,可以快速切换至另外一台)
Nginx web高可用实现方式:
基于shell脚本实现
基于keepalived软件实现
基于Heartbeat软件实现 -
D、宕机容错
如果nginx请求后端服务器tomcat集群某一台服务器down,不可能一直请求。怎么处理呢?
这时候就需要加入nginx参数:
#n为时间自己去调试
proxy_connect_timeout n;
#后端服务器连接的超时时间_发起握手等候响应超时时间(默认60秒)
proxy_send_timeout n;
#连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理(也可以说是后端服务器处理请求的时间)
proxy_read_timeout n;
#后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据 -
E、动静分离
动态的交给tomcat处理,静态nginx处理。提高静态资源的访问速度。
2、nginx Rewrite规则
Rewrite规则含义就是某个URL重写成特定的URL,从某种意义上说为了美观或者对搜索引擎友好,提高收录量及排名等。
Rewrite规则的最后一项参数为flag标记,支持的flag标记主要有以下几种:
1)last :相当于Apache里德(L)标记,表示完成rewrite;
2)break;本条规则匹配完成后,终止匹配,不再匹配后面的规则
3)redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址
4)permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
last和break用来实现URL重写,浏览器地址栏URL地址不变。
a)例如用户访问www.test.com,想直接跳转到网站下面的某个页面,www.test.com/new/index.html如何来实现呢?
我们可以使用Nginx Rewrite 来实现这个需求,具体如下:
在server中加入如下语句即可:
rewrite ^/$ http://www.test.com/new/index.html permanent;
*代表前面0或更多个字符
+代表前面1或更多个字符
?代表前面0或1个字符
^代表字符串的开始位置
$代表字符串结束的位置
。为通配符,代表任何字符
b)例如多个域名跳转到同一个域名,nginx rewrite规则写法如下:
server
{
listen 80;
server_name www.test.com test.com;
if ($host != 'www.test.com' ) {
rewrite ^/(.*)$ http://www.test.com/$1 permanent;
}
3、nginx防范DDos
通过nginx和nginx Plus阻止DDos攻击
例如攻击的流量通常来源于一些固定的IP地址,每一个IP地址会创建比真实用户多得多的连接和请求;同时由于流量全部是由机器产生的,其速率要比人类用户高的多。此外,进行攻击的机器其User-Agent头也不是标准的值,Referer头有时也会被设置成能够与攻击关联起来的值。针对这些特点,认为Nginx和Nginx Plus有很多能够通过调节或控制流量来应对或者减轻DDoS攻击的特性。
-
A、限制请求率:
将Nginx和Nginx Plus可接受的入站请求率限制为某个适合真实用户的值。例如,通过下面的配置让一个真正的用户每两秒钟才能访问一次登录页面:limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m; server { ... location /login.html { limit_req zone=one; ... } }
在该配置中,limit_req_zone指令配置了一个名为one的共享内存zone用来存储$binary_remote_addr的请求状态,location块中/login.html的limit_req指令引用了共享内存zone。
-
B、限制连接数量:
将某个客户端IP地址所能打开的连接数限制为真实用户的合理值。例如,限制每一个IP对网站/store部分打开的连接数不超过10个:limit_conn_zone $binary_remote_addr zone=addr:10m; server { ... location /store/ { limit_conn addr 10; ... } }
该配置中,limit_conn_zone指令配置了一个名为addr的共享内存zone用来存储$binary_remote_addr的请求,location块中/store/的limit_conn指令引用了共享内存zone,并将最大连接数设置为10.
-
C、关闭慢连接:
关闭那些一直保持打开同时写数据又特别频繁的连接,因为它们会降低服务器接受新连接的能力。Slowloris就是这种类型的攻击。对此,可以通过client_body_timeout和client_header_timeout指令控制请求体或者请求头的超时时间,例如,通过下面的配置将等待时间控制在5s之内:server { client_body_timeout 5s; client_header_timeout 5s; ... }
-
D、设置IP黑名单:
如果能识别攻击者所使用的客户端IP地址,那么通过deny指令将其屏蔽,让Nginx和Nginx Plus拒绝来自这些地址的连接或请求。例如,通过下面的指令拒绝来自123.123.123.3、123.123.123.5和123.123.123.7的请求:location / { deny 123.123.123.3; deny 123.123.123.5; deny 123.123.123.7; ... }
-
E、设置IP白名单:
如果允许访问的IP地址比较固定,那么通过allow和deny指令让网站或者应用程序只接受来自于某个IP地址或者某个IP地址段的请求。例如,通过下面的指令将访问限制为本地网络的一个IP段:location / { allow 192.168.1.0/24; deny all; ... }
-
F、通过缓存削减流量峰值:
通过启用缓存并设置某些缓存参数让Nginx和Nginx Plus吸收攻击所产生的大部分流量峰值。例如,通过proxy_cache_use_stale指令的updating参数告诉Nginx何时需要更新过期的缓存对象,避免因重复发送更新请求对后端服务器产生压力。另外,proxy_cache_key指令定义的键通常会包含嵌入的变量,例如默认的键$scheme$proxy_host$request_uri包含了三个变量,如果它包含$query_string变量,那么攻击者可以通过发送随机的query_string值来耗尽缓存,因此,如果没有特别原因,不要在该键中使用$query_string变量。
-
G、阻塞请求:
配置Nginx和Nginx Plus阻塞以下类型的请求:
以某个特定URL为目标的请求
User-Agent头中的值不在正常客户端范围之内的请求
Referer头中的值能够与攻击关联起来的请求
其他头中存在能够与攻击关联在一起的值的请求
例如,通过下面的配置阻塞以/foo.php为目标的攻击:
location / {
if ($http_user_agent ~* foo|bar) {
return 403;
}
...
}
- H、限制对后端服务器的连接数:
通常Nginx和Nginx Plus实例能够处理比后端服务器多得多的连接数,因此可以通过Nginx Plus限制到每一个后端服务器的连接数。例如,通过下面的配置限制Nginx Plus和每一台后端服务器之间建立的连接数不多于200个:upstream website { server 192.168.100.1:80 max_conns=200; server 192.168.100.2:80 max_conns=200; queue 10 timeout=30s; }
4、nginx防盗链
目的:防止资源非法利用
-
A、对nginx项目下的jpg、gif、mp4、png等资源进行防盗链
location ~* \.(jpg|gif|mp4|png)${ valid_referer none blocked baidu.com,google.com; if ($valid_referers){ rewrite ^/ https://www.badiu.com/images/1.jpg; #如果有人盗取,放回一个防盗链图片或者403。 return 403; } }
-
B、对nginx指定目录或指定项目进行防盗链
location /image/ { valid_referer none blocked server_names baidu.com,google.com; if ($valid_referer){ return 403; } }
-
C、nginx第三方模块ngx_http_accesskey_module实现下载文件的防盗链
这个自定义模块编译安装就行了配置加入以下内容:location /download { accesskey on; accesskey_hashmethod md5; accesskey_arg "key"; accesskey_signature "mypass$remote_addr"; } #accesskey为模块开关; #accesskey_hashmethod为加密方式MD5或者SHA-1; #accesskey_arg为url中的关键字参数; #accesskey_signature为加密值,此处为mypass和访问IP构成的字符串
5、nginx进程解读
yum安装或者源码编译安装,nginx.conf中会发现默认user nginx或者是use nobody。一个maste进程管理多个worker进程,一般情况下worker进程的数量与服务器上的CPU核心数相等。每一个worker进程都很繁忙,他们是真正提供服务的,而master只是负责管理worker进程。workerer进程之间通过共享内存、原子操作等一些进程间通信机制来实现负载均衡等功能。
思考为什么要使用master-worker进程来启动nginx?
- 由于master进程不会对用户请求提供服务,只用于管理真正提供服务的worker进程,所以master进程可以是唯一的,它仅专注于自己的纯管理工作,为管理员提供命令行服务,包括诸如启动服务、停止服务、重载配置文件、平滑升级程序等。master进程需要拥有较大的权限,例如,通常会利用root用户启动master进程。worker进程的权限要小于或等于master进程,这样master进程才可以完全地管理worker进程。当任意一个worker进程出现错误从而导致coredump时,master进程会立刻启动新的worker进程继续服务
- 多个worker进程处理互联网请求不但可以提高服务的健壮性(一个worker进程出错后,其他worker进程仍然可以正常提供服务),最重要的是,这样可以充分利用现在常见的SMP多核架构,从而实现微观上真正的多核并发处理。因此,用一个进程( master进程)来处理互联网请求肯定是不合适的。另外,为什么要把worker进程数量设置得与CPU核心数量一致呢?这正是Nginx 与 Apache服务器的不同之处。在Apache 上每个进程在一个时刻只处理一个请求,因此,如果希望Web服务器拥有并发处理的请求数更多,就要把Apache的进程或线程数设置得更多,通常会达到一台服务器拥有几百个工作进程,这样大量的进程间切换将带来无谓的系统资源消耗。而Nginx则不然,一个worker进程可以同时处理的请求数只受限于内存大小,而且在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程通常不会进入睡眠状态,因此,当Nginx 上的进程数与CPU核心数相等时(最好每一个worker进程都绑定特定的CPU核心),进程间切换的代价是最小的。
6、nginx性能优化
随着访问量的不断增加,需要对Nginx和内核做相应的优化来满足高并发用户的访问,那下面在单台Nginx服务器来优化相关参数。
1)Nginx.conf配置优化:
worker_processes 8;
nginx进程数,建议按照cpu数目来指定,一般为它的倍数。
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000
00100000 01000000 10000000;
为每个进程分配cpu,上例中将8个进程分配到8个cpu,当然可以写多个,或者将一
个进程分配到多个cpu。
worker_rlimit_nofile 102400;
这个指令是指当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打
开文件数(ulimit -n)与nginx进程数相除,但是nginx分配请求并不是那么均匀
,所以最好与ulimit -n的值保持一致。
use epoll;
使用epoll的I/O模型。epoll是Linux内核为处理大批量文件描述符而作了改进的
poll,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用
率。
worker_connections 102400;
每个进程允许的最多连接数,理论上每台nginx服务器的最大连接数为
worker_processes*worker_connections。
keepalive_timeout 60;
keepalive超时时间,客户端到服务器端的连接持续有效时间,当出现对服务器的后
继请求时,keepalive-timeout功能可避免建立或重新建立连接。
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
时间内一次没被使用,它将被移除。
2)linux文件打开最大数
vi /etccuritymits.conf
* soft nproc 65535
* hard nproc 65535
* soft nofile 65535
* hard nofile 65535
为了防止失控的进程破坏系统的性能,Unix和Linux跟踪进程使用的大部分资源,允许用户和系统管理员使用对进程的资源限制,设置的限制有两种: 硬限制和软限制:
hard硬限制是可以在任何时候任何进程中设置 但硬限制只能由超级用户修改。
soft软限制是内核实际执行的限制,任何进程都可以将软限制设置为任意小于等于对进程限制的硬限制的值,(noproc)最大线程数和(nofile)文件数。
3)Linux内核参数优化
vi /etc/sysctl.conf
net.ipv4.tcp_max_tw_buckets = 6000
timewait的数量,默认是180000。
net.ipv4.ip_local_port_range = 1024 65000
允许系统打开的端口范围。
net.ipv4.tcp_tw_recycle = 1
启用timewait快速回收。
net.ipv4.tcp_tw_reuse = 1
开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接。
net.ipv4.tcp_syncookies = 1
开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies来处理。
net.core.somaxconn = 262144
web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。
net.core.netdev_max_backlog = 262144
每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.ipv4.tcp_max_orphans = 262144
系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。这个限制仅仅是为了防止简单的DoS攻击,不能过分依靠它或者人为地减小这个值,更应该增加这个值(如果增加了内存之后)。
net.ipv4.tcp_max_syn_backlog = 262144
记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言,缺省值是1024,小内存的系统则是128。
net.ipv4.tcp_timestamps = 0
时间戳可以避免序列号的卷绕。一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉。
net.ipv4.tcp_synack_retries = 1
为了打开对端的连接,内核需要发送一个SYN并附带一个回应前面一个SYN的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。
net.ipv4.tcp_syn_retries = 1
在内核放弃建立连接之前发送SYN包的数量。
net.ipv4.tcp_fin_timeout = 1
如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60秒。2.2 内核的通常值是180秒,你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2的危险性比FIN-WAIT-1要小,因为它最多只能吃掉1.5K内存,但是它们的生存期长些。
net.ipv4.tcp_keepalive_time = 30
当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时。
7、IO模型原理
-
A、Blocking I/O(阻塞)
同步阻塞IO:在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式! -
B、Non-Blocking I/O(非阻塞)
同步非阻塞IO:在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。 -
C、I/O Multiplexing(多路复用)
异步非阻塞IO:在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。目前Java中还没有支持此种IO模型。 -
D、Asynchronous I/O(异步)
异步阻塞IO:此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为什么说是阻塞的呢?
因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄,从而提高系统的并发性!
nginx掌握多练多思考根据服务器的配置而配置调到最优性能就好!