/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有以下优势:
-
动态文件系统的大小,/dev /shm需要注意的一个是容量问题,在linux下,它默认最大为内存的一半大小,使用df -h命令可以看到。但它并不会真正的占用这块内存,如果/dev/shm/下没有任何文件,它占用的内存实际上就是0字节;如果它最大为1G,里头放有 100M文件,那剩余的900M仍然可为其它应用程序所使用,但它所占用的100M内存,是绝不会被系统回收重新划分的
-
tmpfs 的另一个主要的好处是它闪电般的速度。因为典型的 tmpfs 文件系统会完全驻留在 RAM 中,读写几乎可以是瞬间的。
-
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被驱散
参考
- https://www.cnblogs.com/oloroso/p/5405113.html
- https://www.linuxidc.com/Linux/2014-05/101818.htm
- https://blog.csdn.net/chen3888015/article/details/7515706
- https://blog.csdn.net/chen3888015/article/details/7515706