/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被驅散
參考