/dev/shm 容器下调优

目录

/dev/shm 容器下调优

背景

一些应用软件如oracle、postgresql在处理数据时通常会利用/dev/shm目录来缓存的数据文件,以加快IO读写,但是docker 默认只在容器里给这个文件分配64M大小,当应用软件需要缓存较大数据时,就会导致类似could not resize shared memory segment "/PostgreSQL.1131616928" to 16777216 bytes: No space left on device的报错,这样就需要调整/dev/shm大小

/dev/shm目录是什么

/dev/shm在linux中被看作一个设备文件,可以把它看成是内存的入口、一块物理存储或者tmp filesystem,可以通过这个设备向内存中读写文件,以加快某些io高的操作。

/dev/shm 理论

默认的Linux发行版中的内核配置都会开启tmpfs,映射到了/dev/下的shm目录。可以通过df 命令查看结果.
/dev/shm/是linux下一个非常有用的目录,因为这个目录不在硬盘上,而是在内存里。因此在linux下,就不需要大费周折去建ramdisk,直接使用/dev/shm/就可达到很好的优化效果。默认系统就会加载/dev/shm ,它就是所谓的tmpfs,有人说跟ramdisk(虚拟磁盘),但不一样。象虚拟磁盘一样,tmpfs 可以使用您的 RAM,但它也可以使用您的交换分区来存储。而且传统的虚拟磁盘是个块设备,并需要一个 mkfs 之类的命令才能真正地使用它,tmpfs 是一个文件系统,而不是块设备;您只是安装它,它就可以使用了。
tmpfs有以下优势:

  1. 动态文件系统的大小,/dev /shm需要注意的一个是容量问题,在linux下,它默认最大为内存的一半大小,使用df -h命令可以看到。但它并不会真正的占用这块内存,如果/dev/shm/下没有任何文件,它占用的内存实际上就是0字节;如果它最大为1G,里头放有 100M文件,那剩余的900M仍然可为其它应用程序所使用,但它所占用的100M内存,是绝不会被系统回收重新划分的

  2. tmpfs 的另一个主要的好处是它闪电般的速度。因为典型的 tmpfs 文件系统会完全驻留在 RAM 中,读写几乎可以是瞬间的。

  3. tmpfs 数据在重新启动之后不会保留,因为虚拟内存本质上就是易失的。所以有必要做一些脚本做诸如加载,绑定的操作。

修改/dev/shm大小

默认的最大一半内存大小在某些场合可能不够用,并且默认的inode数量很低一般都要调高些,这时可以用mount命令来管理它。
#mount -o size=1500M -o nr_inodes=1000000 -o noatime,nodiratime -o remount /dev/shm

也可以将mount配置写到fstab让其开机生效

echo "tmpfs /dev/shm tmpfs,defaults,size=512m 0 0" >> /etc/fstab
mount -o remount /dev/shm

应用

下面我们可以创建一个目录绑定/dev/shm文件系统,并测试读写速度

mkdir /dev/shm/tmp
chmod 1777 /dev/shm/tmp
mkdir /fbo-tmp
mount --bind /dev/shm/tmp /fbo-tmp
cd /fbo-tmp
dd if=/dev/zero of=./test.dt bs=1k count=10000

# free -m 可以发现share内存被占用了10M

容器下怎么设置

docker设置

docker启动时添加--shm-size参数调整/dev/shm文件系统大小

$ docker run --shm-size 124M -it --rm --name test-$RANDOM busybox /bin/sh
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
b71f96345d44: Pull complete 
Digest: sha256:930490f97e5b921535c153e0e7110d251134cc4b72bbb8133c6a5065cc68580d
Status: Downloaded newer image for busybox:latest
/ # df -h  | grep /dev/shm
shm                     124.0M         0    124.0M   0% /dev/shm

k8s 中的设置

可以通过emptyDir挂在内存到容器的/dev/shm目录实现设置容器内的/dev/shm大小

$ vim pods-shm.yml 
apiVersion: v1
kind: Pod
metadata:
  name: test-pd-shm
spec:
  containers:
  - image: busybox
    name: busybox-test
    command: [ "sleep", "1000000" ]
    imagePullPolicy: "IfNotPresent"
    volumeMounts:
      - mountPath: /dev/shm
        name: cache-volume
  volumes:
  - emptyDir:
      medium: Memory
      sizeLimit: 128Mi
    name: cache-volume
$ kubectl apply -f pods-shm.yml 
pod/test-pd-shm created
$ kubectl exec -it test-pd-shm -- sh
/ # df -h | grep /dev/shm
tmpfs                    15.7G         0     15.7G   0% /dev/shm
### 这里看到大小为15.7G,难道sizelimit没有生效?
### 测试一下
/dev/shm # dd if=/dev/zero of=test.dt bs=1M count=200
200+0 records in
200+0 records out
209715200 bytes (200.0MB) copied, 0.099244 seconds, 2.0GB/s
/dev/shm # df -h | grep /dev/shm
tmpfs                    15.7G    200.0M     15.5G   1% /dev/shm
/dev/shm # command terminated with exit code 137
$ kubectl get pods 
NAME          READY   STATUS    RESTARTS   AGE
test-pd-shm   0/1     Evicted   0          6m22s
### 可以看到实际写入200m就会导致pod被驱散

参考

上一篇:POSIX的IPC方式:消息队列、共享内存


下一篇:Linux下进程间通信方式——共享内存