本文为您介绍Hologres监控指标相关的常见问题。
连接数过多时如何查看有哪些连接以及Kill连接?
连接数包括实例中总的SQL连接数,包括Active、Idle状态的JDBC/PSQL等连接。实例的连接数通常与实例的规格有关,如果您发现连接数过多,甚至出现超出实例最大连接数的情况,或者遇到如下报错:
产生
FATAL: sorry, too many clients already connection limit exceeded for superusers
报错。产生
FATAL: remaining connection slots are reserved for non-replication superuser connections
报错。
说明实例连接数已达上限,通过HoloWeb或者SQL的方式查看当前的连接情况,详情请参见连接数管理。可以使用Superuser账号对不符合预期或者Idle的连接进行Kill操作。
查询延迟过高时如何解决?
常见的延迟过高有以下几种原因,可以先通过慢Query日志查找对应的慢SQL并根据如下的情况进行解决,详情请参见慢Query日志查看与分析。
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%左右都属于正常现象。
一些情况下,会使得内存使用率持续升高,甚至接近80%。主要原因如下:
表越来越多,数据总量越来越大,以至于数据规模远大于当前计算规格。由于内存使用率和元数据、索引量存在正相关关系,因此,表的数量越多,数据量越大,索引越多,都会导致内存使用率升高。
索引不合理,例如表的列特别多,TEXT列居多,设置了过多的Bitmap或Dictionary索引。此情况可以考虑去掉一些Bitmap或者Dictionary索引,详情请参见ALTER TABLE。
但是当内存使用率稳定增长,长期接近80%时,通常意味着内存资源可能成为了系统的瓶颈,可能会影响实例的稳定性和或性能。稳定性影响体现在当元数据等过大,超额占据了正常Query可用的内存空间时,在查询过程中,可能会偶发SERVER_INTERNAL_ERROR
、ERPC_ERROR_CONNECTION_CLOSED
、Total memory used by all existing queries exceeded memory limitation
等报错。性能影响体现在当元数据等过大,超额占据了正常Query本来能够使用的缓存空间,从而缓存命中会减少,Query延迟会增加。
因此当内存长期接近80%时,有如下几个操作建议。
删除不再查询的数据,以释放元数据等占用的内存。
设置合理的索引,若是业务场景用不上的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%如何解决?
当Hologres实例CPU使用率长期接近100%时(例如CPU使用率连续3小时满载100%,或者连续12小时达到90%以上等),说明实例负载非常高,这通常意味着CPU资源成为了系统的瓶颈,需要分析具体的业务场景和查询,以判断原因。可以从以下几方面进行排查。
排查一: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上涨,存在消耗CPU较高的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时长较长如何解决?
监控指标正在运行Query持续时长中有长时间运行的Query,例如运行时长大于1小时。当出现有长时间运行的Query时,可以先通过活跃Query页面查看正在运行的Query,详情请参见Query管理。正在运行Query时长较长,通常有以下几种情况,可以根据实际情况进行排查。
情况一:实例有较长时间的写入。
解决方法:通过监控指标的实时写入RPS指标查看是否有持续的写入任务,从而导致出现Query运行时间较长的情况。
情况二:事务空闲(idle in transaction)。
客户端打开事务,进行DDL后未进行commit操作,使用如下SQL命令查询活跃Query状态,Query的状态显示为
idle in transaction
,且运行时间较长。--查看运行时间较长的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因为等锁卡住等原因,导致长时间运行中。
解决方法:通过以下示例SQL查询出运行时间较长的Query,如果是因为
idle in transaction
导致运行时间较长,可以客户端关闭事务或者设置合理的空闲事务超时时间,详情请参见修改空闲Query超时时间。--查看运行时间较长的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; --superuser取消query执行 select pg_cancel_backend(<pid>);
情况三: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。
失败Query如何排查?
失败Query代表每秒钟失败的Query。Query总数量是时间范围乘以QPS个数,即时间范围内的面积。不建议依赖QPS来判断失败的总数量。可以通过慢Query日志排查Query总的失败数量和失败原因,并根据报错针对性地解决,详情请参见慢Query日志查看与分析。
Worker CPU负载不均如何解决?
在Hologres中数据分片(Shard)决定了数据的分布情况,一个Worker在计算时可能会访问一个或者多个Shard的数据。同一个实例中,一个Shard同一时间只能被一个Worker访问,不能同时被多个Worker访问。如果实例中每个Worker访问的Shard总数不同,那么就有可能出现Worker资源负载不均的情况,主要原因如下:
原因一:存在数据倾斜。
如果数据存在严重的倾斜,那么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资源。