前言:最近在研究服务器初始化和内核参数调优,翻阅了大量文档,尽量做到每个参数都能有详细的解释,而不是捡一篇通用调优配置就上到服务器上去。
个人愚见:关于内核参数调优方面,安全应该是第一位的,性能可以通过架构设计再做调整。没有通用性的调优,具体调优要根据生产的业务为主导,对一项内核参数进行更改时,应该要了解该参数的作用,而不是复制粘贴,否则可能出现负优化,甚至是出现未知的故障。
cat > /etc/sysctl.conf
kernel.pid_max = 65535
vm.min_free_kbytes = 65535
kernel.kptr_restrict = 1
fs.file-max = 100000
vm.dirty_ratio = 20
vm.dirty_background_ratio = 10
kernel.shmmax = 68719476736
kernel.shmall = 3145728
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_rmem = 8192 87380 16777216
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.ipv4.tcp_wmem = 8192 65536 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
net.core.somaxconn = 16384
net.core.netdev_max_backlog = 16384
net.core.optmem_max = 65535
net.ipv4.tcp_max_tw_buckets = 65535
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 16384
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_fastopen = 3
以下部分内容是对上述部分参数的详细解释
kernel.pid_max = 65535
该值为全局变量,max user processes 的值受该值影响,默认的pid_max
值为32768,正常情况下是够用的,但在耗尽系统的pid资源时,会报出fork:retry: Resource temporarily
unavailable的错误。
内核允许系统创建的最大进程数,这个值在64位机上最大可设置为4194304,在ceph集群中启动多个OSD的主机上可能会产生大量的线程,建议调大该值
vm.min_free_kbytes = 65535
为了防止缓存将所有的内存全部耗尽,而导致其他程序无法申请到内存而崩溃 为了避免在ceph
集群在OSD进行内存分配的请求时遇到内存不足相关的问题,可以适当调大该参数。对于线上128G的内存的机器,可以考虑将min设置为536870(总内存x0.4%x1024x1024≈参考值)。具体优化也要根据业务来看,调大的风险远大于调小的风险。
kernel.kptr_restrict = 1
kptr_restrict == 2:内核将符号地址打印为全0,root和普通用户都没有权限. kptr_restrict ==
1:root用户有权限读取,普通用户没有权限. kptr_restrict == 0:root和普通用户都可以读取.默认值
阿里云安骑士检查服务器的时候发现了的一个配置项问题,内核地址以%p打印时无论在什么情况下都会以HASH地址方式打印,而%pK可以通过
变量kptr_restrict隐藏内核地址,防止内核地址泄漏。建议修改为1
fs.file-max = 100000
系统级别的能够打开的文件句柄的数量。是对整个系统的限制,并不是针对用户的
#遇到文件句柄达到上限时,会碰到"Too many open files"或者Socket/File: Can’t open so many files等错误,对于服务器来说,file-max和ulimit都需要设置,否则会出现文件描述符耗尽的问题
通常来说,如果机器的内存越大,那么file-max的默认值也会越大
This file defines a system-wide limit on the number of open files for all processes. (See also setrlimit(2), which can be
used by a process to set the per-process limit, RLIMIT_NOFILE, on the
number of files it may open.) If you get lots of error
messages in the kernel log about running out of file handles (look for “VFS: file-max limit reached”), try
increasing this value:
echo 100000 > /proc/sys/fs/file-max
vm.dirty_ratio = 20
使用vm.dirty_ratio和vm.dirty_background_ratio更好的Linux磁盘缓存和性能(脏页是linux内核中的概念,因为硬盘的读写速度远赶不上内存的速度,系统就把读写比较频繁的数据事先放到内存中,以提高读写速度,这就叫高速缓存,linux是以页作为高速缓存的单位,当进程修改了高速缓存里的数据时,该页就被内核标记为脏页,内核将会在合适的时间把脏页的数据写到磁盘中去,以保持高速缓存中的数据和磁盘中的数据是一致的)是绝对的脏数据限制,内存里的脏数据百分比不能超过这个值。如果脏数据超过这个数量,新的IO请求将会被阻挡,直到脏数据被写进磁盘。这是造成IO卡顿的重要原因,但这也是保证内存中不会存在过量脏数据的保护机制
vm.dirty_background_ratio = 10
是内存可以填充“脏数据”的百分比。这些“脏数据”在稍后是会写入磁盘的,pdflush/flush/kdmflush这些后台进程会稍后清理脏数据。举一个例子,我有32G内存,那么有3.2G的内存可以待着内存里,超过3.2G的话就会有后来进程来清理它
通过设置vm.dirty_ratio参数可以增加被内核进程刷新到磁盘之前的脏页数量,可以在Kafka集群运行期间检查脏页的数量来计算最恰当的值,不管是在生产环境还是在模拟环境。
kernel.shmmax = 12884901887
64 位 linux 系统:可取的最大值为物理内存值 -1byte ,建议值为多于物理内存的一半,一般取值大于 SGA_MAX_SIZE
即可,可以取物理内存 -1byte 。 计算方式(内存10241024*1024-1)
kernel.shmall = 3145728
该参数控制可以使用的共享内存的总页数。 Linux 共享内存页大小为 4KB, 共享内存段的大小都是共享内存页大小的整数倍。(一个共享内存段的最大大小是 16G ,那么需要共享内存页数是 16GB/4KB==4194304 (页))
防范syn攻击,ddos攻击
net.ipv4.tcp_syncookies = 1
表示开启 SYN Cookies功能,当出现 SYN 等待队列溢出时, 启用 Cookies 来处理, 可防范少量SYN攻击
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
新建TCP连接请求,需要发送一个SYN包,该值决定内核需要尝试发送多少次syn连接请求才决定放弃建立连接。默认值是5. 对于高负载且通信良好的物理网络而言,调整为2
net.ipv4.tcp_max_syn_backlog = 4096
Tcp syn队列的最大长度, 默认为 1024,在进行系统调用connect时会发生Tcp的三次握手,server内核会为Tcp维护两个队列,Syn队列和Accept队列,Syn队列是指存放完成第一次握手的连接,Accept队列是存放完成整个Tcp三次握手的连接,修改net.ipv4.tcp_max_syn_backlog使之增大可以接受更多的网络连接。注意此参数过大可能遭遇到Syn flood攻击,即对方发送多个Syn报文端填充满Syn队列,使server无法继续接受其他连接
net.ipv4.ip_forward = 1
数据包转发,Linux下默认为0,禁止数据包转发的,但在某些特殊场合需要使用这一功能,所谓转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的ip地址将包发往本机另一网卡,该网卡根据路由表继续发送数据包。这通常就是路由器所要实现的功能
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
0: 不进行源地址校验;
1: 严格模式,即RFC3704定义的严格反向路径;每个入向报文都要经过FIB进行反向路径检验,如果反向路径的出向端口不是最优的,则检测失败。默认情况下,丢弃检验失败的报文,在某些特殊情况下可能会丢包造成业务异常;
2: 松散模式,即RFC3704定义的松散反向路径;每个入向报文的源地址都要经过FIB检验,如果入向报文的源地址不能通过反向路径的任何出向端口到达,则检测失败。
#RFC3704文档建议使能严格模式,防止IP欺骗的DDos攻击。如果使用非对称路由或者其他复杂路由,建议使用松散模式
net.ipv4.tcp_fin_timeout = 15
#表示套接字由本端要求关闭,这个参数决定了他保持在 FIN_WAIT_2 状态的时间, 默认值是 60 秒
net.ipv4.tcp_keepalive_time = 300
表示当keepalive启用时, TCP 发送keepalive消息的频度, 默认是2小时, 建议 20 分钟;
Tcp keepalive心跳包机制,用于检测连接是否已断开,我们可以修改默认时间来间断心跳包发送的频率。
keepalive一般是服务器对客户端进行发送查看客户端是否在线,因为服务器为客户端分配一定的资源,但是Tcp 的keepalive机制很有争议,因为它们可耗费一定的带宽
net.ipv4.tcp_keepalive_probes = 3
keepalive probes最大探测次数
net.ipv4.tcp_keepalive_intvl = 15
客户端异常关闭,或网络断开。client无响应,server收不到ACK,在一定时间(/proc/sys/net/ipv4/tcp_keepalive_intvl
15 即15秒)后重发keepalive packet
net.ipv4.icmp_echo_ignore_broadcasts = 1
忽略ICMP广播请求,启动设置为1:从 ICMP 的角度出发,为了避免 ICMP 主机探测、ICMP Flood 等各种网络问题,你可以通过内核选项,来限制 ICMP 的行为,避免放大攻击
net.ipv4.icmp_ignore_bogus_error_responses = 1
开启恶意icmp错误消息保护
net.ipv4.ip_local_port_range = 1024 65535
服务器某个端口可以连接的最大tcp数量是由四元组成的也就是(src_ip,src_port,dst_ip,dst_port)(本地ip,本地端口,客户端ip,客户端端口)。理论上在src_ip,src_port固定的情况下,一个客户端Ip理论上最多有65535个连接数。ip_local_port_range这个参数控制的就是dst_port的范围,缺省情况下很小:32768到61000。
net.ipv4.tcp_rmem = 8192 87380 16777216
为 自动调优定义socket使用的内存。第一个值是为socket接收缓冲区分配的最少字节数;第二个值是默认值(该值会被rmem_default覆 盖),缓冲区在系统负载不重的情况下可以增长到这个值;第三个值是接收缓冲区空间的最大字节数(该值会被rmem_max覆盖)。
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
socket缓冲区默认大小
socket缓冲区最大值
net.ipv4.tcp_wmem = 8192 65536 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
为 自动调优定义socket使用的内存。第一个值是为socket发送缓冲区分配的最少字节数;第二个值是默认值(该值会被wmem_default覆 盖),缓冲区在系统负载不重的情况下可以增长到这个值;第三个值是发送缓冲区空间的最大字节数(该值会被wmem_max覆盖)。
net.core.somaxconn = 16384
somaxconn参数决定Accept队列长度,在listen函数调用时backlog参数即决定Accept队列的长度,该参数太小也会限制最大并发连接数,因为同一时间完成3次握手的连接数量太小,server处理连接速度也就越慢。服务器端调用accept函数实际上就是从已连接Accept队列中取走完成三次握手的连接。
Accept队列和Syn队列是listen函数完成创建维护的。 该选项默认值是128,这个参数用于调节系统同时发起的TCP连接数,在高并发的请求中,默认的值可能会导致链接超时或重传,因此,需要结合并发请求数来调节此值,对应系统路径为:/proc/sys/net/core/somaxconn
net.core.netdev_max_backlog = 16384
表示当每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许发送到队列的数据包最大数,对应系统路径为:/proc/sys/net/core/netdev_max_backlog,默认值为1000
net.core.optmem_max = 65535
表示每个套接字所允许的最大缓冲区的大小
net.ipv4.tcp_max_tw_buckets = 65535
系统在同时所处理的最大timewait sockets 数目。如果超过此数的话,time-wait socket
会被立即砍除并且显示警告信息,当出现TCP: time wait bucket table overflow,尽量调大参数
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 1
TIME_WAIT专有的优化参数reuse、recycle,默认也都是关闭的,这两个参数必须在timestamps打开的前提下才能生效使用,再次重申现在互联网NAT结构很多,如果开启tcp_tw_recycle,服务器可能会拒绝非递增请求连接,导致无法三次握手。会导致到NAT设备后面的Client连接Server不稳定(有的 Client 能连接 server,有的 Client 不能连接 server)为内部网络(网络环境自己可控 ” ——不存在NAT 的情况)设计的,对于公网环境下,不宜使用。
在常见的互联网架构中(NGINX反代跟NGINX,NGINX跟FPM,FPM跟redis、mysql、memcache等),减少TIME-WAIT状态的TCP连接,最有效的是使用长连接,不要用短连接,尤其是负载均衡跟web服务器之间。在服务端,不要启用net.ipv4.tcp_tw_recycle,除非你能确保你的服务器网络环境不是NAT。在服务端上启用net.ipv4.tw_reuse对于连接进来的TCP连接来说,是没有任何效果的。
net.ipv4.tcp_max_orphans = 16384
系统所能处理不属于任何进程的TCP sockets最大数量。假如超过这个数量,那么不属于任何进程的连接会被立即reset,并同时显示警告信息。之所以要设定这个限制,纯粹为了抵御那些简单的 DoS 攻击,千万不要依赖这个或是人为的降低这个限制。
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_moderate_rcvbuf = 1
如果开启,tcp会在连接关闭时也就是LAST_ACK状态保存各种连接信息到路由缓存中,新建立的连接可以使用这些条件来初始化.。大部分情况下这会增加总体的系统性能,但是有些时候也会引起性能下降.0:关闭,1:开启
net.ipv4.tcp_slow_start_after_idle = 0
在连接空闲期间保持拥塞窗口的大小,在连接空闲的同时,网络状况也可能发生了变化,为了避免拥塞,理应将拥塞窗口重置回“安全的”默认值。SSR对于那些会出现突发空闲的长周期TCP连接(比如HTTP的keep-alive连接)有很大的影响。因此,我们建议在服务器上禁用SSR
net.ipv4.tcp_fastopen = 3
开启tcp_fastopen数据能尽快传给server
另外还有一项可选参数加入:
该参数的含义是:永久禁 ping,一定程度上在互联网上隐藏自己防止一些批量扫描软件探测主机,减少被入侵的几率,不过却减少了使用上的便利性
net.ipv4.icmp_echo_ignore_all = 1
附一篇linux安全加固与审计的文档以供参考
《Linux安全加固与审计》