Markdown

[Redis] warning

在redis log 發現warning:
1.WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add ‘vm.overcommit_memory = 1’ to /etc/sysctl.conf and then reboot or run the command ‘sysctl vm.overcommit_memory=1’ for this to take effect.
2.WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
3.WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command ‘echo never > /sys/kernel/mm/transparent_hugepage/enabled’ as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

overcommit_memory:
This value contains a flag that enables memory overcommitment.
When this flag is 0, the kernel attempts to estimate the amount
of free memory left when userspace requests more memory.
When this flag is 1, the kernel pretends there is always enough
memory until it actually runs out.
When this flag is 2, the kernel uses a "never overcommit"
policy that attempts to prevent any overcommit of memory.
Note that user_reserve_kbytes affects this policy.
This feature can be very useful because there are a lot of
programs that malloc() huge amounts of memory "just-in-case"
and don’t use much of it.
The default value is 0.
See Documentation/vm/overcommit-accounting and
mm/mmap.c::__vm_enough_memory() for more information.
Memory Overcommit的意思是操作系统承诺给进程的内存大小超过了实际可用的内存。一个保守的操作系统不会允许memory overcommit,有多少就分配多少,再申请就没有了,这其实有些浪费内存,因为进程实际使用到的内存往往比申请的内存要少,比如某个进程malloc()了200MB内存,但实际上只用到了100MB,按照UNIX/Linux的算法,物理内存页的分配发生在使用的瞬间,而不是在申请的瞬间,也就是说未用到的100MB内存根本就没有分配,这100MB内存就闲置了。下面这个概念很重要,是理解memory overcommit的关键:commit(或overcommit)针对的是内存申请,内存申请不等于内存分配,内存只在实际用到的时候才分配。
Linux是允许memory overcommit的,只要你来申请内存我就给你,寄希望于进程实际上用不到那么多内存,但万一用到那么多了呢?那就会发生类似“银行挤兑”的危机,现金(内存)不足了。Linux设计了一个OOM killer机制(OOM = out-of-memory)来处理这种危机:挑选一个进程出来杀死,以腾出部分内存,如果还不够就继续杀…也可通过设置内核参数 vm.panic_on_oom 使得发生OOM时自动重启系统。这都是有风险的机制,重启有可能造成业务中断,杀死进程也有可能导致业务中断,我自己的这个小网站就碰到过这种问题,参见前文。所以Linux 2.6之后允许通过内核参数 vm.overcommit_memory 禁止memory overcommit。
内核参数 vm.overcommit_memory 接受三种取值:
0 – Heuristic overcommit handling. 这是缺省值,它允许overcommit,但过于明目张胆的overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存。Heuristic的意思是“试探式的”,内核利用某种算法(对该算法的详细解释请看文末)猜测你的内存申请是否合理,它认为不合理就会拒绝overcommit。
1 – Always overcommit. 允许overcommit,对内存申请来者不拒。
2 – Don’t overcommit. 禁止overcommit。
http://linuxperf.com/?p=102

