[转载] Docker里莫名其妙的/proc/sys/kernel/shmmax

原文: http://www.weibo.com/p/1001603829422523342026

由docker ipc namespace引起的.

Docker部署重型应用,比如数据库,是否有坑?今天还真发现了一个

在部署数据库的时候,可能需要调整一些内核参数,比如/proc/sys/kernel/shmmax这个参数,这个参数是用来限制内核共享内存大小。共享内存这个东西有什么用呢?比如Oracle的SGA实现就是使用的共享内存,多个Session可以共享一块公共的内存空间,从而降低整体内存占用率。Java应用也有一些尝试,比如多个JVM之间可以共享内存,不过不太成熟。

但是在Docker容器里 (kernel 2.6.32),这个值就是33554432,也就是32M,所以如果你的应用很依赖共享内存的大小,就要谨慎了。

莫名其妙的/proc/sys/kernel/shmmax

如果你想在自己的环境里验证一下,可以按如下步骤验证:

On Host:

# cat /proc/sys/kernel/shmmax

68719476736

# ipcs -lm

------ Shared Memory Limits --------

max number of segments = 4096                                    #SHMMNI

max seg size (kbytes) = 67108864                                 #SHMMAX

max total shared memory (kbytes) = 17179869184        #SHMALL

min seg size (bytes) = 1

In Container:

# docker run -it --rm ubuntu cat /proc/sys/kernel/shmmax

33554432

# docker run -it --rm ubuntu ipcs -lm

------ Shared Memory Limits --------

max number of segments = 4096

max seg size (kbytes) = 32768

max total shared memory (kbytes) = 8388608

min seg size (bytes) = 1

如果是boot2docker上,容器的shmmax值又很大,表示奇怪:

# boot2docker version

Boot2Docker-cli version: v1.5.0

Git commit: ccd9032

docker@boot2docker:~$ cat /proc/sys/kernel/shmmax

18446744073692774399

docker@boot2docker:~$ docker run -it --rm ubuntu:14.04 cat /proc/sys/kernel/shmmax

18446744073692774399

第一个疑问:容器为什么没有继承宿主机的shmmax值

第一反应,docker容器复用的内核,这个值应该跟宿主机的值一样才对。搜了半天,终于在Kernel的Google Groups发现了原因。原来是IPC Namespace的创建实现,在初始化shm的过程中使用的是SHMALL,SHMMAX两个宏定义,也就是默认值。这个默认值是多少呢?坑爹的,还真是32M。

#define SHMMAX 0x2000000

这就能解释为什么docker容器在创建后,并没有继承父容器(也就是宿主机)的shmmax值。而能不能继承呢?实际上也有人提过,[PATCH] IPC initialize shmmax and shmall from the current value not the default(https://groups.google.com/forum/#!topic/linux.kernel/b5PAWl7kNls),就是在shm_init_ns的时候判断一下,代码是这样的:

---

ipc/shm.c | 9 +++++++--

1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/ipc/shm.c b/ipc/shm.c

index 7a51443..b7a4728 100644

--- a/ipc/shm.c

+++ b/ipc/shm.c

@@ -74,8 +74,13 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it);

void shm_init_ns(struct ipc_namespace *ns)

