人大金仓 (Kingbase) 数据库 /dev/shm 问题分析文档

目录


1. 问题现象

1.1 典型错误信息

ERROR: could not resize shared memory segment "/kingbase.xxx" to xx bytes: No space left on device

1.2 问题影响

  • 数据库服务无法启动
  • 已运行的数据库连接中断
  • 业务系统无法正常访问数据库
  • 数据库性能下降(如果勉强运行)

2. 错误原因分析

2.1 容器默认 /dev/shm 大小限制

Kubernetes 容器中 /dev/shm 的默认大小仅为 64MB

# 查看容器内 /dev/shm
$ df -h /dev/shm
Filesystem      Size  Used Avail Use% Mounted on
shm              64M   16K   64M   1% /dev/shm

# 查看实际挂载参数
$ cat /proc/mounts | grep shm
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k)
                                                        # ↑ 默认只有 64MB

2.2 Kingbase 为什么需要共享内存

Kingbase(基于 PostgreSQL 内核)使用共享内存用于:

用途 说明 内存占用估算
共享缓冲区 (Shared Buffers) 数据页缓存 shared_buffers × 8KB
WAL 缓冲区 事务日志缓冲 wal_buffers × 8KB
锁管理器 表锁、行锁等 max_connections × 500KB
进程间通信 信号量、消息队列 数 MB
查询工作内存 排序、哈希等临时操作 work_mem × 活跃查询数

2.3 为什么会报错 “No space left on device”

即使只是尝试分配 1MB,也会报错的原因:

  1. 已有共享内存段占用空间 - Kingbase 启动时已分配了多个共享内存段
  2. 累积效应 - 多个连接、多次分配累积超过 64MB
  3. 配置参数过大 - shared_buffersmax_connections 等参数配置较高
典型 Kingbase 配置的共享内存需求:
shared_buffers = 128MB        # 约 131072 个 8KB 页
max_connections = 200          # 约 100MB 用于锁管理
work_mem = 4MB                 # 每个查询最多 4MB
wal_buffers = 16MB             # WAL 缓冲区
--------------------------------
总需求:约 300-500MB+

结论:默认 64MB 的 /dev/shm 远远不够!


3. 技术背景

3.1 容器 /dev/shm 挂载方式

默认方式(64MB)
# 未配置 dshm 卷时,容器使用默认 sandbox shm
# 挂载点:/run/containerd/io.containerd.grpc.v1.cri/sandboxes/<id>/shm
# 大小固定:64MB
实际挂载示例
# 查看宿主机上的容器 shm 挂载
$ mount | grep containerd
shm on /run/containerd/io.containerd.grpc.v1.cri/sandboxes/.../shm \
    tmpfs rw,nosuid,nodev,noexec,relatime,size=65536k
    # ↑ 容器默认 shm,只有 64MB

# 对比:配置了 dshm 的 pod
tmpfs on /var/lib/kubelet/pods/<pod-id>/volumes/kubernetes.io~empty-dir/dshm \
    tmpfs rw,relatime,size=130501340k
    # ↑ 通过 emptyDir 创建的 dshm,约 125GB

3.2 Kubernetes 中的三种挂载方式

方式 配置 大小 适用场景
默认 无配置 64MB 小内存应用
emptyDir + Memory 见下文 自定义 数据库等需大 shm
hostPath 挂载宿主机 /dev/shm 继承宿主机 需跨容器共享

4. 解决方案

4.1 方案一:配置 emptyDir(推荐)

适用于 KingbaseCluster CRD
apiVersion: qfusion.irds.io/v1alpha1
kind: KingbaseCluster
metadata:
  name: kingbase-53e4bf90
  namespace: qfusion-admin
spec:
  # 其他配置...

  # 添加 Pod 模板配置
  podTemplate:
    spec:
      containers:
      - name: kingbase
        # 挂载扩容的 /dev/shm
        volumeMounts:
        - mountPath: /dev/shm
          name: dshm
      volumes:
      - name: dshm
        emptyDir:
          medium: Memory      # 使用内存作为存储介质
          sizeLimit: 512Mi    # 设置大小为 512MB
适用于普通 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kingbase
spec:
  template:
    spec:
      containers:
      - name: kingbase
        image: kingbase-v8r6:v4.1.2
        volumeMounts:
        - mountPath: /dev/shm
          name: dshm
      volumes:
      - name: dshm
        emptyDir:
          medium: Memory
          sizeLimit: 512Mi

