本次内容主要记录《DM8 安装手册》中关于Linux系统资源限制的问题。我把排查和学习的过程记录下来,希望能加深自己的理解,也希望能帮到和我一样的新人加深理解。
本文目录
关于Linux系统资源限制问题,《DM8 安装手册》首先在2.2.1.3 Linux(Unix)下检查操作系统限制 章节进行了描述 。它指导我们通过 ulimit -a 命令检查资源限制 ,并建议我们修改 /etc/security/limits.conf 文件来提高限制,比如把“最大文件打开数”(nofile) 调整到 65536 或更高 。
我在这里补充《DM8安装手册》中没有提到的,这些资源限制参数对应的意义,以及具体应该如何修改。
关键参数及建议值:
data seg size (kbytes, -d):
malloc 或 new 获取的堆内存)。-d 的限制太小(比如小于数据库配置的 MEMORY_POOL 大小加上其他必要内存),数据库在启动过程中向操作系统申请内存时,就会因为超出资源限制而被操作系统拒绝,导致内存分配失败,数据库进程无法完成初始化,进而启动失败。file size ((blocks, -f)):
blocks (块),通常一个块是 512 字节或 1KB 或 4KB,具体取决于文件系统。-f 限制太小,可能在写入某个较大的文件(比如核心库)时达到上限,导致安装过程失败。dminit) 创建数据库文件:当执行 dminit 初始化数据库时,需要创建初始的数据文件 (.dbf) 和日志文件 (.log)。这些文件的大小通常由初始化参数(如 LOG_SIZE)决定,可能远超几百 MB 甚至 GB 级别。如果 -f 的限制小于这些文件的大小,dminit 在创建这些核心数据库文件时就会因为超出文件大小限制而被操作系统拒绝,导致初始化失败。open files (-n):
参数含义:它限制了一个进程能够同时打开的文件描述符 (File Descriptors) 的最大数量。在 Linux 中,“一切皆文件”,包括普通文件、目录、网络套接字 (Sockets)、管道 (Pipes) 等。每打开一个,就会消耗一个文件描述符。
建议 65536 以上或 unlimited。数据库需要打开大量文件句柄(数据文件、日志、网络连接)。原因如下:
-n 的限制太小(比如 Linux 默认的 1024),在高并发场景下(大量用户同时连接并操作),数据库进程很容易就会耗尽可用的文件描述符。这时就会出现类似下列问题:virtual memory ((kbytes, -v):
-d 限制),还包括程序代码本身、共享库文件、内存映射文件等。-v 的限制太小,即使物理内存和交换空间足够,进程在尝试扩展其虚拟地址空间(比如加载共享库、扩展堆、创建线程栈)时,也会因为超出虚拟地址空间的总量限制而被操作系统拒绝,导致内存分配失败或映射失败,数据库进程无法正常启动或运行。修改方式:需要 root 权限,修改 /etc/security/limits.conf 文件。注意:修改后需要重新登录 dmdba 用户才能生效。
其基本语法是在文件末尾添加一行或多行,格式如下:
<domain> <type> <item> <value>
<domain>:指定这个限制应用于谁。
dmdba:只对 dmdba 这个用户生效。@dinstall:对 dinstall 这个用户组里的所有用户生效。*:对所有用户生效(不推荐,除非你清楚影响)。<type>:指定限制的类型。
soft:软限制 (Soft Limit)。这是内核强制执行的实际限制值,但用户自己可以(在硬限制范围内)临时调高它(比如用 ulimit -n 8192)。hard:硬限制 (Hard Limit)。这是软限制可以被调高的上限,只有 root 用户才能调高硬限制。普通用户不能超过硬限制。<item>:指定要限制的资源类型(对应 ulimit -a 里的名称)。
data:对应 data seg size (-d) (单位是 KB)。fsize:对应 file size (-f) (单位是 KB,注意,ulimit -a 显示的是 blocks)。nofile:对应 open files (-n) (单位是文件描述符数量)。as:对应 virtual memory (-v) (单位是 KB)。<value>:指定限制的值。
unlimited:表示无限制。示例:为 dmdba 用户设置建议值
# Settings for Dameng Database user dmdba
dmdba soft data unlimited
dmdba hard data unlimited
dmdba soft fsize unlimited
dmdba hard fsize unlimited
dmdba soft nofile 65536
dmdba hard nofile 65536
dmdba soft as unlimited
dmdba hard as unlimited
#博客补充堆栈参数
dmdba hard stack 32768
dmdba soft stack 16384
补充:堆栈参数(见csdn博客:https://blog.csdn.net/feritylamb/article/details/132184556)
stack size (kbytes, -s) 限制了进程中每个线程可以使用的栈空间大小。栈主要用于存储函数调用时的局部变量、参数和返回地址。soft 16384 (16MB) 和 hard 32768 (32MB) 是比较常见的建议值,通常足够用。limits.conf “失效”安装手册最后的 5.5 章节:资源限制 有一个非常关键的补充:
“在 Linux (Unix) 系统的 Systemd 服务环境中,通过 ulimit 命令或是修改 /etc/security/limits.conf 配置文件来设置系统资源限制,此修改不会对系统服务生效。”
个人理解的原理是:
/etc/security/limits.conf 是pam_limits 模块的配置文件,它仅在用户创建登录会话时(例如通过 SSH 或终端登录)被加载。因此,它只对当前登录的 Shell 及其子进程生效。
./dmserver /path/data/instancename/dm.ini),dmserver 进程会作为 Shell 的子进程继承 limits.conf 中设置的资源限制。在这种启动方式下,限制是生效的。DmServiceDMSERVER并使用 systemctl start 命令启动时,情况则完全不同。系统服务将交由 systemd 进行管理和启动。
systemd 是现代 Linux(如 CentOS 7+)的系统和服务管理器,它作为 1 号进程(init process)在系统引导阶段启动,并负责初始化系统和管理所有后台服务的生命周期。systemd 启动服务时并不会通过 PAM 模块创建登录会话,因此它完全不会读取 /etc/security/limits.conf 文件的配置。systemctl 管理的达梦服务,我们在 /etc/security/limits.conf 中为 dmdba 用户配置的资源限制将会失效。dmserver 进程会继承 systemd 自身的默认限制,而这个默认限制(尤其是 nofile)通常非常低,无法满足数据库高并发运行的需求。这就是为什么提到5.5 章节:资源限制 最后总结:
系统服务需通过 Systemd 服务环境中的相关配置文件去设置系统资源限制。
下面将讲解具体的检查操作,以及为什么平时在使用时,没有刻意去修改手册中提到的这一点,达梦服务却依旧能正常运行。
systemd步骤一:找到达梦服务的 .service 文件路径
使用 systemctl status 命令检查达梦服务状态,可以从 Loaded: 行确定服务单元配置文件的绝对路径。
[yyh@localhost ~]$ systemctl status DmServiceDMSERVER ● DmServiceDMSERVER.service - DM Instance Service Loaded: loaded (/usr/lib/systemd/system/DmServiceDMSERVER.service; enabled; vendor preset: disabled) Active: active (running) since 日 2025-11-02 06:29:07 PST; 1min 29s ago ...
可以看到,它的服务文件路径在 /usr/lib/systemd/system/DmServiceDMSERVER.service。
步骤二:检查服务单元文件内容
读取该服务单元文件的内容,以核实其对资源限制的具体配置。
[yyh@localhost ~]$ cat /usr/lib/systemd/system/DmServiceDMSERVER.service
[Unit]
Description=DM Instance Service
After=network-online.target remote-fs.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/home/dmdba/dmdbms/bin/pids/DmServiceDMSERVER.pid
ExecStart="/home/dmdba/dmdbms/bin/DmServiceDMSERVER" start
ExecStop="/home/dmdba/dmdbms/bin/DmServiceDMSERVER" stop
PrivateTmp=true
User=dmdba
TasksMax=infinity
LimitCORE=infinity
LimitNOFILE=100000
LimitNPROC=100000
[Install]
WantedBy=multi-user.target
检查表明,达梦数据库的 systemd 服务单元文件中已包含明确的资源限制指令。
在 [Service] 配置段中,以下指令主动配置了服务进程的资源上限:
LimitNOFILE=100000: 对应 ulimit -n(最大文件打开数)。100000 的配置值远高于手册 2.2.1.3 节 建议的 65536,满足高并发 I/O 的要求。LimitNPROC=100000: 对应 ulimit -u(最大用户进程数)。LimitCORE=infinity: 对应 ulimit -c(核心转储文件大小),设置为 infinity(无限),确保在实例崩溃时能生成完整的 core dump 文件以供分析。TasksMax=infinity: systemd 自身用于限制任务(线程)数的参数,infinity 确保了数据库的线程调度不受限制。systemd 服务确实不读取 limits.conf,而是遵守其 .service 单元文件中定义的 Limit... 指令。
该 .service 文件,大概率是在数据库实例创建后(例如使用 DBCA 工具),按照手册指引 切换至 root 用户执行 rootServiceinstaller.sh 脚本时自动生成的。
总结:
systemd 环境下,修改 /etc/security/limits.conf 仅对用户登录的 Shell 会话及其子进程(如手动执行 ./dmserver)生效。systemctl start DmService... 启动的服务,其资源限制必须在其 .service 配置文件中(如 /usr/lib/systemd/system/DmServiceDMSERVER.service)使用 Limit... 指令进行定义。rootServiceinstaller.sh)遵循了 systemd 的最佳实践,在生成服务单元文件时,已主动配置了高额的资源限制。因此,在标准安装的达梦环境中,通常无需再手动干预 systemd 配置。在排查资源限制问题时,必须区分两种失败类型:
virtual memory (-v) 或 data seg size (-d)。dmserver 进程在启动时,必须为其 BUFFER(共享内存)向操作系统申请虚拟地址空间。如果 ulimit -v 限制过低,该申请会立即失败,导致 dmserver 进程无法启动。max open files (-n)。dmserver 进程启动时仅需少量文件句柄,因此即使 ulimit -n 限制很低(如 1024),实例也能成功启动。但随着运行时间增长,并发连接和查询的增加,当进程试图打开第 1025 个文件句柄时,系统将拒绝请求,导致数据库报错(如 max open files)。/etc/security/limits.conf,但未重新登录 dmdba 用户会话,便直接启动了 dmserver,导致进程继承了旧的 1024 限制。stack size(堆栈参数)
max open files(文件打开数)一样,stack size也可以归属于运行时失败。dmserver 进程启动时,对堆栈(Stack)很低,因此可以成功启动。但如果后续数据库执行一个极其复杂的 SQL,或者一个深度递归/嵌套调用的存储过程,会导致函数调用链条非常长。这会导致堆栈持续增长,一旦超出了 ulimit -s 的限制(例如 8MB 或 10MB),就会发生**“栈溢出” (Stack Overflow),进而可能导致进程崩溃**。max open files相同。详情见下文。gdb 附加(attach)到进程,并在调试器中调用 setrlimit() C函数。此方法风险高,不推荐在生产环境使用。本文采用 prlimit 工具进行操作。
步骤一:复现与验证问题
首先,必须确认 dmserver 进程的真实限制。
获取 dmserver 进程的 PID:
[dmdba@localhost ~]$ ps -ef | grep dmserver dmdba 16922 10545 1 22:50 pts/0 00:00:01 ./dmserver ../data/DAMENG/dm.ini
检查该 PID 的当前限制: cat /proc 文件系统是查看进程实时状态的最准确方式。
[dmdba@localhost ~]$ cat /proc/16922/limits | grep "Max open files"
Max open files 1024 1024 files
步骤二:使用 prlimit 动态提升限制
现在,我们对这个 PID 为 16922 的进程执行“热修复”。(此命令通常需要 root 权限或与目标进程相同的所有者权限)。
执行 prlimit 命令:
# 命令格式:prlimit --pid <PID> --<LIMIT_TYPE>=<SOFT>:<HARD>
[dmdba@localhost ~]prlimit --pid 16922 --nofile=65536:65536
命令解析:
--pid 16922:指定要操作的目标进程。--nofile:指定修改的是“最大文件打开数”(RLIMIT_NOFILE)。65536:65536:设置新的限制值,格式为 <Soft Limit>:<Hard Limit>。步骤三:再次验证(确认修复)
prlimit 执行成功后,效果是立即生效的。我们立刻回到步骤一的验证方法:
[dmdba@localhost ~]$ cat /proc/16922/limits | grep "Max open files"
Max open files 65536 65536 files
结论:进程的限制已经被动态修改。此时,dmserver 进程可以打开更多的文件句柄,数据库的 “max open files” 错误会立刻停止,服务得到恢复,整个过程无需重启数据库。
步骤四:当数据库重启,以上措施失效
prlimit 是一种**“热修复” ,它只对当前正在运行的 PID (16922) 生效。如果这个 dmserver 进程被重启(例如 systemctl restart 或手动./dmserver)重启,它会丢失**这个 prlimit 修改。
演示:
#手动启动数据库
[dmdba@localhost bin]$ ./dmserver ../data/DAMENG/dm.ini
file dm.key not found, use default license!
version info: develop
# 省略数据库启动日志......
重新查看数据库服务进程和对应的limits——发现变回原来的值。
[dmdba@localhost ~]$ ps -ef | grep dmserver dmdba 106461 101322 1 22:56 pts/0 00:00:01 ./dmserver ../data/DAMENG/dm.ini [dmdba@localhost ~]$ cat /proc/106461/limits | grep "Max open files" Max open files 1024 1024 files
补充强调:
/etc/security/limits.conf 文件需要root权限,修改后需要重新登录 dmdba 用户才能生效。这里重新登录指必须退出当前session,单纯切换用户配置不生效。prlimit 是一种**“热修复” (Hotfix),它只对当前正在运行**的 PID (16922) 生效。dmserver 进程被重启(例如 systemctl restart 或手动重启),它会丢失这个 prlimit 修改。systemd 管理的:永久修复方案是回到我们上面第四章分析与总结的结论——修改 /usr/lib/systemd/system/DmServiceDMSERVER.service 文件,设置 LimitNOFILE=100000,然后执行 systemctl daemon-reload。/etc/security/limits.conf 的 65536 限制,然后再启动 ./dmserver。在本次排查Linux资源限制的过程中,个人还查阅到一份关于 DM7 在 CentOS 6.5 环境下的社区文章,其问题与本文有着共同之处。个人将在5.2进行补充讲解,原文链接如下:
祢真伟大:dmdba用户资源限制ulimit -a 部分配置未生效
环境:
init.d 脚本启动服务)症状:
ERROR database P0000070004 main_thread self_site(0) to dest_site(2) port_closed, return EC_CONNECT_LOSTATAL database p000000227121 main_htread fail to create thread uthr_db_htread排查: 管理员已在 /etc/security/limits.conf 中为 dmdba 用户配置了 nproc(最大进程/线程数)为 10240 ,但通过 cat /proc/227121/timts 命令(227121为dm进程pid)检查,发现 dmserver 进程实际的限制仍为 1024 。
问题分析: 症状与我们在 systemd 环境下遇到的问题如出一辙(配置与实际生效不符),但根源不同。
init.d 环境中,服务本应通过 pam_limits 模块正确继承 limits.conf 的配置。Enforcing(强制)模式是导致问题的根源 。SELinux 的安全策略(Policy)干扰了服务进程加载 pam_limits 模块,阻止了高额资源限制的生效。解决方案: 将 SELinux 设为 Permissive(宽容)模式(setenforce 0),问题解决。
具体操作如下:
setenforce命令将SELinux设置为宽容模式(Permissive),这样SELinux就不会强制执行策略,但会继续记录违反策略的行为。setenforce 0。这个命令会将SELinux设置为宽容模式,实际上临时关闭了SELinux的强制执行功能。这种状态将持续到下一次系统重启。永久关闭 SELinux:
/etc/selinux/config文件,根据您的需要更改SELINUX=的值。例如,要将SELinux设置为关闭,设置为SELINUX=disabled。这个案例表明,“为服务进程配置资源限制”是一个需要关注的Linux 运维问题。
init.d) 时代,主要的“干扰者”是 SELinux。systemd) 时代,主要的“干扰者”是 systemd 自身的设计机制(它根本不读取 limits.conf)。因此,实践需要注意:
limits.conf 就想当然地认为服务可以安全运行。必须在服务启动后,通过 cat /proc/<PID>/limits 去检查进程的实际限制。文章
阅读量
获赞