{

-       ns->shm_ctlmax = SHMMAX;

-       ns->shm_ctlall = SHMALL;

+       if (ns == &init_ipc_ns) {

+               ns->shm_ctlmax = SHMMAX;

+               ns->shm_ctlall = SHMALL;

+       } else {

+               ns->shm_ctlmax = init_ipc_ns.shm_ctlmax;

+               ns->shm_ctlall = init_ipc_ns.shm_ctlall;

+       }

ns->shm_ctlmni = SHMMNI;

ns->shm_rmid_forced = 0;

ns->shm_tot = 0;

--

1.8.4

效果呢,就是这个样子滴:

[root@sp2 ~]# sysctl -a|grep shmmax

kernel.shmmax = 68719476736

[root@sp2 ~]# lxc-attach -n cent_plain

[root@localhost ~]# sysctl -a|grep shmmax

kernel.shmmax = 68719476736

[root@localhost ~]# halt

[root@sp2 ~]# sysctl -a|grep shmmax

kernel.shmmax = 68719476736

[root@sp2 ~]# sysctl kernel.shmmax=34359738368

kernel.shmmax = 34359738368

[root@sp2 ~]# lxc-start -n cent_plain -d

[root@sp2 ~]# lxc-attach -n cent_plain

[root@localhost ~]# sysctl -a|grep shmmax

kernel.shmmax = 34359738368

[root@localhost ~]#

回头来问,继承这个解决方案是不是一个好方案呢?个人认为未必,而且由于container是共用内核,这样默认情况下就会导致所有container都会继承相同的值,而实际上有可能各container对这个值的需求是不一样的。

第二个疑问:为什么boot2docker的shmmax值这么大

第一反应是boot2docker是不是做了什么修改。偶然间发现,是kernel有人提了patch,ipc/shm.c: increase the defaults for SHMALL, SHMMAX(https://git.kernel.org/cgit/linux/kernel/git/mhocko/mm.git/commit/include/uapi/linux/shm.h?id=060028bac94bf60a65415d1d55a359c3a17d5c31)

diff --git a/include/uapi/linux/shm.h b/include/uapi/linux/shm.h

index 78b6941..74e786d 100644

--- a/include/uapi/linux/shm.h

+++ b/include/uapi/linux/shm.h

@@ -9,15 +9,13 @@

/*

* SHMMAX, SHMMNI and SHMALL are upper limits are defaults which can

- * be increased by sysctl

+ * be modified by sysctl.

*/

-#define SHMMAX 0x2000000 /* max shared seg size (bytes) */

#define SHMMIN 1 /* min shared seg size (bytes) */

#define SHMMNI 4096 /* max num of segs system wide */

-#ifndef __KERNEL__

-#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))

-#endif

+#define SHMMAX (ULONG_MAX - (1L<<24)) /* max shared seg size (bytes) */

+#define SHMALL (ULONG_MAX - (1L<<24)) /* max shm system wide (pages) */

#define SHMSEG SHMMNI /* max shared segs per process */

boot2docker使用的内核比较新,应该是包含了这个更新,所以shmmax值这么大

docker@boot2docker:~$ uname -a

Linux boot2docker 3.18.5-tinycore64 #1 SMP Sun Feb 1 06:02:30 UTC 2015 x86_64 GNU/Linux

第三个疑问:这个值在容器里能改吗

既然这个值在生产环境的系统中有坑,那能够在容器里进行定制化吗?简单方式肯定不行,因为docker容器默认/proc是只读挂载的,所以无法在运行期进行修改:

root@98dd6e62ff18:/# echo "18446744073692774398" > /proc/sys/kernel/shmmax

bash: /proc/sys/kernel/shmmax: Read-only file system

针对这个问题,也有相关的issue,像how can i change the value of /proc/sys/kernel/shmmax in a container?(https://github.com/docker/docker/issues/10176)和sysctl tunables(https://github.com/docker/docker/issues/4717)

目前看起来可行的两个方案:

--ipc=host,这个参数在docker的1.3.2版本中不支持

--privileged=true,不过这个比较危险

docker@boot2docker:~$ docker run -it --rm --privileged=true ubuntu:14.04 bash

root@6d8525137fb9:/# echo "18446744073692774398" > /proc/sys/kernel/shmmax

root@6d8525137fb9:/# cat /proc/sys/kernel/shmmax

18446744073692774398

root@6d8525137fb9:/# exit

docker@boot2docker:~$ cat /proc/sys/kernel/shmmax

18446744073692774399

时间: 2025-01-04 23:10:36

[转载] Docker里莫名其妙的/proc/sys/kernel/shmmax的相关文章

LINUX远程强制重启/proc/sys/kernel/sysrq /proc/sysrq-trigger

1.     # echo 1 > /proc/sys/kernel/sysrq 2.     # echo b > /proc/sysrq-trigger 1. /proc/sys/kernel/sysrq 向sysrq文件中写入1是为了开启SysRq功能.根据linux/Documentations/sysrq.txt中所说:SysRq代表的是Magic System Request Key.开启了这个功能以后,只要内核没有挂掉,它就会响应你要求的任何操作.但是这需要内核支持(CONFIG

linux主机hang住echo 0 &gt; /proc/sys/kernel/hung_task_timeout_secs disables this message

问题原因: 默认情况下, Linux会最多使用40%的可用内存作为文件系统缓存.当超过这个阈值后,文件系统会把将缓存中的内存全部写入磁盘, 导致后续的IO请求都是同步的. 将缓存写入磁盘时,有一个默认120秒的超时时间. 出现上面的问题的原因是IO子系统的处理速度不够快,不能在120秒将缓存中的数据全部写入磁盘.IO系统响应缓慢,导致越来越多的请求堆积,最终系统内存全部被占用,导致系统失去响应. 解决方法: 根据应用程序情况,对vm.dirty_ratio,vm.dirty_background

&quot;echo 0 /proc/sys/kernel/hung_task_timeout_secs&quot; disable this message

问题现象: 问题原因: 默认情况下, Linux会最多使用40%的可用内存作为文件系统缓存.当超过这个阈值后,文件系统会把将缓存中的内存全部写入磁盘, 导致后续的IO请求都是同步的. 将缓存写入磁盘时,有一个默认120秒的超时时间. 出现上面的问题的原因是IO子系统的处理速度不够快,不能在120秒将缓存中的数据全部写入磁盘. IO系统响应缓慢,导致越来越多的请求堆积,最终系统内存全部被占用,导致系统失去响应. 解决办法: 根据应用程序情况,对vm.dirty_ratio,vm.dirty_bac

ipcs、ipcrm、sysresv、kernel.shmmax

ipcs.ipcrm.sysresv.kernel.shmmax 1.1  BLOG文档结构图 1.2  前言部分 1.2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~: ① ipcs的使用 ② ipcrm释放oracle内存段 ③ sysresv的使用 ④ 内核参数kernel.shmmax ⑤ 如何快速的清理Oracle的进程 ⑥ 其它维护操作   Tips: ① 本文在itpub(http://blog.it

linux /proc/sys

所有的TCP/IP调优参数都位于/proc/sys/net/目录.例如, 下面是最重要的一些调优参数,后面是它们的含义: 1./proc/sys/net/core/rmem_max — 最大的TCP数据接收缓冲 2./proc/sys/net/core/wmem_max — 最大的TCP数据发送缓冲 3./proc/sys/net/ipv4/tcp_timestamps — 时间戳在(请参考RFC 1323)TCP的包头增加12个字节 4./proc/sys/net/ipv4/tcp_sack 

Linux TCP/IP调优参数 /proc/sys/net/目录

所有的TCP/IP调优参数都位于/proc/sys/net/目录. 例如, 下面是最重要的一些调优参数,后面是它们的含义: /proc/sys/net/core/rmem_default "110592" 定义默认的接收窗口大小:对于更大的 BDP 来说,这个大小也应该更大. /proc/sys/net/core/rmem_max "110592" 定义接收窗口的最大大小:对于更大的 BDP 来说,这个大小也应该更大. /proc/sys/net/core/wmem

/proc/sys/net/ipv4/

/proc/sys/net/ipv4/icmp_timeexceed_rate这个在traceroute时导致著名的"Solaris middle star".这个文件控制发送ICMP Time Exceeded消息的比率. /proc/sys/net/ipv4/igmp_max_memberships主机上最多有多少个igmp (多播)套接字进行监听. /proc/sys/net/ipv4/inet_peer_gc_maxtime求 助: Add a little explanati

[转]手工释放linux内存——/proc/sys/vm/drop_caches

另一篇:http://www.linuxfly.org/post/320/ ? 1.清理前内存使用情况?free -m 2.开始清理??echo 1 > /proc/sys/vm/drop_caches 3.清理后内存使用情况?free -m 4.完成! 查看内存条数命令: dmidecode?|?grep?-A16?"Memory?Device$" ? ? ? ? ? +++++++++++++++++++++++++++++++++++++++++++++++++++++++

/proc/sys/fs 内容解析

This subdirectory contains specific file system, file handle, inode, dentry and quota information. 1,/proc/sys/fs/aio-max-nr aio-max-nr allows you to change the maximum value/proc/sys/fs/aio-nr can grow to. 2,/proc/sys/fs/aio-nr aio-nr shows the curr