优化那些事儿

生产环境下网站做前期的优化肯定是比不可少的,简单来说就是用同等条件的硬件资源,处理更多的网站业务,大程度提供网站业务处理能力;前辈留下的实战经验可都是财富,好多坑只有踩过才知道痛,下面就来漫谈下优化的那些事儿

修改系统Ulimit

网站优化,首先要做的是先对系统进行优化,上线的服务器经常是用Linux系统做的;而在Linux下面部署应用的时候,有时候会遇上Socket/File: Can’t open so many files的问题;这是因为Linux是有文件句柄限制的,而且Linux默认不是很高,一般都是1024,这个值也会影响服务器的最大并发数(每个连接都是打开一个文件描述符),生产服务器这个值肯定是不够的;先做个测试看看ulimit的重要性

查看ulimit值:

[root@localhost ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7671
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7671
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

其中 "open files (-n) 1024 "是Linux操作系统对一个进程打开的文件句柄数量的限制(也包含打开的socket数量,可影响所有底层用到socket的服务,包括MySQL等)

进行ab压力测试:

[root@bogon ~]# ab -n 2000 -c 1000 http://192.168.20.219/paperindex.htm

#发起1000个并发连接,共2000次请求

ab工具下载-》》windows:https://pan.baidu.com/s/1skNwUKH  Linux:yum -y install httpd  默认在/usr/bin/ab下

统计日志:

[root@localhost logs]# cat host.access.log | wc -l
2001
[root@localhost logs]# awk '{print $4}' host.access.log | grep 500 | wc -l
874
[root@localhost logs]# awk '{print $4}' host.access.log | grep 200 | wc -l
1127

web端一共收到2000次请求,200状态码的正常访问1127次,其余800多次客户端访问抛出500异常,未能提供正常响应

修改ulimit:

ulimit -n 65535 暂时生效      ##也可为655360
若要令修改ulimits的数值永久生效,则必须修改配置文档,可以给ulimit修改命令放入/etc/profile里面,这个方法实在是不方便 还有一个方法是修改/etc/security/limits.conf
[root@localhost ~]# vim /etc/security/limits.conf
文件里面有很详细的注释,比如
* soft nofile 65535 * hard nofile 65535
星号代表全局, soft为软件,hard为硬件,nofile为这里指可打开文件数。
把以上两行内容加到 limits.conf文件中即可 另外,要使 limits.conf 文件配置生效,必须要确保 pam_limits.so 文件被加入到启动文件中。查看 /etc/pam.d/login 文件中有:
[root@localhost ~]# vim /etc/pam.d/login
session required /lib/security/pam_limits.so 修改完重新登录就可以见到效果,可以通过 ulimit -n 查看 重启nginx服务
[root@localhost ~]# ulimit -n
65535

重新做压力测试:

[root@bogon ~]# ab -n 100000 -c 10000 http://192.168.20.219/paperindex.htm

Benchmarking 192.168.20.219 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests

直接发送100000次请求,10000并发

统计日志:

[root@localhost logs]# cat host.access.log |wc -l
101337
[root@localhost logs]# awk '{print $4}' host.access.log |grep 200 |wc -l
101337

web端一共收到101337次请求,所有请求状态200正常

限制访问连接

生产环境下很多情况是不对访问做限制,但也有特殊状况,比如部署个网络投票评选平台,会有恶意刷票的情况出现,刷票会占用大量系统资源,影响其他正常的访问,这时就需要对访问的IP进行并发数或者访问频率进行限制

nginx有两个模块可以控制访问

  • limit_conn_zone   限制同时并发访问的数量
  • limit_req_zone     限制访问数据,每秒内最多几个请求

但具体有什么不同呢?下面是 nginx 官网上抛出的解释

limit_conn_zone
Limit simultaneous connections from a client.
This module makes it possible to limit the number of simultaneous connections for the assigned session or as a special case, from one address. limit_req_zone
Limit frequency of connections from a client.
This module allows you to limit the number of requests for a given session, or as a special case, with one address.
Restriction done using leaky bucket.

按照字面的理解

  • limit_conn_zone 功能是限制一个客户端的并发连接数(这个模块可以限制单个地址 的指定会话 或者特殊情况的并发连接数)
  • lit_req_zone的功能是通过漏桶原理来限制用户的连接频率(这个模块允许你去限制单个地址 指定会话或特殊需要 的请求数 )

一个是限制并发连接一个是限制连接频率,表面上似乎看不出来有什么区别,那就直接看效果如何

测试limit_conn_zone修改配置文件:

http {
include mime.types;
default_type application/octet-stream; limit_conn_zone $remote_addr zone=James_conn:10m ; limit_conn James_conn 1; ..............
}

limit_zone James_conn  $binary_remote_addr  10m;这里的James_conn是声明一个 limit_zone 的名字,$remote_addr是客户端的IP,10m是会话状态储存的空间,1M大概可以保存16000IP
limit_conn James_conn 1 ;限制客户端并发连接数量为1

并发测试:

[root@bogon ~]# ab -n 20 -c 10 http://192.168.20.219/paperindex.htm

#10个并发,20个请求

log日志:

分析日志20次的请求中不只一次返回200,多测试几次依然如此,看来此模块也不一定能限制的住1秒钟1个并发连接,但还是拒绝了大多数的访问

后续:

又对服务器进行了10000并发10000次请求

[root@bogon ~]# ab -n 10000 -c 10000 http://192.168.20.219/paperindex.htm

日志结果:

短时间内大的并发量处理还是有效果的

测试limit_req_zone修改配置文件:

http {
include mime.types;
default_type application/octet-stream; limit_req_zone $remote_addr zone=req_James:10m rate=1r/s; ......................................
server {
listen 80;
server_name localhost;
limit_req zone=req_James burst=120 nodelay; ...........................
}
}

简单说明一下, rate=1r/s 的意思是每个地址每秒只能请求一次,也就是说根据漏桶原理 burst=120 一共有120块令牌,并且每秒钟只新增1块牌,120块令牌发完后就不会再响应 ,加上nodelay之后超过 burst大小的请求就会直接返回503,而不是在后台进行排队等待
连接频率测试:

[root@bogon ~]# ab -n 10000 -c 1000 http://192.168.20.219/paperindex.htm

#1000并发的10000次请求

整个测试过程大概花了4秒钟,也就在一共可以正常的访问124次左右

log日志:

几乎全是503错误,再对日志进行统计

126次正常访问,9949次503错误,结果跟我们猜想的清楚差不多,说明这个模块真的还蛮好用的

番外:根据真实IP做限制

##取用户的真实IP

 map $http_x_forwarded_for  $clientRealIp {
## 没有通过代理,直接用 remote_addr
"" $remote_addr;
## 用正则匹配,从 x_forwarded_for 中取得用户的原始IP
## 例如 X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...## 这里第一个 202.123.123.11 是用户的真实IP,后面其它都是经过的 CDN 服务器
~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr;
}
## 通过 map 指令,我们为 nginx 创建了一个变量 $clientRealIp ,这个就是 原始用户的真实 IP 地址,
## 不论用户是直接访问,还是通过一串 CDN 之后的访问,我们都能取得正确的原始IP地址 ## 每秒并发连接限制
limit_conn_zone $clientRealIp zone=TotalConnLimitZone:10m ; ## 每秒请求数限制
limit_req_zone $clientRealIp zone=ConnLimitZone:10m rate=10r/s; #未经过测试 以后有时间再做

  

  

优化配置文件突破十万并发

#user  nobody;
worker_processes auto; ##允许Nginx进程生成的worker process数 根据cpu内核数自动生成 worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
#为每个进程分配cpu,上例中将8 个进程分配到8 个cpu,当然可以写多个,或者将一个进程分配到多个cpu #error_log logs/error.log
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid; worker_rlimit_nofile 102400;
#这个指令是指当一个nginx 进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx 进程数相除,
#但是nginx 分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致 events {
use epoll; ##配置事件驱动模型,使用epoll 的I/O 模型
worker_connections 102400; ##配置最大连接数,每个进程允许的最多连接数,理论上每台nginx 服务器的最大连接数
#为worker_processes*worker_connections
} http {
include mime.types; ##定义MIME-Type
default_type application/octet-stream;
log_format main '$remote_addr - [$time_local] - "$request"' ##定义日志类型,远程地址、时间、请求内容、请求状态、cookie值
' - $status' $http_cookie; types_hash_max_size 2048; ##多servername需设置
client_header_buffer_size 4k; ##客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求
#头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE 取得
open_file_cache max=102400 inactive=20s;
#这个将为打开文件指定缓存,默认是没有启用的,max 指定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存
open_file_cache_valid 30s;
#这个是指多长时间检查一次缓存的有效信息
server_names_hash_bucket_size 512;
sendfile on;
server_tokens off; ##关闭默认版本号
keepalive_timeout 20; ##定义链接超时时间,防止慢速dos攻击
client_header_timeout 15; ##请求头超时时间
client_body_timeout 15; ##请求体超时时间
reset_timedout_connection on; ##关闭不响应的客户端连接,释放客户端占有内存
send_timeout 10; ##客户端两次读取时间,如果这段时间里没有读取任何数据,nginx就会关闭连接 ########################内核优化#####################
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 秒,3你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB 服务器,
#也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2 的危险性比FIN-WAIT-1 要小,因为它最多只能吃掉1.5K 内存,但是它们的生存期长些。
net.ipv4.tcp_keepalive_time = 30
当keepalive 起用的时候,TCP 发送keepalive 消息的频度。缺省是2 小时。 server { ##直接访问IP 反馈500错误
listen 80 default;
return 500;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
} server {
listen 80;
server_name www.test.com www.test.com.cn;
#rewrite域名跳转
if ($host != 'www.test.com' ) {
rewrite ^/(.*)$ http://www.test.com/$1 permanent; #调转
}
access_log /data/web_log/test/access.log main;
error_log /data/web_log/test/error.log debug; #设置cookie值
if ($http_cookie ~* "(.*)$"){
#if ($http_cookie ~* "JCRB_VOTE=([A-Z0-9]*)"){
set $guid $1;
} #当访问.txt结尾的文件时向/data/yanz目录里找
location ~ \.txt$ {
root /data/yanz;
} location / {
root /data/test;
index index.html index.xml;
ssi on;
ssi_silent_errors on;
ssi_types text/shtml;
} error_page 404 /404.html;
location = /404.html {
root html;
} error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
} } }

  

  