4.2 方案二:降低 Kingbase 共享内存参数

如果不方便修改 Kubernetes 配置,可以降低数据库参数:

-- 连接到数据库
ALTER SYSTEM SET shared_buffers = '32MB';      -- 降低共享缓冲区
ALTER SYSTEM SET max_connections = 50;         -- 降低最大连接数
ALTER SYSTEM SET work_mem = '1MB';             -- 降低工作内存
ALTER SYSTEM SET wal_buffers = '4MB';          -- 降低 WAL 缓冲区

-- 重启数据库使配置生效
SELECT pg_reload_conf();

注意:这种方式会影响数据库性能,仅作为临时解决方案。

4.3 方案三:使用 hostPath(不推荐)

volumes:
- name: dshm
  hostPath:
    path: /dev/shm

缺点

  • 安全性较低
  • 所有容器共享同一块 shm
  • 不适合生产环境

5. 推荐配置

5.1 根据 Kingbase 参数计算所需 /dev/shm 大小

#!/bin/bash
# 计算 Kingbase 所需的 /dev/shm 大小

# 获取配置(假设已连接数据库)
SHARED_BUFFERS=$(ksql -t -c "SHOW shared_buffers" | awk '{print $2}')
MAX_CONN=$(ksql -t -c "SHOW max_connections" | awk '{print $2}')
WORK_MEM=$(ksql -t -c "SHOW work_mem" | awk '{print $2}')
WAL_BUFFERS=$(ksql -t -c "SHOW wal_buffers" | awk '{print $2}')

# 转换单位为 MB
function to_mb() {
    echo $1 | sed 's/MB//;s/GB/*1024/' | bc
}

# 估算总需求
SHM_SIZE=$((
    $(to_mb $SHARED_BUFFERS) +
    $(to_mb $WAL_BUFFERS) +
    MAX_CONN * 1 +
    $(to_mb $WORK_MEM) * 10
))

# 建议大小(留 50% 余量)
RECOMMENDED=$((SHM_SIZE * 3 / 2))

echo "推荐 /dev/shm 大小: ${RECOMMENDED}MB"

5.2 推荐配置表

场景 shared_buffers max_connections 推荐 /dev/shm
开发测试 32MB 50 256Mi
小型生产 128MB 100 512Mi
中型生产 256MB 200 1Gi
大型生产 512MB+ 300+ 2Gi+

6. 验证方法

6.1 检查当前 /dev/shm 使用情况

# 在容器内执行
df -h /dev/shm

# 查看共享内存段详情
ipcs -m

# 查看 /dev/shm 下的文件
ls -lh /dev/shm/

6.2 检查 Pod 挂载配置

# 查看 Pod 的 volume 挂载情况
kubectl get pod <pod-name> -n qfusion-admin -o jsonpath='{.spec.volumes[*]}'

# 查看容器内的挂载点
kubectl exec -it <pod-name> -n qfusion-admin -- df -h

6.3 测试共享内存分配

# 在容器内创建测试文件
dd if=/dev/zero of=/dev/shm/test bs=1M count=100
# 如果成功写入 100MB,说明 /dev/shm 至少有 100MB 可用空间

# 清理测试文件
rm /dev/shm/test

6.4 验证 Kingbase 共享内存使用

-- 查看共享缓冲区大小
SHOW shared_buffers;

-- 查看当前共享内存使用情况
SELECT * FROM pg_stat_sharing;

-- 查看活跃连接数
SELECT count(*) FROM pg_stat_activity;

7. 故障排查检查清单

  • 检查容器内 df -h /dev/shm 输出
  • 检查 Pod 是否配置了 dshm emptyDir 卷
  • 检查 Kingbase 的 shared_buffers 参数
  • 检查 Kingbase 的 max_connections 参数
  • 使用 ipcs -m 查看共享内存段使用情况
  • 检查数据库日志中的相关错误信息
  • 确认 emptyDir 的 sizeLimit 是否足够

8. 附录

8.1 相关错误代码

错误代码 含义 解决方案
ENOSPC No space left on device 扩容 /dev/shm
EINVAL Invalid argument 检查 sizeLimit 格式
EPERM Operation not permitted 检查 Pod 安全策略

8.2 参考资料


文档版本: 1.0
创建日期: 2026-01-06
适用于: Kingbase V8R6, QFusion 4.1.2+

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