唯一键表支持冷存去重,支持删除冷存数据中的重复数据,提升存储空间利用率。本文介绍了如何启用唯一键表冷存去重功能以及如何配置相关内存参数,减少内存占用。
在 ByteHouse 中,冷存数据存储在 S3 的同时,本地磁盘也会缓存远端的 unique_key.idx
索引文件,存储至 /remote_unique_key_index_cache/
目录中(所有唯一键表共享),可避免去重时频繁读取 S3 索引文件带来额外的性能开销。本地磁盘空间充足的前提下,/remote_unique_key_index_cache/
目录默认大小是 min(50 GiB,初始化容量大小为可用空间 * 0.25)
,如果存储目录达到存储上限,系统将触发 LRU(最近最少使用)淘汰机制。当远端 part(数据分片)转为非活跃状态并被清理后,该 part 在本地磁盘缓存的唯一键索引(unique key index)会通过唯一键表的后台清理线程异步删除。
为了实现更好的写冷存性能,唯一键表新生成的 part 都会生成在本地磁盘:主节点支持 write、merge、mutate 操作,备节点支持 fetch part 操作。满足 TTL 规则(按行设置过期时间)的 part 将通过后台 move 线程移动到 S3/HDFS 冷存储。
开启唯一键表冷存去重功能后,内存会短暂上升,这是因为系统在写入冷数据时需要对 S3 上的 parts 执行去重,由于 S3 上的 parts 可能未设置磁盘唯一索引(disk unique index),需先将 parts 数据读取至内存并构造内存唯一索引(memory unique index)。ByteHouse 支持通过内存唯一索引缓存机制(memory unique index cache)管理内存占用,通过后台线程及时淘汰、释放掉超过内存阈值的内存索引,提升全局内存限制的能力。如需限制内存唯一索引的内存占用,您可参考memory_unique_index_max_bytes设置参数阈值,启用后需要等待一段时间(分钟级)才会生效,可能短暂超过设定的内存阈值。
说明
Part 的内存索引采用 lazy 加载模式,在去重时被用到才会加载,新写入的 part 的内存索引并不会及时放在内存中,因此可能查出来内存索引总占用量为 0。
执行以下命令,开启唯一键表和冷存上 part 去重功能。启用后,仅支持对增量 part(即新写入的 part)去重。
alter table {db}.{table} on cluster {xxx} modify setting enable_unique_dedup_with_remote_disk = true;
参数说明
参数 | 默认值 | 含义 |
---|---|---|
enable_unique_dedup_with_remote_disk | false | 表级粒度,设置为 true 后,允许新的写入和远端的 parts 去重,保证唯一性。 |
注意
如果希望对所有表都生效,请参考修改配置参数,将参数添加到 config.xml
下的 <merge_tree></merge_tee>
中。调整参数后,需重启服务器生效。
以下操作以 S3 上的某张唯一键表为例。
开启冷存去重功能。请使用实际的库、表、集群名称替换以下命令中的变量。
alter table {db}.{table} on cluster {xxx} modify setting enable_unique_dedup_with_remote_disk = true;
开启冷存 merge 开关,否则当 S3 parts 过多时,将影响写入去重性能。
ALTER TABLE {db}.{table} on cluster {xxx} modify setting skip_merge_for_unique_data_in_remote_disk = false;
查看节点所有唯一键表的内存使用量。更多内存查询命令请参见memory_unique_index_max_bytes。
您可根据命令输出结果查看内存使用情况,如果内存使用量上升,您可按照步骤 4 的操作降低内存占用。
select formatReadableSize(sum(unique_index_bytes_in_memory)) from system.parts where engine = 'HaUniqueMergeTree';
(可选)若您的内存使用上升较多并期望降低内存,您可通过以下两种方法降低内存占用:
方法 | 操作说明 |
---|---|
调整 |
|
物化索引 | 执行物化索引命令,将某个分区的唯一键表的 memory unique index 转化为 disk unique index。该 mutation 操作比较重,建议按分区级别进行物化 index,避免一次性对过多 parts 重写,占满本地磁盘。
更多关于物化索引的说明,请参考 materialize unique index 章节。 |
您可使用以下命令查询磁盘索引缓存的大小和容量。该缓存用于存储 unique_key.idx
索引文件(按 part 粒度管理),支持 LRU 淘汰机制和全局内存限制。
SELECT metric, formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric LIKE 'UniqueKeyIndex%Bytes' Query id: 20528fa9-5d92-4961-90ae-1c221e8d8cb7 ┌─metric────────────────┬─formatReadableSize(value)─┐ │ UniqueKeyIndexMetaCacheBytes │ 0.00 B │ │ UniqueKeyIndexBlockCapacityBytes │ 20.00 GiB │ │ UniqueKeyIndexMetaCapacityBytes │ 10.00 GiB │ │ UniqueKeyIndexBlockCacheBytes │ 0.00 B │ └────────────────────┴──────────────────┘
内存唯一索引是内存表,用于存储 unique index 的数据。memory_unique_index_max_bytes
参数可用于限制内存唯一索引的最大可用内存,避免内存溢出(OOM)。
查看内存唯一索引最大容量:
-- 查询 Memory unique index 最大容量: SELECT metric, formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric LIKE 'MemoryUniqueKeyIndex%'
查看内存唯一索引占用内存情况:
-- 获取节点所有 unique 表的 memory index 内存使用量 select formatReadableSize(sum(unique_index_bytes_in_memory)) from system.parts where engine = 'HaUniqueMergeTree'; -- 获取节点 memory index 内存使用量 Top 10 的 unique 表 select database || '.' || table as db_tbl, formatReadableSize(sum(unique_index_bytes_in_memory)) from system.parts where engine = 'HaUniqueMergeTree' and active group by db_tbl order by sum(unique_index_bytes_in_memory) desc limit 10; -- 查询某张表 memory unique index 总计内存 SELECT formatReadableSize(sum(unique_index_bytes_in_memory)) FROM system.parts WHERE engine = 'HaUniqueMergeTree' and table = '';
使用内存唯一索引将指定 parts 通过变更(mutation)转化为使用本地磁盘唯一索引的 parts,以降低内存。该命令也称物化索引,这里物化的含义是指将内存态的 index 转化为磁盘态的 index。您可在主、备节点上执行该命令,备节点接收到命令后会转发给主节点。示例如下:
ALTER TABLE materialize_unique_index_{table.table_name} [on cluster {}] MATERIALIZE UNIQUE INDEX;
ALTER TABLE materialize_unique_index_tests.test_table1 [on cluster {}] MATERIALIZE UNIQUE INDEX;
ALTER TABLE materialize_unique_index_tests.test_table1 on cluster {} MATERIALIZE UNIQUE INDEX IN PARTITION '2024-10-02';