对于操作系统来说,数据库算是比较大型的应用,往往需要耗费大量的系统资源,特别是在内部进程间通信这块的资源。
操作系统默认的配置可能无法满足数据库对资源使用的需求。
那么应该如何根据数据库的需要,设置操作系统相关资源参数呢?
在讲资源分配前,大家可以参考阅读一下
<a href="https://www.postgresql.org/docs/9.5/static/kernel-resources.html#sysvipc">https://www.postgresql.org/docs/9.5/static/kernel-resources.html#sysvipc</a>
<a href="https://www.postgresql.org/docs/9.5/static/runtime-config-resource.html#runtime-config-resource-memory">https://www.postgresql.org/docs/9.5/static/runtime-config-resource.html#runtime-config-resource-memory</a>
kernel-doc-xxx/documentation/sysctl/kernel.txt
<a href="https://en.wikipedia.org/wiki/unix_system_v">https://en.wikipedia.org/wiki/unix_system_v</a>
这一篇主要讲的是进程间通信
<a href="https://docs.oracle.com/cd/e19455-01/806-4750/6jdqdflta/index.html">https://docs.oracle.com/cd/e19455-01/806-4750/6jdqdflta/index.html</a>
关于postgresql的共享内存管理,早期的 postgresql 版本共享内存分配只支持sysv的方式,数据库启动时,需要分配一块共享内存段,这个需求主要与配置多大的shared_buffers 有关。
社区在9.3的版本做了一个变动,使用mmap分配共享内存,大幅降低了系统对system v共享内存的需求量。
<a href="https://www.postgresql.org/docs/9.3/static/release-9-3.html">https://www.postgresql.org/docs/9.3/static/release-9-3.html</a>
但是mmap并不好,会带来额外的io开销,所以postgresql 9.4开始,又做了一个变动,支持动态分配共享内存,主要是为多核并行计算做的铺垫,而且默认的共享内存分配的方法变成了posix(如果环境支持),同样不需要启动时分配大的共享内存段 。
<a href="https://www.postgresql.org/docs/9.4/static/release-9-4.html">https://www.postgresql.org/docs/9.4/static/release-9-4.html</a>
从9.4开始,共享内存分配方法通过参数 dynamic_shared_memory_type 控制。
不同的值,创建共享内存段的方法也不一样,例如posix使用shm_open,sysv使用shmget,mmap使用mmap。
正是由于创建共享内存段的方法不一样,所以需要配置的操作系统内核参数也不一样。
不同的共享内存分配方法,对操作系统的内核参数配置要求也不一样。
涉及的资源以及计算方法如下
| name | description | reasonable values |
| ---- | ---- | ---- |
| shmmax | 单个共享内存段最大允许多大 (bytes) | 见另一张表,或者直接设置为内存的80% |
| shmmin | 单个共享内存段最小允许多小 (bytes) | 1 |
| shmall | 整个系统允许分配多少共享内存,(所有共享内存段相加) (bytes or pages) | 需考虑其他需要分配共享内存的应用,确保大于所有应用的需求量,通常可以设置为实际内存大小 |
| shmseg | 每个进程允许分配多少个共享内存段 | only 1 segment is needed, but the default is much higher, 所以不需要设置 |
| shmmni | 整个系统允许分配多少个共享内存段 | 需要分配共享内存的进程数 * shmseg |
| semmni | 允许分配多少组信号量id (i.e., sets) | at least ceil((max_connections + autovacuum_max_workers + 5) / 16) ,postgresql每16个进程一组 |
| semmns | 允许分配多少个信号量 | ceil((max_connections + autovacuum_max_workers + 5) / 16) 17 plus room for other applications,每组信号量需要17字节,加上其他软件的需求。实际设置时设置为semmnisemmsl |
| semmsl | 每组允许开多少信号量 | at least 17 |
| semmap | number of entries in semaphore map | see text |
| semvmx | maximum value of semaphore | at least 1000 (the default is often 32767; do not change unless necessary) |
共享内存 sysv 管理 (适用于 < 9.3 的版本)
<a href="https://www.postgresql.org/docs/9.2/static/kernel-resources.html">https://www.postgresql.org/docs/9.2/static/kernel-resources.html</a>
因此对于9.2以及更低版本的共享内存sysv管理的情况,shmmax的需求计算方法如下,将所有项相加。
usage
approximate shared memory bytes required (as of 8.3)
connections
(1800 + 270 max_locks_per_transaction) max_connections
autovacuum workers
(1800 + 270 max_locks_per_transaction) autovacuum_max_workers
prepared transactions
(770 + 270 max_locks_per_transaction) max_prepared_transactions
shared disk buffers
(block_size + 208) * shared_buffers
wal buffers
(wal_block_size + 8) * wal_buffers
fixed space requirements
770 kb
共享内存 sysv 管理 (适用于 >= 9.3 的版本)
对于9.3以及更高版本的postgresql, 即使使用sysv,也不需要这么多共享内存。后面会有实测。
通常需要4kb左右。
共享内存 posix, mmap, none 管理
一个postgresql集群只需要56字节(实测)的共享内存段大小
小结
9.3 以下版本,设置这3个内核参数
(9.3 以及以上版本,需要的shmmax没那么大,所以也可以使用以上设置。 )
如果一台服务器中要启动多个postgresql集群,则每个集群都需要
shmmin和shmseg不需要设置,从shmget的开发者手册也可以得到证实
系统页大小(未使用huge page时)
man shmget
信号量的需求,和数据库版本无关,计算方法如下。
需要多少组
semmni >= (max_connections + max_worker_processes + autovacuum_max_workers + 5) / 16
需要多少信号量
semmns >= ((max_connections + max_worker_processes + autovacuum_max_workers + 5) / 16) * 17 + 其他程序的需求
每组需要多少信号量
semmsl >= 17
对应系统内核配置举例
含义分别为
如何查看当前系统设置的sysv资源限制
如何查看已使用的sysv资源
shmmax与信号量实测
共享内存管理方法 posix, mmap, none 实测 shmmax 需求 如下
启动数据库, 查看ipc
共享内存管理方法 sysv 实测 shmmax 需求 如下
如果设置低于数据库的需求,会报错
报错
把shm加到到20gb,
9.5的版本,启动时实际需要的内存并不多,如果你在9.2或者更低版本测试,那会需要很多
postgresql 9.2 shared_buffer=16gb , 启动时需要申请大量的内存.
ulimit 设置主要是限制进程级别对系统资源的使用。
配置文件举例
/etc/security/limits.conf
查看进程设置
# cat /proc/$pid/limits
查看当前用户的limit配置
postgresql 推荐设置
core dump 相关内核设置
postgresql 的守护进程是postgres,如果它挂了,数据库就挂了,其他进程挂了它会负责crash recovery,自动重启数据库(默认设置了 restart_after_crash = on )
所以如果要防止系统oom时杀掉postgres主进程,需要在启动数据库前,使用root用户设置self脚本进程的oom_score_adj,然后启动数据库。
例子
man shm_open, shmget, mmap, semctl, sem_overview
本文主要帮助大家理解postgresql数据库对操作系统资源的需求,以及计算方法。
如果用户需要在一个系统中运行多个数据库集群,则需要将所有集群的需求加起来。
postgresql 9.2以及以前的版本,在数据库启动时对sysv共享内存段的需求很大,所以要设得比较大,需要用户注意。
祝大家玩得开心,欢迎随时来 阿里云促膝长谈业务需求 ,恭候光临。
阿里云的小伙伴们加油,努力 做好内核与服务,打造最贴地气的云数据库 。