文件描述符和最大进程数
ulimit的使用
ulimit
#-a 列出所有当前资源极限
#-n 每个进程可以同时打开的最大文件数
#-u 可以运行的最大并发进程数
#-S 设置软限制
#-H 设置硬限制
在命令行直接执行该命令只会在当前shell生效,退出或者新开一个shell都会无效,所以可以加入到全局设置中:
/bin/echo "ulimit -SHn 65535" >> /etc/profile
有时候为了方便起见,也可以将用户资源的限制统一由一个文件来配置
这个文件就是/etc/security/limits.conf,该文件不但能对指定用户的资源进行限制,还能对指定组的资源进行限制。
echo "* hard nofile 65535" >>/etc/security/limits.conf
echo "* soft nofile 65535" >>/etc/security/limits.conf
echo "* soft nproc 65535" >>/etc/security/limits.conf
echo "* hard nproc 65535" >>/etc/security/limits.conf
需要注意的是,在centos系统中,除了/etc/security/limits.conf文件外,还有一个文件/etc/security/limits.d/20-nproc.conf(centos7.x系统),
/etc/security/limits.d/90-nproc.conf(centos6.x系统),这个文件中,对nproc设置了一个默认值,
并且是针对所有系统用户设置的。而如果在/etc/security/limits.conf文件中也设置了nproc值的话,
则会被覆盖,也就是说/etc/security/limits.d/里面的文件的配置会覆盖/etc/security/limits.conf的配置。
所以最好是删除该文件或者修改或者屏蔽该文件内容:
/bin/sed -i 's/1024/65535/g' /etc/security/limits.d/90-nproc.conf
或者:
rm -f /etc/security/limits.d/90-nproc.conf
TCP/IP协议
3次握手4次挥手
3次握手原理:
第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后客户端进入SYN_SENT状态,等待服务器的确认;
第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);
同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
4次挥手原理:
第一次挥手: 主机A(可以使客户端,可以是服务器端),设置Sequence Number和Acknowledgment Number,向主机B发送一个FIN报文段;
此时,主机A进入FIN_WAIT_1状态;这表示主机A没有数据要发送给主机B;
第二次挥手:主机B收到了主机A发送的FIN报文段,向主机A回一个ACK报文段,Acknowledgment Number为Sequence Number加1;
主机A进入FIN_WAIT_2状态;主机B告诉主机A,我“同意”你的关闭请求;
第三次挥手:主机B向主机A发送FIN报文段,请求关闭连接,同时主机B进入LAST_ACK状态;
第四次挥手:主机A收到主机B发送的FIN报文段,向主机B发送ACK报文段,然后主机A进入TIME_WAIT状态;
主机B收到主机A的ACK报文段以后,就关闭连接;此时,主机A等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机A也可以关闭连接。
Linux内核参数优化
Linux /proc/sys目录下存放着多数内核的参数,并且可以在系统运行时进行更改,一般重新启动机器就会失效。而/etc/sysctl.conf是一个允许改变正在运行中的Linux系统的接口,它包含一些TCP/IP堆栈和虚拟内存系统的高级选项,修改内核参数永久生效。
/proc/sys下内核文件与配置文件sysctl.conf中变量存在着对应关系,即修改sysct.conf配置文件,其实是修改/proc/sys相关参数,所以对Linux内核优化只需修改/etc/sysctl.conf文件即可
示例
生产环境/etc/sysctl.conf内核参数
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.tcp_max_tw_buckets = 10000
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 16384 4194304
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 262144
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_keepalive_time = 30
net.ipv4.ip_local_port_range = 1024 65535
参数详解:
net.ipv4.ip_forward = 0 # 是否开启内核转发1开启
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
#是否接受含有源路由信息的ip包。参数值为布尔值,1表示接受,0表示不接受。
#在充当网关的linux主机上缺省值为1,在一般的linux主机上缺省值为0。
#从安全性角度出发,建议你关闭该功能。
kernel.sysrq = 0 # 关闭sysrq魔术组合键,具体可以上网查看这个的功能,一般用不到
kernel.core_uses_pid = 1 #在生成的core文件名中加入进程id,core主要用于应用程序奔溃或者异常是产生,用于分析,默认参数与应用文件同目录下
net.ipv4.tcp_syncookies = 1 #防洪水***
kernel.msgmnb = 65536 #每个消息队列的最大字节限制。该文件指定一个消息队列的最大长度(bytes)。
kernel.msgmax = 65536 #该文件指定了从一个进程发送到另一个进程的消息最大长度。进程间的消息传递是在内核的内存中进行的。不会交换到硬盘上。所以如果增加该值,则将增加操作系统所使用的内存数量。
kernel.shmmax = 68719476736 #该参数定义了共享内存段的最大尺寸(以字节为单位)。默认是32M。
kernel.shmall = 4294967296 #该参数表示统一一次可以使用的共享内存总量(以页为单位)。默认是2097152,通常不需要修改。
net.ipv4.tcp_max_tw_buckets = 10000
#系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息;
#默认为180000,设为较小数值此项参数可以控制TIME_WAIT套接字的最大数量,避免服务器被大量的TIME_WAIT套接字拖死;
net.ipv4.tcp_sack = 1 #选择性应答(SACK)是 TCP 的一项可选特性,可以提高某些网络中所有可用带宽的使用效率;
net.ipv4.tcp_window_scaling = 1 #启用RFC 1323定义的window scaling,要支持超过64KB的TCP窗口,必须启用该值(1表示启用),TCP窗口最大至1GB,TCP连接双方都启用时才生效。
net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 16384 4194304
#为每个TCP连接分配的读、写缓冲区内存大小,单位是Byte
#第一个数字表示,为TCP连接分配的最小内存
#第二个数字表示,为TCP连接分配的缺省内存
#第三个数字表示,为TCP连接分配的最大内存
#一般按照缺省值分配
net.core.wmem_default = 8388608 #该参数指定了发送套接字缓冲区大小的缺省值(以字节为单位)
net.core.rmem_default = 8388608 #指定了接收套接字缓冲区大小的缺省值(以字节为单位)。
net.core.rmem_max = 16777216 #指定了接收套接字缓冲区大小的最大值(以字节为单位)。
net.core.wmem_max = 16777216 #该参数指定了发送套接字缓冲区大小的最大值(以字节为单位)
net.core.netdev_max_backlog = 262144 #该参数决定了,网络设备接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.core.somaxconn = 262144 #Linux kernel参数,表示socket监听的backlog(监听队列)上限
net.ipv4.tcp_max_orphans = 3276800 #系统所能处理不属于任何进程的TCP sockets最大数量(孤儿套接字);
net.ipv4.tcp_max_syn_backlog = 262144 #表示SYN队列长度,默认1024,改成8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_timestamps = 0 #该参数控制RFC 1323 时间戳与窗口缩放选项;时间戳可以避免序列号的卷绕。一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种"异常"的数据包。这里需要将其关掉。
net.ipv4.tcp_synack_retries = 1 #tcp_synack_retries显示或设定Linux在回应SYN要求时尝试多少次重新发送初始SYN,ACK封包后才决定放弃;
net.ipv4.tcp_syn_retries = 1 #对于一个新建连接,内核要发送多少个SYN 连接请求才决定放弃;
net.ipv4.tcp_tw_recycle = 1 #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1 #表示开启重用,允许将TIME-WAIT sockets重新用于新的TCP连接;
net.ipv4.tcp_mem = 94500000 915000000 927000000
#内核分配给TCP连接的内存,单位是Page,1 Page = 4096 Bytes,可用命令查看:
getconf PAGESIZE
4096
#第一个数字表示,低于此值,TCP没有内存压力
#第二个数字表示,在此值下,进入内存压力阶段;kernel 会进入 “memory pressure” 压力模式
#第三个数字表示,高于此值,TCP拒绝分配socket;就会报:Out of socket memory
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 #如果某个TCP连接在空闲30秒后,内核才发起probe(探查);
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 3
#如果probe 3次(每次3秒既tcp_keepalive_intvl值)不成功,内核才彻底放弃,认为该连接已失效;
net.ipv4.ip_local_port_range = 1024 65535 #表示用于向外连接的端口范围;
net.ipv4.icmp_echo_ignore_broadcasts = 1 # 避免放大***
net.ipv4.icmp_ignore_bogus_error_responses = 1 # 开启恶意icmp错误消息保护
net.ipv4.netfilter.ip_conntrack_max=655360 #在内核内存中netfilter可以同时处理的“任务”(连接跟踪条目);centos6:net.nf_conntrack_max = 655360
#注意使用该参数时需要事先加载该模块modprobe ip_conntrack
net.ipv4.tcp_orphan_retries = 0 #孤儿socket废弃前重试的次数,重负载web服务器建议调小
net.ipv4.tcp_retries2 = 2 #活动TCP连接重传次数,超过次数视为掉线,放弃连接。缺省值:15,建议设为 2或者3.
net.ipv4.tcp_retries1 = 3 #放弃回应一个TCP 连接请求前﹐需要进行多少次重试;
net.ipv4.route.gc_timeout = 100 #路由缓存刷新频率,当一个路由失败后多长时间跳到另一个路由,默认是300。
DDOS
完整的TCP连接的三次握手,假设一个用户A向服务器发送了SYN报文后突然死机或掉线,那么服务器在发出SYN+ACK应答报文后是无法收到客户端的ACK报文的(第三次握手无法完成),这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级(大约为30秒-2分钟)。
一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源,数以万计的半连接,即使是简单的保存并遍历也会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。
实际上如果服务器的TCP/IP栈不够强大,最后的结果往往是堆栈溢出崩溃,即使服务器端的系统足够强大,服务器端也将忙于处理者伪造的TCP连接请求而无暇理睬客户的正常请求(毕竟客户端的正常请求比率非常之小),此时从正常客户的角度看来,服务器失去响应,服务器拒绝提供服务,服务器受到了DDOS,这里的手段为DDOS中SYN Flood(SYN洪水)。
查看系统TCP连接
netstat -an | awk '/tcp/ {s[$NF]++} END {for(a in s) {print a,s[a]}}'
netstat -an | awk '/tcp/ {print $NF}' | sort | uniq -c
如果处于SYN_RECV 状态太多,就有可能是遭受syn洪水