Nginx性能调优,解决C10K问题

  • Post author:
  • Post category:其他

        公司的技术总监最近出了一道架构方面的问题让我们同组的开发人员设计,题目是这样的:有个签到功能,需要记录每个⽤户每年每⼀天的签到情况。假设⽤户量在千万,甚⾄亿级,该如何设计。

思考这个问题后,我给出的设计方案如下:

第一层:通过DNS,同一个域名绑定多个IP,在DNS上进行负载均衡。

第二层:中央Nginx集群,通过DNS负载均衡后,通过nginx二次负载均衡(Nginx的配置需要根据服务器配置调整,比如连接数,进程数等);

第三层:web层,将应用部署在多个节点上。

第四层:消息引擎层,将上层数据写入消息引擎中,consumer端将数据异步入库,建议使用kafka,吞吐量大。

第五层:数据库层,数据量庞大,传统的关系型数据库已经不太适用,即使通过水平分库分表,按日期或按userid分库,也很难解决存储和跨多库的查询问题。可以考虑使用MongoDB或大数据技术(HDFS和HBASE)来存储签到数据。

不知道合不合理,但总的设计理念是:负载均衡+异步。同时也要在Nginx和Linux内核方面进行优化,以抵抗更大的压力。

        下面,我将从Nginx的配置和Linux内核配置方面,讲解Nginx性能调优。

Nginx配置

总览Nginx的配置,我就不多做解释了,如果大家对Nginx的安装或各模块不太了解请自行百度。

...              #全局块

events {         #events块
   ...
}

http      #http块
{
    ...   #http全局块
    server        #server块
    { 
        ...       #server全局块
        location [PATTERN]   #location块
        {
            ...
        }
        location [PATTERN] 
        {
            ...
        }
    }
    server
    {
      ...
    }
    ...     #http全局块
}

Nginx的优化

常用的Nginx的配置参数有下:

 worker_processes 8;

Nginx工作进程数,一般配置为CPU的核数。

worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

这个参数有意思,为每个进程分配cpu。配置此参数要根据cpu核数和worker_processes;例如:

两核cpu,开启两个进程
worker_processes 2;
worker_cpu_affinity 01 10;

两核cpu,开启4个进程
worker_processes 2;
worker_cpu_affinity 01 10 01 10;

四核cpu,开启四个进程
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;

4核cpu,开启2个进程
worker_processes     2;
worker_cpu_affinity 0101 1010;

8核cpu,开启8个进程
worker_processes     8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
worker_rlimit_nofile 65535;

一个Nginx进程打开最多文件描述符的个数,从理论上讲,这个值应该设置为(ulimit -n)/worker_processes,即Linux打开的最多文件描述符个数/Nginx工作进程数,但Nginx的请求分配并不是那么均衡,所以将此值设置为(ulimit -n)的值。若此值设置的较小,并发较大时会报错。

events {
    use epoll; #使用epoll事件驱动,因为epoll的性能相比其他事件驱动要好很多
}
worker_connections 65535;

每个Nginx进程的连接数,理论上一个Nginx服务器允许的最大的连接数是worker_processes*worker_commections;

keepalive_timeout 60;

keppalive的超时时间。

client_header_buffer_size 4k;

请求头缓冲取大小,这个要根据Linux的系统分页来配置,查看Linux的分页大小的命令: getconf PAGESIZE

open_file_cache max=65535 inactive=60s;
open_file_cache_valid 80s;
open_file_cache_min_uses 1;

open_file_cache,这个将为打开文件指定缓存,默认是没有启用的,max 指定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存。
open_file_cache_valid,这个是指多长时间检查一次缓存的有效信息。
open_file_cache_min_uses,是open_file_cache 指令中的inactive 参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive 时间内一次没被使用,它将被移除。

 

当然,Nginx的优化不仅仅上面的参数,比如,对各种buffer缓冲、数据gzip压缩、静态文件缓存cache等等进行配置。

 

Linux内核的优化

net.ipv4.tcp_max_tw_buckets = 6000

表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000,建议减小,避免TIME_WAIT状态过多消耗整个服务器的资源,但也不能太小,跟你后端的处理速度有关,如果速度快可以小,速度慢则适当加大,否则高负载会有请求无法响应或非常慢。

net.ipv4.ip_local_port_range = 1024 65000

允许系统打开的端口范围。

net.ipv4.tcp_tw_recycle = 0

启用timewait 快速回收,1为开启。网上对这个字段争议很大,但我建议最好设置为0不要开启,请参考不要在linux上启用net.ipv4.tcp_tw_recycle参数优化内核时的坑,切记不要启用net.ipv4.tcp_tw_recycle

net.ipv4.tcp_tw_reuse = 1

开启重用。允许将TIME-WAIT sockets 重新用于新的TCP 连接。

net.ipv4.tcp_syncookies = 1

开启SYN Cookies,当出现SYN 等待队列溢出时,启用cookies 来处理。可防范少量SYN攻击,默认为0,表示关闭。

net.core.somaxconn = 262144

挂起请求的最大数量.默认是128.对繁忙的服务器,增加该值有助于网络性能.可调整到8192/16384/32768。

net.core.netdev_max_backlog = 262144

每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。

net.ipv4.tcp_max_orphans = 262144

系统所能处理不属于任何进程的TCP sockets最大数量。假如超过这个数量,那么不属于任何进程的连接会被立即reset,并同时显示警告信息。之所以要设定这个限制,纯粹为了抵御那些简单的 DoS 攻击,千万不要依赖这个或是人为的降低这个限制。
缺省设置:8192

net.ipv4.tcp_max_syn_backlog = 262144

表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

net.ipv4.tcp_timestamps = 0

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 小时。

 

经过上面的一系列优化,你的Nginx就可以抗压了。


版权声明:本文为nuoWei_SenLin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。