预加载 Preload 主要用于加速实时表写入。在数据通过 INSERT 写入和 MERGE 写入时,新写入的远程 PART 会被立即加载到表绑定的读 VW 中,并以本地缓存的形式存在。这样,当用户访问相关数据时,能够直接读取热数据,从而避免冷读导致的性能抖动。
若要开启某个表的 Preload,需要进行以下参数设置:
更多参数含义如下:
类别 | 名称 | 默认值 | 说明 |
---|---|---|---|
system | parts_preload_level | 1 |
0:关闭,所有表生效,即使表级别配置了开启参数
0:关闭,原则上manual-prelaod时不应指定为0 |
disk_cache_mode | auto | 控制查询时候的DiskCache模式: | |
drop_vw_disk_cache | 0 | 用于drop disk cache时控制是否清空表所在VW上的所有表cache: | |
cnch_parallel_preloading | 0 | 用于控制reader节点缓存Part的并发:
| |
preload_send_rpc_max_ms | 3000 | 用于控制writer节点和server节点发送rpc的超时时间 | |
part_allocation_algorithm | 2 | PART分发的一致性HASH规则,在不设置表级别的该参数时,以此参数为准。 | |
table | parts_preload_level | 0 | 用于控制当前表开启Preload的级别: |
enable_parts_sync_preload | 0 | 用于控制auto-preload任务执行模式: | |
enable_preload_parts | 0 | 旧配置,用于兼容表旧有的设置。如果之前没有使用过该配置,则忽略即可。 | |
enable_gc_evict_disk_cache | 0 | 开启后,Part被清理后对应缓存会被一并清理 | |
cnch_part_allocation_algorithm | -1 | 开启后,查询将优先按照表级别分配算法分配part |
Preload 分为两种方式并包含清空操作:
# 手动Preload Cache:当表关闭Preload设置后,该操作将无效 ## -[partition p]:要手动加载的分区名字,如果不填写则默认加载全表 ## -[SYNC|ASYNC]:手动加载任务的执行方式,同步使用独立线程;异步则与全局Cache共用一个线程,有概率部分任务失败;不指定的话默认为ASYNC ## -[SETTINGS parts_preload_level = 1]:指定preload的粒度,参见上面表格叙述 ## -[SETTINGS virtual_warehouse = '']:指定preload data加载到的目标VW,若不指定则使用表绑定的VW alter disk cache preload table [db.]table_name [partition p] [SYNC|ASYNC] [SETTINGS parts_preload_level = 1, virtual_warehouse = 'vw_name']
# 根据加载级别设置parts_preload_level值 alter table [db.]table_name modify setting parts_preload_level = 1;
# 手动 Drop Cache ## -[table [db.]table_name] [partition p] [SYNC|ASYNC]:与Preload定义相同 ## -[SETTINGS drop_vw_disk_cache=1]:当指定1时,将清理该表所在VW上的所有表的缓存 alter disk cache drop [table [db.]table_name] [partition p] [SYNC|ASYNC] [SETTINGS drop_vw_disk_cache = 1]
当发现某个表的缓存命中率比较低时:
cnch_part_allocation_algorithm
、cnch_hybrid_part_allocation_algorithm
会存在相关性。
- 当cnch_part_allocation_algorithm > 0时,SQL对应的PARTS会可能会通过rebalance策略重新调整一致性HASH结果,以保证PART在节点的分布尽量均衡。如果Preload的PARTS在分发时不需要rebalance,则将导致同一个PART对于Preload和Query来说会落到不同的节点上,最终的结果即Preload的PART不能被后续的Query查询命中。
- cnch_hybrid_part_allocation_algorithm > 0时,与part_allocation_algorithm类似,会重新调整PART分发的策略,导致与Preload不一致。
产生上述不一致的根本原因在于,当一个PART在不同的分发组时,不论是rebalance策略还是hybrid策略都会重新进行节点分配。而Preload的PARTS组与Query的PARTS组往往都不一致,因此在做节点调整时很容易引发不一致。
每次的Preload任务都会记录在READER节点上的system.part_log系统表中,注意:必须写table like {table%}
。
SELECT * FROM cnch('{vw_name}', system.part_log) where database = xxx and table like xxx ORDER BY event_time DESC LIMIT 5
一个典型的日志记录如下:
以2.0为例,查看每个Query的缓存命中率使用如下SQL:
SELECT any(event_time) AS time, formatReadableSize(sum(ProfileEvents['ReadBufferFromS3ReadBytes'] + ProfileEvents['ReadBufferFromHdfsReadBytes'])) AS remote, formatReadableSize(sum(ProfileEvents['ReadBufferFromFileDescriptorReadBytes'])) AS disk, max(query_duration_ms) AS ms, max(round((MaxIOThreadProfileEvents['RemoteFSAsynchronousReadWaitMicroseconds'] + MaxIOThreadProfileEvents['RemoteFSSynchronousReadWaitMicroseconds']) / 1000)) AS remote_ms, max(round((MaxIOThreadProfileEvents['DiskReadElapsedMicroseconds']) / 1000)) AS disk_read_ms, round(sum(ProfileEvents['ReadBufferFromFileDescriptorReadBytes']) / (sum(ProfileEvents['ReadBufferFromS3ReadBytes'] + ProfileEvents['ReadBufferFromHdfsReadBytes'] + ProfileEvents['ReadBufferFromFileDescriptorReadBytes'])), 2) AS hit_rate FROM cnch('vw-851725483243-xxl-16', system.query_log) # 换成对应的VW名称 WHERE (event_date = today()) and GROUP BY initial_query_id ORDER BY time DESC LIMIT 100
如果想查看整体天级别的缓存命中率变化,请使用如下SQL:
select event_date, round(quantile(0.90)(query_duration_ms)) as p90, round(quantile(0.95)(query_duration_ms)) as p95, count(*) as total, round(sum(hit_rate) / total, 2) as average_hit_rate, round(sum(if (hit_rate >= 0.99, 1, 0)) / total, 2) as _99_total, round(sum(if (0.99 > hit_rate and hit_rate >= 0.95, 1, 0)) / total, 2) as _95_total, round(sum(if (0.95 >= hit_rate and hit_rate > 0.90, 1, 0)) / total, 2) as _90_total, round(sum(if (0.90 >= hit_rate and hit_rate > 0.50, 1, 0)) / total, 2) as _50_total, round(sum(if (hit_rate <= 0.50, 1, 0)) / total, 2) as _00_total from ( select event_date, query_duration_ms, initial_query_id from cnch(server, system.query_log) WHERE tables[1] like '%seamless_app%' AND (event_date >= today() - 7) AND (query_duration_ms > 0) # 换成对应的表名 ) as server INNER JOIN ( select initial_query_id, query_id, ProfileEvents['ReadBufferFromS3ReadBytes'] + ProfileEvents['ReadBufferFromHdfsReadBytes'] AS remote_bytes, ProfileEvents['ReadBufferFromFileDescriptorReadBytes'] AS disk_bytes, query_duration_ms, (MaxIOThreadProfileEvents['RemoteFSAsynchronousReadWaitMicroseconds'] + MaxIOThreadProfileEvents['RemoteFSSynchronousReadWaitMicroseconds']) / 1000 AS s3_read_ms, disk_bytes / (remote_bytes + disk_bytes) as hit_rate from cnch('vw-851725483243-xxl-16', system.query_log) # 换成对应的VW名称 where query_duration_ms > 0 and remote_bytes + disk_bytes > 0 and (event_date >= today() - 7) ) as worker on server.initial_query_id = worker.initial_query_id group by event_date
一般情况下,开启Preload后如果缓存命中率有明显提升,则说明Preload的缓存发挥了作用,但是如果效果不明显,请按照调优步骤进行操作。详细的排查手段如下: