优先级
优先考虑用户、查询或数据库
PostgreSQL 没有提供限制特定用户、查询或数据库消耗资源的功能,也无法相应地设置优先级,以便一个用户/查询/数据库获得比其他用户/查询/数据库更多的资源。需要使用操作系统功能来实现有限的优先级分配。
PostgreSQL 用户、查询和数据库将争夺三种主要资源:
- 内存
- CPU
- 磁盘 I/O
在这些资源中,磁盘 I/O 通常是数据库应用程序的瓶颈,但并非总是如此。一些模式设计和查询对 CPU 的依赖性特别高。另一些则真正得益于大量可用的内存,通常用于排序。
优先级真的是问题吗?
在过于纠结于优先考虑查询/用户/数据库之前,值得优化你的查询并调整数据库。你可能会发现,无需使用优先级或采取极端措施,就可以通过以下技术获得完全可以接受的性能:
- 改进你的查询
- 调整自动清理器以减少膨胀
- 总体上优化集群的性能
- 避免使用VACUUM FULL。它会占用大量内存,扫描需要很长时间,浪费磁盘 I/O 带宽。有关更多信息,请参阅VACUUM FULL 页面。
CPU 真是瓶颈吗?
人们经常抱怨 CPU 负载过高(100%),并认为这是数据库速度慢的原因。但这并不一定正确 - 系统可能显示出明显的 100% CPU 使用率,但实际上可能主要受 I/O 带宽限制。考虑以下测试,它启动 20 个 `dd` 进程,每个进程从硬盘(此处:/dev/md0)读取不同的 1GB 块,偏移量为 1GB(以 root 身份运行测试)。
sync ; sh -c "echo 3 > /proc/sys/vm/drop_caches for i in `seq 1 20`; do ( dd if=/dev/md0 bs=1M count=1000 skip=$(($i * 1000)) of=/dev/null &) done
导致 `top` 输出:
top - 14:51:55 up 3 days, 2:09, 5 users, load average: 10.92, 4.94, 2.93 Tasks: 259 total, 3 running, 256 sleeping, 0 stopped, 0 zombie Cpu(s): 1.6%us, 15.0%sy, 0.0%ni, 0.0%id, 78.6%wa, 0.8%hi, 4.0%si, 0.0%st Mem: 4055728k total, 3843408k used, 212320k free, 749448k buffers Swap: 2120544k total, 4144k used, 2116400k free, 2303356k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 33 root 15 -5 0 0 0 R 5 0.0 0:26.67 kswapd0 904 root 20 0 4152 1772 628 D 5 0.0 0:00.62 dd 874 root 20 0 4152 1768 628 D 3 0.0 0:00.74 dd 908 root 20 0 4152 1768 628 D 3 0.0 0:00.80 dd 888 root 20 0 4152 1772 628 D 3 0.0 0:00.44 dd 906 root 20 0 4152 1772 628 D 3 0.0 0:00.56 dd 894 root 20 0 4152 1768 628 D 2 0.0 0:00.49 dd 902 root 20 0 4152 1772 628 D 2 0.0 0:00.46 dd .... etc ....
… 这可能会被误认为是繁忙的 CPU,但实际上是磁盘 I/O 引起的负载。这里的主要警告信号是 `iowait` CPU 百分比 ("%wa") 很高,表明大部分明显的负载实际上是由 I/O 子系统的延迟造成的。大多数 `dd` 进程处于 'D' 状态,即在系统调用中不可中断的睡眠,如果用 "ps" 检查 "wchan",你将看到它们正在睡眠,等待 I/O。
与其假设 CPU 争用是问题所在,不如使用可用的性能分析工具,更准确地了解系统瓶颈究竟在哪里。
优先考虑 CPU
要调整 PostgreSQL 进程的 CPU 优先级,可以使用 "renice"(在 UNIX 系统上),但操作起来有点笨拙,因为你需要 "renice" 感兴趣的后端,而不是连接到该后端的客户端程序。可以使用 SQL 查询 "SELECT pg_backend_pid()" 或查看 pg_stat_activity 视图获取后端进程 ID。
"renice" 或任何基于 setpriority() 调用的方法的一个重要限制是,在大多数类 UNIX 平台上,必须以 root 身份才能降低数值优先级(即安排进程更紧急地运行)。
通过 root 用户调用 "renice" 提高重要后端的优先级,而不是降低不重要后端的优先级,可能更有效。
优先级模块
prioritize 扩展允许用户调整 CPU 优先级,就像 "renice" 一样,通过 SQL 函数 set_backend_priority() 进行调整。普通用户可以提高在同一用户名下运行的任何后端进程的优先级值。超级用户可以提高任何后端进程的优先级值。就像手动使用 "renice" 一样,无法降低后端的优先级值,因为 PostgreSQL 不会以 "root" 用户身份运行。
如果你知道你的应用程序将运行一个不重要的 CPU 密集型查询,你可以在安装 "prioritize" 模块后让它调用 set_backend_priority(pg_backend_pid(), 20),以便将该进程安排为最低的紧急程度。
优先考虑 I/O
I/O 更难处理。一些操作系统为进程提供 I/O 优先级,例如 Linux 的 ionice,你可能会认为可以像使用 'nice' 一样使用它们。不幸的是,这种方法不太有效,因为 PostgreSQL 执行的大量工作,特别是磁盘写入,都是通过一个独立的后台写入进程完成的,该进程从所有后端共享的内存中读取数据。类似地,预写日志由它们自己的进程通过共享内存进行管理。由于这两个原因,很难有效地为一个用户提供比另一个用户更高的写入优先级。不过,ionice 对读取应该比较有效。
与 "nice" 一样,要实现有效的连接级别控制,需要添加适当的辅助函数,并且需要用户合作才能实现用户级别的优先级。
更好的 I/O 工作负载分离需要集群分离,这有自身的成本,并且仅在数据库级别有效。
优先考虑内存
PostgreSQL 确实有一些可调参数 用于内存使用,这些参数是针对每个客户端的,特别是 work_mem
和 maintenance_work_mem
。这些参数可以在给定的连接内设置,允许该后端为排序和索引创建等操作使用比平时更多的内存。你可以在 postgresql.conf
中将这些参数设置为保守的低值,然后使用 SET
命令为特定后端分配更高的值,例如 SET work_mem = '100MB';
。
你可以使用每个用户 GUC 变量为 work_mem
和 maintenance_work_mem
设置不同的值。例如
ALTER USER myuser SET work_mem = '50MB';
你无法通过这种方式影响使用共享缓冲区等设置完成的共享内存分配,该值在数据库启动时固定,无法在不重启的情况下更改。
在大多数操作系统中,没有简单的方法来优先考虑内存分配,例如,操作系统会更倾向于交换一个后端的内存,而不是另一个后端的内存。
外部链接
鸣谢
页面最初由 Ringerc 2009 年 11 月 26 日 02:34 (UTC) 创建