什么是Overcommit和OOM
在Unix中,当一个用户进程使用malloc()函数申请内存时,假如返回值是NULL,则这个进程知道当前没有可用内存空间,就会做相应的处理工作。许多进程会打印错误信息并退出。
Linux使用另外一种处理方式,它对大部分申请内存的请求都回复"yes",以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存。这种技术叫做Overcommit。
当内存不足时,会发生OOM killer(OOM=out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存。
Overcommit的策略
Linux下overcommit有三种策略(Documentation/vm/overcommit-accounting):
0. 启发式策略。合理的overcommit会被接受,不合理的overcommit会被拒绝。
  1. 任何overcommit都会被接受。
  2. 当系统分配的内存超过swap+N%*物理RAM(N%由vm.overcommit_ratio决定)时,会拒绝commit。
    overcommit的策略通过vm.overcommit_memory设置。
    overcommit的百分比由vm.overcommit_ratio设置。
    #echo 2 > /proc/sys/vm/overcommit_memory
    #echo 80 > /proc/sys/vm/overcommit_ratio
    当oom-killer发生时,linux会选择杀死哪些进程
    选择进程的函数是oom_badness函数(在mm/oom_kill.c中),该函数会计算每个进程的点数(0~1000)。
    点数越高,这个进程越有可能被杀死。
    每个进程的点数跟oom_score_adj有关,而且oom_score_adj可以被设置(-1000最低,1000最高)。

在Linux中,/proc/sys/net/core/somaxconn这个参数,linux中内核的一个不错的参数somaxconn。
对于一个TCP连接,Server与Client需要通过三次握手来建立网络连接.当三次握手成功后,
我们可以看到端口的状态由LISTEN转变为ESTABLISHED,接着这条链路上就可以开始传送数据了.
每一个处于监听(Listen)状态的端口,都有自己的监听队列.监听队列的长度,与如下两方面有关:
  • somaxconn参数.
  • 使用该端口的程序中listen()函数.
  1. 关于somaxconn参数:
定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数,默认值为1024,具体信息为:
Purpose:
Specifies the maximum listen backlog.
Values:
Default: 1024 connections
Range: 0 to MAXSHORT
Type: Connect
Diagnosis:
N/A
Tuning
Increase this parameter on busy Web servers to handle peak connection rates.
看下FREEBSD的解析:
限制了接收新 TCP 连接侦听队列的大小。对于一个经常处理新连接的高负载 web服务环境来说,默认的128太小了(web服务器listen函数的backlog会给我们内核参数的net.core.somaxconn先知道128,比如nginx)。大多数环境这个值建议增加到 1024 或者更多。 服务进程会自己限制侦听队列的大小(例如 sendmail(8) 或者 Apache),常常在它们的配置文件中有设置队列大小的选项。大的侦听队列对防止拒绝服务 DoS 攻击也会有所帮助。
socket tcp的backlog的上限是min(backlog,somaxconn),其中backlog是应用程序中传递给listen系统调用的参数值,somaxconn是内核规定的最大连接数。
sysctl -w net.core.somaxconn = 1024 或者echo 『net.core.somaxconn= 1024』 >>/etc/sysctl.conf;sysctl -p

命令:‘echo never > /sys/kernel/mm/transparent_hugepage/enabled’ 不啟用(會限制內存碎片清理,會使用系統軟體的算法管理內存映射)此處可能理解有誤,歡迎指正。
與 /sys/kernel/mm/transparent_hugepage/defragalways (表示時刻進行內存碎片清理)息息相關
在 Linux 作業系統上運行內存需求量較大的應用程式時,由於其採用的默認頁面大小為 4KB,因而將會產生較多 TLB Miss 和缺頁中斷,從而大大影響應用程式的性能。當作業系統以 2MB 甚至更大作為分頁的單位時,將會大大減少 TLB Miss 和缺頁中斷的數量,顯著提高應用程式的性能。這也正是 Linux 內核引入大頁面支持的直接原因。好處是很明顯的,假設應用程式需要 2MB 的內存,如果作業系統以 4KB 作為分頁的單位,則需要 512 個頁面,進而在 TLB 中需要 512 個表項,同時也需要 512 個頁表項,作業系統需要經歷至少 512 次 TLB Miss 和 512 次缺頁中斷才能將 2MB 應用程式空間全部映射到物理內存;然而,當作業系統採用 2MB 作為分頁的基本單位時,只需要一次 TLB Miss 和一次缺頁中斷,就可以為 2MB 的應用程式空間建立虛實映射,並在運行過程中無需再經歷 TLB Miss 和缺頁中斷(假設未發生 TLB 項替換和Swap)。
為了能以最小的代價實現大頁面支持,Linux 作業系統採用了基於 hugetlbfs 特殊文件系統 2M 字節大頁面支持。這種採用特殊文件系統形式支持大頁面的方式,
使得應用程式可以根據需要靈活地選擇虛存頁面大小,而不會被強制使用 2MB 大頁面。

留言