本文为您介绍Hologres监控指标相关的常见问题。
- 连接数过多时如何查看有哪些连接以及Kill连接?
- 查询延迟过高时如何解决?
- 内存使用率高的原因及解决方法?
- 为什么只有一个任务,Hologres实例CPU使用率就达到100%?
- 写入慢如何解决?
- CPU使用率长期达到100%如何解决?
- 正在运行Query时长较长如何解决?
- 失败Query如何排查?
- Worker CPU负载不均如何解决?
连接数过多时如何查看有哪些连接以及Kill连接?
- 产生
FATAL: sorry, too many clients already connection limit exceeded for superusers
报错。 - 产生
FATAL: remaining connection slots are reserved for non-replication superuser connections
报错。
查询延迟过高时如何解决?
- QPS较低,但查询SQL较复杂,导致查询延迟高。
解决方法:对SQL进行优化,设置合理的索引,以提高查询性能,详情请参见优化内部表的性能和优化MaxCompute外部表的查询性能。
- 查询的QPS较高,导致查询延迟较高。
解决方法:若是SQL已经优化完毕,但需要更高的QPS以及更低的延迟,可以扩容实例,用更多的资源获取更好的性能,详情请参见实例升配。
- 查询时还有大量的写入,写入影响查询,导致查询延迟高。
解决方法:写入影响了查询性能,可以进行如下操作。
- 写入在查询低峰期进行,降低对查询的影响。
- 降低写入的并发度,提高查询效率,如果是外表写入,可以用以下参数降低并发度。
--设置MaxCompute执行的最大并发度,默认为128,建议数值设置小一些,避免一个Query影响其他Query,导致系统繁忙导致报错。 set hg_experimental_foreign_table_executor_max_dop = 32; --优先考虑设置 --调整每次读取MaxCompute表batch的大小,默认8192。 set hg_experimental_query_batch_size = 1024; --直读orc set hg_experimental_enable_access_odps_orc_via_holo = on; --设置MaxCompute表访问切分spilit的数目,可以调节并发数目,默认64MB,当表很大时需要调大,避免过多的split影响性能。 set hg_experimental_foreign_table_split_size = 512MB;
内存使用率高的原因及解决方法?
Hologres实例的内存使用率为内存综合使用率。Hologres的内存资源采用预留模式,在没有查询的时候,也会有数据表的元数据、索引、数据缓存等加载到内存中,以便加快检索和计算,此时内存使用率不为零是正常情况。理论上在无查询的情况,内存使用率达到30%~40%左右都属于正常现象。
- 表越来越多,数据总量越来越大,以至于数据规模远大于当前计算规格。由于内存使用率和元数据、索引量存在正相关关系,因此,表的数量越多,数据量越大,索引越多,都会导致内存使用率升高。
- 索引不合理,例如表的列特别多,TEXT列居多,设置了过多的Bitmap或Dictionary索引。此情况可以考虑去掉一些Bitmap或者Dictionar索引,详情请参见ALTER TABLE。
但是当内存使用率稳定增长,长期接近80%时,通常意味着内存资源可能成为了系统的瓶颈,可能会影响实例的稳定性和或性能。稳定性影响体现在当元数据等过大,超额占据了正常Query可用的内存空间时,在查询过程中,可能会偶发SERVER_INTERNAL_ERROR
、ERPC_ERROR_CONNECTION_CLOSED
、Total memory used by all existing queries exceeded memory limitation
等报错。性能影响体现在当元数据等过大,超额占据了正常Query本来能够使用的缓存空间,从而缓存命中会减少,Query延迟会增加。
- 删除不再查询的数据,以释放元数据等占的内存。
- 设置合理的索引,若是业务场景用不上的bitmap和dictionary,可以去掉,但不建议直接去掉,需要根据业务情况具体分析。
- 升配实例的计算和存储资源。对于升配的建议是:
- 普通场景:可以容许读磁盘数据的延迟,响应时间要求不严格,1CU(1Core+4GB内存)可以支持50~100GB的数据存储。
- 响应时间要求低的Serving场景:最好查询热点数据全在内存的缓存中。内存中缓存的比例默认占总内存的30%,即1CU(1Core+4GB内存)其中1.3GB用于数据缓存,同时数据缓存还会被表的元数据所使用一些。举个例子,低响应要求的场景,热点数据如果是100GB,那么最好要求100GB 在缓存可用(实际上数据读出来解压后,占用内存不止100GB),因此至少需要约320GB内存以上,从而推算计算资源至少需要96CU左右。
为什么只有一个任务,Hologres实例CPU使用率就达到100%?
Hologres实例的CPU使用率为实例的CPU综合使用率。Hologres因其可以充分发挥多核并行计算的能力,通常来说单个查询可以迅速将CPU使用率提高到100%,这说明计算资源得到了充分利用。CPU使用率高不是问题,CPU使用率高了之后,查询慢写入慢才是问题,需要综合分析。
写入慢如何解决?
执行insert
、insert on conflict
或update
命令时,耗时比较长即写入性能较差,通常原因是因为SQL没有走Fixed Plan,没有走Fixed Plan的SQL命令存在表锁,并发执行时会等锁,导致耗时较长,实时写入RPS
监控指标会显示写入类型为insert
。可以查看Query的特征改写为走Fixed Plan的方式,让监控指标的写入类型变成SDK
提升写入性能,详情请参加Fixed Plan加速SQL执行。
CPU使用率长期达到100%如何解决?
- 排查一:QPS或者RPS明显上涨。
对比CPU使用率上涨前和上涨后的QPS和RPS监控指标,如果有明显的上涨趋势,而导致CPU使用率上涨。
解决方法如下。- 查询数据(select)行为导致CPU使用率上涨,可以通过慢Query日志,排查耗时较长的Query,对Query进行针对性优化。
- 执行
insert
、update
或delete
操作导致CPU使用率上涨,建议通过慢Query日志排查Query是否未走Fixed Plan,如下SQL所示。未走Fixed Plan的insert
、update
或delete
命令会产生表锁,Query并发会造成锁等待,可以从业务上判断是否可以改写为走Fixed Plan的SQL,避免表锁,降低CPU水位。--示例查看过去一小时未走fixed plan的insert/update/delete select * from hologres.hg_query_log where query_start >= now() - interval '3 h' and command_tag in ('INSERT','UPDATE','DELETE') and 'HQE'=ANY(engine_type) order by query_start desc limit 500;
- SQL都已经合理,但是CPU使用率还是比较高,说明实例资源已到瓶颈,可以适当的扩容或者使用多实例共享存储部署从而读写分离,详情请参见实例升配或多实例读写分离高可用部署(共享存储)。
- 排查二:未有明显的QPS或者RPS上涨,存在运行时间较长的Query。
通过监控指标发现没有明显的QPS或者RPS上涨,但是CPU使用率却突然上涨并且持续一段时间,可以通过
正在运行Query持续时长
监控指标查看是否有运行时间较长的Query,若监控指标显示有运行时长超过半个小时或者一小时的Query,说明是该Query导致的CPU使用率高。使用如下命令通过活跃Query查询运行的Query,并结束Query,从而降低CPU使用率。--查看运行时间较长的query SELECT current_timestamp - query_start as runtime, datname::text, usename, query, pid::text FROM pg_stat_activity WHERE state != 'idle' order by 1 desc; --取消query执行 select pg_cancel_backend(<pid>);
- 排查三:未有明显的QPS或者RPS上涨,存在耗时较长的Query。
通过监控指标发现没有明显的QPS或者RPS上涨,但是CPU使用率却突然上涨并且持续一段时间,可以通过如下命令从慢Query日志查看消耗CPU较高的Query,从而定位CPU消耗的操作,并根据Query优化SQL。
-- 查询最近3小时消耗比较高的Query select status as "状态", duration as "耗时(ms)", query_start as "开始时间", (read_bytes/1048576)::text || ' MB' as "读取量", (memory_bytes/1048576)::text || ' MB' as "内存", (shuffle_bytes/1048576)::text || ' MB' as "Shuffle", (cpu_time_ms/1000)::text || ' s' as "CPU时间", physical_reads as "读盘量", query_id as "QueryID", query from hologres.hg_query_log where query_start > current_timestamp - interval'3 h' and command_tag in ('SELECT','INSERT','UPDATE','DELETE') and duration > 1000 order by duration desc, read_bytes desc, shuffle_bytes desc, memory_bytes desc, cpu_time_ms desc, physical_reads desc limit 500;
- 排查四:PQE的SQL导致CPU使用率达到100%。
通过监控指标发现未有明显的QPS或者RPS上涨,可以使用如下SQL命令从慢Query日志查询是否有新增的PQE SQL,导致CPU使用率上涨。如果存在PQE SQL,则需要优化SQL中走PQE引擎的算子,详情请参见优化内部表的性能。
--查询最近3小时走PQE的query select * from hologres.hg_query_log where query_start > current_timestamp - interval'3 h' and 'PQE'=ANY(engine_type) order by query_start desc limit 500;
- 排查五:对表修改过Bitmap或者Dictionary索引。
对表修改过Bitmap或者Dictionary索引,修改后会触发后台异步执行Compaction,占用一定的CPU资源,同时实例的存储量可能会出现先上升后回落的情况,可以使用如下SQL命令示例从慢Query日志查询是否有修改过索引。
--查询最近3小时内执行过修改索引的记录 select * from hologres.hg_query_log where query_start >= now() - interval '3 h' and command_tag in ('CALL') order by query_start desc limit 500;
正在运行Query时长较长如何解决?
- 情况一:实例有较长时间的写入。
解决方法:通过监控指标的实时写入RPS指标查看是否有持续的写入任务,从而导致出现Query运行时间较长的情况。
- 情况二:事务空闲(idle in transaction)。
- 客户端打开事务,进行DDL后未进行commit操作,使用如下SQL命令查询活跃Query状态,Query的状态显示为
idle in trancation
,且运行时间较长。 - Query因为等锁卡住等原因,导致长时间运行中。
解决方法:通过以下示例SQL查询出运行时间较长的Query,如果是因为
idle in trancation
导致运行时间较长,可以客户端关闭事务或者设置合理的空闲事务超时时间,详情请参见修改空闲Query超时时间。 - 客户端打开事务,进行DDL后未进行commit操作,使用如下SQL命令查询活跃Query状态,Query的状态显示为
- 情况三:SQL运行复杂且有PQE的Query。
解决方法:通过以下命令查询当前正在运行且运行时间较长的Query,然后通过执行计划(explain sql)查看当前有SQL走了PQE引擎(执行计划中有
External SQL(Postgres)
),导致执行时间较长。--查看运行时间较长的query SELECT current_timestamp - query_start as runtime, datname::text, usename, query, pid::text FROM pg_stat_activity WHERE state != 'idle' order by 1 desc; --查看query的执行计划 explain sql
- 使用Superuser账号Kill运行时间较长的Query。
- 优化SQL中走PQE引擎的算子,详情请参见优化内部表的性能。
- 情况四:并发执行DDL导致抢锁。
并发执行DDL时会锁表,导致互相抢锁,从而出现等锁,导致运行时间较长。
解决方法:- 可以通过如下命令查看是否有DDL正在执行中,并Kill掉对应的DDL,释放锁。
SELECT datname::text,usename,query,pid::text,state FROM pg_stat_activity WHERE state != 'idle' ;
- 串行执行DDL。
- 可以通过如下命令查看是否有DDL正在执行中,并Kill掉对应的DDL,释放锁。
失败Query如何排查?
失败Query代表每秒钟失败的Query。Query总数量是时间范围乘以QPS个数,即时间范围内的面积。不建议依赖QPS来判断失败的总数量。可以通过慢Query日志排查Query总的失败数量和失败原因,并根据报错针对性的解决,详情请参见慢Query日志查看与分析。
Worker CPU负载不均如何解决?
- 原因一:存在数据倾斜。
如果数据存在严重的倾斜,那么Worker的负载就会访问固定的Shard,导致出现CPU负载不均的情况。
解决方法:需要通过以下语句排查数据倾斜。如示例结果,某个Shard的数值比其他Shard大太多,从而出现数据倾斜。可根据业务情况处理倾斜数据或者设置合适的Distribution Key,详情请参见优化内部表的性能。select hg_shard_id,count(1) from <table_name> group by hg_shard_id; --示例结果:shard 39的count值较大,存在倾斜 hg_shard_id | count -------------+-------- 53 | 29130 65 | 28628 66 | 26970 70 | 28767 77 | 28753 24 | 30310 15 | 29550 39 | 164983
- 原因二:实例设置的Shard数和Worker个数不是整倍数关系。
当Table Group中设置的Shard数和实例的总Worker数不是整倍数关系时,意味着不同的Worker上分配的Shard数不同,从而导致负载不均。
解决方法:根据实例规格,设置合理的Shard数,详情请参见Table Group与Shard Count操作指南。一般这种情况出现在较大规格(大于256Core)的实例上,小规格实例可以使用默认Shard数,无需更改。
- 原因三:有Worker Failover后导致Shard分配不均。
当有Worker因为OOM等原因而被终止(Kill)时,为了能快速恢复Worker的查询,系统会将该Worker对应的Shard,快速迁移至其他Worker。当被Kill的Worker被拉起后,系统会再分配部分Shard给它,从而出现Worker间Shard分配不均的现象。
解决方法:如果实例负载较低,可忽略该负载分配不均的问题。如果实例负载较高,可以重启实例以重新均匀分配Shard资源。