NGINX:漫谈优化的更多相关文章

  1. nginx + SSL优化配置

    nginx + SSL优化配置: #http段添加如下配置项: http { ssl_prefer_server_ciphers on; #设置协商加密算法时,优先使用我们服务端的加密套件,而不是客户 ...

  2. nginx 配置优化的几个参数

    nginx 配置优化的几个参数 2011-04-22 本文地址: http://blog.phpbean.com/a.cn/7/ --水平有限欢迎指正-- -- 最近在服务器上搞了一些nginx 研究 ...

  3. 【实战分享】又拍云 OpenResty / Nginx 服务优化实践

    2018 年 11 月 17 日,由 OpenResty 主办的 OpenResty Con 2018 在杭州举行.本次 OpenResty Con 的主题涉及 OpenResty 的新开源特性.业界 ...

  4. [Nginx] – 性能优化 – 配置文件优化

    Nginx基本安全优化 1.调整参数隐藏Nginx版本号信息     一般来说,软件的漏洞都和版本有关,因此我们应尽量隐藏或清除Web服务队访问的用户显示各类敏感信息(例如:Web软件名称及版本号等信 ...

  5. Nginx配置项优化详解【转】

    (1)nginx运行工作进程个数,一般设置cpu的核心或者核心数x2 如果不了解cpu的核数,可以top命令之后按1看出来,也可以查看/proc/cpuinfo文件 grep ^processor / ...

  6. Nginx软件优化【转】

    转自 Nginx软件优化 - 惨绿少年 - 博客园 Nginx软件优化 - 惨绿少年 - 博客园 https://www.cnblogs.com/clsn/p/8484559.html 1.1 Ngi ...

  7. Nginx软件优化

    1.1 Nginx优化分类 安全优化(提升网站安全性配置) 性能优化(提升用户访问网站效率) 1.2 Nginx安全优化 1.2.1 隐藏nginx版本信息优化 官方配置参数说明:http://ngi ...

  8. nginx配置文件优化

    nginx配置优化     #定义Nginx运行的用户和用户组user  www  www: #启动工作进程,通常设置成和cpu的数量相等worker_processes  8:   最多开启8个,8 ...

  9. Nginx配置优化参考

    Nginx配置优化参考                                                                                          ...

随机推荐

  1. Linux中利用LVM实现分区动态扩容

    使用命令: pvscan vgdisplay lvdisplay vgremove vgextend lvresize -l resize2fs 从物理磁盘,创建lvm逻辑分区 pvcreate vg ...

  2. 调用外部 DLL 中的函数(1. 早绑定)

    ,b,t,);end; end.

  3. ubuntu-12.04.5-desktop-amd64.iso:ubuntu-12.04.5-desktop-amd64:安装Oracle11gR2

    ubuntu 桌面版的安装不介绍. 如何安装oracle:核心步骤和关键点. ln -sf /bin/bash /bin/sh ln -sf /usr/bin/basename /bin/basena ...

  4. Unity的加载路径

    1.Resources 路径 只读 不能动态的修改 存放内容 预制体(prefabs) - 不容易变化的预制体 prefabs打包的时候 会自动过滤不需要的资源 有利于减小资源大小 主线程加载 Res ...

  5. [转载]2014年10月26完美世界校招两道java题

    public class VolitileTest { volatile static int count=0; public static void main(String args[]){ for ...

  6. 面试题思考:Servlet 生命周期、工作原理

    Servlet 生命周期:Servlet 加载--->实例化--->服务--->销毁. init():在Servlet的生命周期中,仅执行一次init()方法.它是在服务器装入Ser ...

  7. php学习六:字符串

    前言:越来越觉得php的强大之处了,不紧是数组,在字符串方面也可以看出它的优势,第一:方法多,集合了js,c,c#等多门语言的方法:第二:有许多方法是其他语言不具备的,如他的模糊比较,就是其他语言所没 ...

  8. Android 使用ListView显示信息列表

    课程目标1.理解ListView的基础使用2.学会熟练运用两种适配器(ArrayAdapter.SimpleAdapter)3.学会熟练运用两种监听器(OnScrollListener.OnItemC ...

  9. JAVA中替换字符的方法replace和replaceAll 区别

    replace和replaceAll是JAVA中常用的替换字符的方法,它们的区别是:1)replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSe ...

  10. Oracle12cWindows安装、介绍及简单使用(图文)

    1.下载 地址为:http://www.oracle.com/technetwork/cn/database/enterprise-edition/downloads/index.html 含企业版和 ...