CPU使用率高的问题
问题描述
操作系统的CPU频繁达到70%或以上,操作系统响应慢或无响应,导致数据库运行异常,如活跃连接数增加,大量SQL处理active或Lock状态,SQL执行变慢或长时间执行中。
可能影响
- 操作系统响应慢或无响应;
- 数据库运行异常,如活跃连接数增加,大量SQL处理active或Lock状态,SQL执行变慢或长时间执行中。
解决步骤
- 操作系统层面检查cpu使用情况,如执行top命令,观察CPU整体情况;
- %Cpu(s): 0.8 us, 0.8 sy, 0.0 ni, 98.1 id, 0.3 wa, 0.0 hi, 0.0 si, 0.0 st
- CPU属性值说明:
- %user:CPU处在用户模式下的时间百分比。
- %nice:CPU处在带NICE值的用户模式下的时间百分比。
- %system:CPU处在系统模式下的时间百分比。
- %iowait:CPU等待输入输出完成时间的百分比。
- %steal:管理程序维护另一个虚拟处理器时,虚拟CPU的无意识等待时间百分比。
- %idle:CPU空闲时间百分比。
说明如果%iowait的值过高,表示硬盘存在I/O瓶颈,%idle值高,表示CPU较空闲,如果%idle值高但系统响应慢时,有可能是CPU等待分配内存,此时应加大内存容量。%idle值如果持续低于10,那么系统的CPU处理能力相对较低,表明系统中最需要解决的资源是CPU。
您也可以使用perf,通过sudo perf top -s comm,可以查看当前系统运行进程占比。
这里不像top一样区分idle、system、user,这里的占比是各个进程在总运行时间里面占比。
通过sudo perf record记录采样信息,然后通过sudo perf report -s comm。
通过perf 可以从总体上查看CPU使用占比,结合数据库源码分析问题瓶颈。
- 如上一步骤中,top查看到的都是postgres的进程,那么可以确定是由数据库引起的cpu问题,如果是其它进程,则需要确认进程对应的具体应用,另做分析,此处不再展示;
- 对于由于大量postgres进程占用CPU导致的问题,可以通过postgres进程的pid找到对应哪个实例节点,进一步连接节点,通过查询会话表,查看运行的SQL情况。
如,查询运行时长超过10秒的SQL:
SELECT now() - query_start as "runtime", usename,application_name, client_hostname, datname, state, query
FROM pg_stat_activity
WHERE now() - query_start > '10 seconds'::interval and state!='idle'
ORDER BY runtime DESC;
查询花费时间最多的SQL TOP10:
SELECT round(total_time*1000)/1000 AS total_time,query
FROM pg_stat_statements
ORDER BY total_time DESC limit 10;
查看锁阻塞情况:
select pid, usename, pg_blocking_pids(pid) as blocked_by, query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
根据收集到慢SQL或阻塞会话,进一步进行分析优化,通常策略有
1)优化SQL语句,尤其是并发量大、高频的SQL语句,通常通过创建索引减少大表全表扫描,改写SQL关联逻辑等方式优化;
2)根据业务需要,评估是否可降低并发量;
3)根据瓶颈,横向扩容节点组,调大节点资源配置;
4)提高硬件配置,提升CPU、磁盘性能;
磁盘空间使用率问题
问题描述
磁盘空间占用率高,触发告警,或磁盘空间使用100%,导致数据库运行出错。
可能影响
- 磁盘空间使用率达到100%,会导致数据库运行可能出现异常,新写入或更新文件被置空,数据库无法启动;
- SQL执行报错。
解决步骤
- 执行以下命令检查磁盘空间占用情况
df -h 查看磁盘空间占用,实际上是查看磁盘块占用的文件(block)
df -ih 查看索引节点的占用(Inodes)
磁盘块和索引节点其中之一满,都会导致无法创建文件,提示磁盘空间已满。
所以请注意,查看磁盘还有空间,但是创建文件提示空间满,可能是inodes节点已满。
- 磁盘空间满/过高的问题,可以进入问题目录,执行du -sh * | sort -h命令逐层目录检查,找到占用空间高的目录和文件,根据需要进行清理;
结合find / -size +100M |xargs ls -lh命令,查找系统中内大于100M的文件,根据需要进行清理;
- 索引节点满/过高的问题,可以进入问题目录,执行 find */ ! -type l | cut -d / -f 1 | uniq -c 逐层找出文件最多目录,定位出哪个目录占用inodes最多(通常inodes是因为小文件太多);
- TeleDB数据库常见磁盘占用空间满/过高的问题及解决办法:
1)xlog(wal)日志积压过多
解决办法:可以参照本文中xlog堆积类问题处理;
2)大量更新导致WAL日志快速增长,日志归档速度低于增长速率,导致积压;
解决办法:
a、分析写入/更新逻辑,排查WAL日志写入占比,通过优化写入/更新逻辑,降低WAL日志写入量;
b、操作系统CPU充足的情况下,可设置WAL日志压缩策略
c、提升日志归档速度,如批量提交,提高并发等;
3)查询操作含有大数据量的排序、连接等操作,处理过程中产生临时表并溢出到磁盘,短时间内造成大量空间占用;
解决办法:
a、检查SQL关联逻辑是否错误导致的数据量暴增,优化SQL写法;
b、避免大数据量的排序操作;
c、针对SQL语句会话级调大参数work_mem,减少或规避临时表溢出到磁盘问题;
d、通过设置参数temp_file_limit来限制SQL语句用于指定每个查询可以使用的临时表空间上限(单位为KB),单个查询生成的临时表空间达到上限就会报错;
4)数据库触发异常,产生大量core文件;
解决办法:保留最近几个完整的core文件,联系TeleDB运维工程师分析,通常可通过改写SQL等方式暂时规避,或升级版本解决。
磁盘I/O使用率高的问题
问题描述
磁盘I/O使用率高或100%。
可能原因
- SQL执行慢或无响应;
- 数据库运行异常。
解决步骤
- 可以通过iostat命令查看磁盘IO情况,重点关注until和svctm这两个值
- svctm:The average service time (in milliseconds) for I/O requests that were issued to the device. Warning! Do not trust this field any more. This field will be removed in a future sysstat version.
- %util:Percentage of elapsed time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100%.
执行命令:
iostat -x -k -d 1
返回结果示例:
其中每列说明如下:
- rrqm/s: 每秒进行 merge 的读操作数目。即 rmerge/s
- wrqm/s: 每秒进行 merge 的写操作数目。即 wmerge/s
- r/s: 每秒完成的读 I/O 设备次数。即 rio/s
- w/s: 每秒完成的写 I/O 设备次数。即 wio/s
- rkB/s: 每秒读K字节数。是 rsect/s 的一半,因为每扇区大小为512字节。
- wkB/s: 每秒写K字节数。是 wsect/s 的一半。
- avgrq-sz: 平均每次设备I/O操作的数据大小 (扇区)。
- avgqu-sz: 平均I/O队列长度。
- rsec/s: 每秒读扇区数。即 rsect/s
- wsec/s: 每秒写扇区数。即 wsect/s
- r_await:每个读操作平均所需的时间,不仅包括硬盘设备读操作的时间,还包括了在kernel队列中等待的时间。
- w_await:每个写操作平均所需的时间,不仅包括硬盘设备写操作的时间,还包括了在kernel队列中等待的时间。
- await: 平均每次设备I/O操作的等待时间 (毫秒)。
- svctm: 平均每次设备I/O操作的服务时间 (毫秒)。
- %util: 一秒中有百分之多少的时间用于 I/O 操作,即被io消耗的cpu百分比
返回结果分析:
如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间;如果 await 远大于 svctm,说明I/O 队列太长,io响应太慢,则需要进行必要优化。如果avgqu-sz比较大,也表示有大量io在等待。
注意iostat 中的 %util 基本已经没有任何作用了,svctm也没什么参考意义,%util表示该设备有I/O(即非空闲)的时间比率,不考虑I/O有多少,只考虑有没有。
由于现代硬盘设备都有并行处理多个I/O请求的能力,所以%util即使达到100%也不意味着设备饱和了。
举个简化的例子:某硬盘处理单个I/O需要0.1秒,有能力同时处理10个I/O请求,那么当10个I/O请求依次顺序提交的时候,需要1秒才能全部完成,在1秒的采样周期里%util达到100%;而如果10个I/O请求一次性提交的话,0.1秒就全部完成,在1秒的采样周期里%util只有10%。可见,即使%util高达100%,硬盘也仍然有可能还有余力处理更多的I/O请求,即没有达到饱和状态。
- 可以通过nmon工具分析,具体参见https://nmon.sourceforge.io/pmwiki.php
nmon返回结果中,关注Disk I/O中 Busy列判断磁盘是否达到饱和状态;
- 或者通过dstat、sar来查看磁盘I/O情况
- TeleDB数据库常见磁盘I/O使用率高的问题及解决办法:
1)大批量写入/更新操作,占用大量磁盘I/O;
解决办法:
a、分析写入/更新逻辑,排查WAL日志写入占比,通过优化写入/更新逻辑,降低WAL日志写入量;
b、操作系统CPU充足的情况下,可设置WAL日志压缩策略;
2)高并发SQL语句执行效率低,产生大量I/O,导致磁盘I/O、CPU升高;
解决办法:优化SQL语句,尤其是并发量大、高频的SQL语句,通常通过创建索引减少大表全表扫描,改写SQL关联逻辑等方式优化;
3)磁盘性能不足
解决办法:不使用HDD机械盘,推荐使用NVMe SSD盘,并做raid,提升磁盘性能;
4)shard_buffer、操作系统内存不足,导致频繁的磁盘I/O;
解决办法:操作系统应该保持充足的内存,有更多可用缓存(shard_buffer、操作系统cache),同时调整相关参数,适当拉长checkpoint频率,减少磁盘I/O。
内存不足问题
问题描述
操作系统内存不足,导致数据库运行异常。
可能影响
- 可能会导致执行的SQL因申请不到内存报错;
- 可能会导致新建连接无法建立;
- 可能会导致操作系统主动KILL掉数据库进程,导致数据库异常重启。
解决步骤
- 执行shell命令 free -h,查看内存整体使用情况
free命令输出结果示例:
total used free shared buff/cache available
Mem: 14G 2.3G 195M 5.7G 12G 6.6G
Swap: 0B 0B 0B
Linux操作系统的内存主要看内存大小,剩余内存是否足够。在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了:Linux系统默认的设置倾向于把内存尽可能的用于文件cache,所以在一台大内存机器上,往往我们可能发现没有多少剩余内存。
对于操作系统,free命令显示出的空闲内存,应该更多关注-/+ buffers/cache: 这表明了你的系统可能还剩余的空闲内存。对于应用程序来说,buffers/cached占有的内存是可用的,因为buffers/cached是为了提高文件读取的性能,当应用程序需要用到内存的时候,buffers/cached会很快地被回收,以供应用程序使用。
同时,我们应关注是否用到了swap,当前服务器内存配置足够,通常在数据库服务器上需要关闭swap使用,避免因使用到swap导致性能下降。
- 通过top -o %MEM查看内存使用情况,及内存使用排名TOP的进程
top命令输出结果示例:
这里是按%MEM内存使用TOP排名的结果,可以查看对应的命令和进程ID,进一步分析原因,并进行针对性优化。
- 或者,通过ps aux|sort -rnk 4|head -5 查看内存使用排名TOP5的进程
ps aux命令输出结果示例:
- TeleDB数据库常见内存不足问题及解决办法:
1)非数据库进程占用较大内存,如已知的在多个项目中遇到麒麟V10系统auditd服务占用大量内存问题,导致数据库实例运行异常
解决办法:
a、麒麟V10系统已有补丁,可联系麒麟厂商升级补丁解决;
b、在更新操作系统补丁前,需要关闭操作系统的auditd服务,并设置为服务不自动启动。如有安全要求,不能关闭audited服务,则必须有方案来定期重启auditd服务。
a)关闭audited服务方法:
用root用户执行以下命令来关闭auditd服务:
systemctl stop auditd
systemctl disable auditd
b)或者root用户下配置定时任务来自动重启auditd服务,例如,每天凌晨1点重启:
crontab -e
0 1 * * * systemctl restart auditd > /dev/null 2>&1 &
需要确保root用户可重启auditd服务,验证定时任务已生效。
如重启服务有如下提示:
Failed to restart auditd.service: Operation refused, unit auditd.service may be requested by dependency only (it is configured to refuse manual start/stop).
See system logs and 'systemctl status auditd.service' for details.
可通过注释/usr/lib/systemd/system/auditd.service文件中RefuseManualStop=yes,然后执行 systemctl daemon-reload 重新加载生效。
2)分区表过多,分区的catalog cache占用大量内存,特别需要注意并不是explain里面已经裁减了就代表relcache也裁剪了;
解决办法:
a、控制分区表使用数量,表分区的目的主要拆分大表,降低维护成本,TeleDB分布式数据库,可通过多组DN节点,达到同样的目的,在部分情况下可以不使用分区表,或者减少分区数量;
b、分区表的SQL语句应该尽量使用分布键+分区键条件,尽量缩减访问范围,避免因未使用分布式键、未使用分区键导致的SQL重分布问题、读取全部分区的问题;
3)业务使用了大量长连接, 并且没有设置连接的生命周期, 或者生命周期很长. 连接时间越长, 访问的元数据积累越多, 导致每个会话的私有内存较大。
解决办法:
a、降低应用到数据库的总连接数, 并且设置连接的生命周期(例如, 一个连接最多使用15分钟后自动释放);
b、业务侧做好连接管理,通过连接池限制连接数上限;
c、数据库层面做好连接管理,定期清理空闲连接、长时间未执行结束的SQL;
4)设置了较大的work_mem或hash_mem_multiplier, 并且有大量SQL使用了hash agg或hash join, 导致内存消耗过多;
解决办法:调小work_mem或hash_mem_multiplier. 业务层减少此类请求的并发量。此类SQL使用PG HINT把hash agg\hash join改成group agg或merge join等。
5)数据库有性能问题, 高峰期引起了雪崩, 并且应用程序配置的连接池上限较大, 导致向数据库请求了大量连接, 最终耗费大量内存引起OOM;
解决办法:
a、降低应用到数据库的总连接数, 并且设置连接的生命周期(例如一个连接最多使用15分钟后自动释放);
b、设置数据库或USER的connection limit, 限制用户或数据库级别的连接数上限;
c、收集SQL并分析优化。
6)业务量未预期突增,服务器内存规划不足
解决办法:调整部署策略,如:
a、更换配置更高的服务器,提供更多的内存;
b、提供更多的服务器,将CN、DN节点扩容或调整到更多服务器上,降低单台服务器负载;
c、可能原规划单能服务器上有主、备节点混部情况,在发生切换时,有服务器上存在多个主节点,主节点有业务流入,需要更多的内存,导致高峰期内存不足;建议重新规划部署,充分考虑此类情况下的服务器资源使用情况;
7)开启资源隔离,实例节点分配内存资源预估不足,导致OOM
解决办法:优先尝试优化;在资源需求充分评估后,扩容实例资源;
8)操作系统内存相关参数配置不合理,导致操作系统内存无法充分利用
解决办法:原因可能是vm.overcommit_memory配置为2,同时overcommit_ratio配置较小,导致操作系统有足够的内存,但无法使用;
例如:
sysctl -a | grep -i vm.overcommit_memory 看到为2,也就是关闭了overcommmit
overcommit_ratio 配置为50%,这样只能用系统一半的内存
通常推荐不要关闭overcommit,vm.overcommit_memory应配置为0。
操作系统负载过高问题
问题描述
操作系统负载较平时升高,操作系统层面的shell命令响应变慢或无响应。
可能影响
- 平时正常的SQL语句,出现执行慢或一直处理执行中的现象,导致业务受影响;
- 操作系统响应慢,可能导致节点状态监测失败,触发告警;
- 可能导致节点状态监测失败,触发主备自动切换。
解决步骤
- 可以通过shell命令top、htop、w、uptime等命令查看负载情况。
关于负载的理解:
理想情况下,每个CPU 应该满负荷工作,并且没有等待进程,此时,平均负载 = CPU 逻辑核数。
但是,在实际生产系统中,不建议系统满负荷运行。通用的经验法则是:平均负载= 0.7 * CPU 逻辑核数。
1.当平均负载持续大于 0.7 * CPU 逻辑核数,就需要开始调查原因,防止系统恶化;
2.当平均负载持续大于 1.0 * CPU 逻辑核数,必须寻找解决办法,降低平均负载;
3.当平均负载持续大于 5.0 * CPU 逻辑核数,表明系统已出现严重问题,长时间未响应,或者接近死机。
除了关注平均负载值本身,我们也应关注平均负载的变化趋势,这包含两层含义。一是load1、load5、load15 之间的变化趋势;二是历史的变化趋势。
当load1、load5、load15 三个值非常接近,表明短期内系统负载比较平稳。此时,应该将其与昨天或上周同时段的历史负载进行比对,观察是否有显著上升。
当load1 远小于 load5 或 load15 时,表明系统最近 1 分钟的负载在降低,而过去 5 分钟或 15 分钟的平均负载却很高。
当load1 远大于 load5 或 load15 时,表明系统负载在急剧升高,如果不是临时性抖动,而是持续升高,特别是当 load5 都已超过 0.7 * CPU 逻辑核数 时,应调查原因,降低系统负载。
CPU 使用率是单位时间内 CPU 繁忙程度的统计。而平均负载不仅包括正在使用 CPU 的进程,还包括等待 CPU 或 I/O 的进程。因此,两者不能等同,有两种常见的场景如下所述:
CPU 密集型应用,大量进程在等待或使用 CPU,此时 CPU 使用率与平均负载呈正相关状态。
I/O 密集型应用,大量进程在等待 I/O,此时平均负载会升高,但 CPU 使用率不一定很高。
- TeleDB数据库常见操作系统负载高的问题及解决办法:
评估负载是否符合预期,业务SQL是否有明显的响应变慢,是否对业务造成影响,是否可控;根据评估结果,如需进行调整,通常调整策略有:
1)针对CPU密集型应用,此时CPU是瓶颈,表现为CPU 100%或接近100%
解决办法:以减少CPU或提升总CPU数据为主入手
a、抓取消耗CPU的高频高并发SQL,进行优化;
b、扩容节点组,将业务分散到更多的服务器上,使用更多的CPU资源;
a、高CPU资源的批量业务错峰执行,避免多个任务互相影响;
c、控制业务并发度。
2)针对I/O密集型应用,此时磁盘I/O是瓶颈,表现为磁盘I/O使用率100%或接近100%
解决办法:
a、以减少I/O操作为主入手
b、如优化业务逻辑,以COPY批量导入方式代替单行insert;
c、优化SQL语句,尽量避免大表全表扫描情况;
d、扩容节点组,将业务分散到更多的服务器上;
e、提高磁盘IO性能,更换更好的磁盘;
f、高I/O的批量业务错峰执行,避免多个任务互相影响;
g、降低高I/O的任务的并发度。
3)可能因为服务器内存不足,操作系统响应变慢引起的高负载
解决办法:参考内存不足问题处理。
网络问题
问题描述
实例节点之间、应用与CN节点之前出现网络延迟、拥塞、丢包等问题。
可能影响
- 应用连接CN节点失败;
- 执行SQL失败;
- 节点通信异常,导致触发主备节点自动切换;
- 主备复制可能会因网络丢包导致失败。
解决步骤
- 网络状况,可以使用ifstat或dstat查看,示例:
iftop、nmon也可以查看网络状态
- 针对包延迟、丢包的场景,可以使用ping、traceroute以及tcpdump抓包的方式进一步分析,此处不展开讨论;
- TeleDB数据库常见网络问题及解决办法:
1)网络带宽存在瓶颈
在性能压测、业务高峰期等场景,可能出现服务器的网络带宽被打满的情况。
解决办法:
a、分布式数据库在SQL执行时,CN、DN节点之间通信和数据交互需要消耗较多的网络资源,对带宽有较高的要求,在部署规划前期,应该确保集群内服务器网络是万兆带宽;
b、定期抓取消耗资源高的SQL语句,尤其多表关联的复杂SQL,返回结果集大SQL,进行优化,目标拆分简化复杂SQL写法,减少SQL重分布;针对返回结果集大的SQL,检查SQL逻辑,减少和去除不必要的排序操作,减少不必要的返回数据列。
2)节点之间有网络断开、丢包情况
综合服务器连接数情况,服务器负载情况,分析评估是否因业务量过大,服务器配置不足导致的服务器响应慢或无响应,从而导致节点间出现网络异常断开、丢包情况;
解决办法:
a、优先优化解决业务量中高频且效率不高的SQL;
b、避免后续此类问题出现,应该把控好新上线业务的SQL质量;
c、数据库服务器资源做适当预留,应充分考虑业务业务高峰期的资源使用情况,根据评估需要,横向或纵向扩容数据库;
d、也有其它原因可能导致节点之间网络断开,如服务器资源不足,操作系统主动kill数据库进程;或人力kill会话;触发异常导致节点crash并重启。这些异常需要联系运维工程师进一步分析处理。