码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-04-13 09:22:01      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:

原文: 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

 

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

标签:

原文地址:http://www.cnblogs.com/zhengran/p/4421249.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!