业务场景:存在实时数据,需要更新
当前情况:单机表可以实现 增删改查操作。但是集群表不行,特此引入ReplacingMergeTree引擎,实施ch后台自动去重操作
特别提示:该引擎不能完全依赖去做去重,可能因为merge合并及诸多原因,存在极少量去重失败情况
实际部署:
本地表:
ReplacingMergeTree(【ver】) PARTITION BY day PRIMARY KEY MsgId ORDER BY (MsgId, updateTime)
集群表:
Distributed(cluster_name, database, table, toUnixTimestamp(updateTime))
提示:
集群表按toUnixTimestamp(updateTime) 分发,以便于当遇到重复数据时,数据能准确分发到指定的那个单机ch中,而不是相同数据rand()随机分发,致前后位置不一,无法去重。
本地表以MsgId 做唯一主键,默认,MsgId, updateTime 排序。而按【ver】字段判断数据版本。该字段可以是INT或datatime类型。我用的实时插入的now()。当ch_server在进行merge时,查到相同主键的数据 ,会去自动判别ver版本,取最新的版本数据做保留。本质上来讲,该引擎原本是为了减少存储空间,过滤垃圾数据而做的。恰巧可以借此做去重。可能会因数据源写入超时等原因,产生少量merge失败的情况,无法解决去重问题。
merge数据存储合并问题:
MergeTree 引擎数据存储结构为上图,其中:
20200421代表 分区id
31014 代表 最小block数
31223 代表最大 block数
3 代表 tree的深度。即合并层级
有时,文件后还会有额外一个参数active_status,1为已激活状态,0为未激活状态。未激活状态数据指未合并到指定block中的临时小数据及处理失败的碎片数据(比如truncate 未完全及detach 后的数据)。多为 detach数据。一般在detach解除绑定后,数据会存储在detached目录中
数据会以上图形式,进行相应合并。由此看出,MergeTree 引擎 的异步去重机制,与数据量写入频率,数据量大小也有一定关系。
异步去重机制,一般要几分钟之后才会自动去重,可以做测试等待一段时间。且连续写入数据。
OPTIMIZE TABLE 本地表。可以快速刷新数据,即时查看去重效果。但性能影响较大,不建议实时刷新
存储:
index_granularity 索引粒度。多个主键的标记达到默认值8192,为一个标记存储。一般稀疏索引查询时会查询8192*2的数据量
数据存储在.bin文件中
标记(index_granularity) 存储在.mrk 文件中,文件中的偏移量到压缩块的开头,以及解压缩块中的偏移量到数据的开头。通常,压缩块通过标记对齐,并且解压缩块中的偏移量为零。
内存中存储.idx , 缓存.mrk
读取过程: 首先寻找.idx主键中的数据范围,然后在mrk中查询标记偏移量。一般读取索引粒子整个行的范围,并解压。
稀疏索引: 数据相隔8192列创建一个标记 即一个稀疏索引。更好的过滤数据及避免类似mysql B树一样耗费资源情况
(1)随着索引中的列增多,划分数据会更稀疏,建立的索引也需要更多,影响写入性能,也会增加内存的使用
(2)相比普通的B树索引,稀疏索引需要的内存更少,但是可能导致需要扫描的行数比实际的多
(3)默认"8192",若大量数据极其类似,可适当调大。
因为稀疏索引(有助于数据过滤)的原因,主键并不是唯一的,无法确保insert 时 主键检测。