herefree 发布的文章

Consumerid+primarykey+fixed bucket

Source

MonitorSource

主要负责读取快照,下发datasplit到下游Operator。
snapshot时将快照id存储,之后在notifyComplete时将consumerid写入。
pollNext时会将splits(元数据信息)下发到下游readerOperator,通过readerBuilder.scan.plan.split。由于readbuilder在创建时已经将flink的各种filter已经传进来,因此在plan时会根据元数据里面的信息进行一大波的过滤。

ReadOperator

Datasplit下发到readerOperator之前会将根据partition+bucket信息进行shuffle确保相同分区+bucket的数据发向对应的ReaderOperator。

readerOperator主要是根据datasplit中信息读取真正的数据文件,以及上报一些metrcis(ps:SOURCE_IDLE_TIME是我实现的)在读取真正数据文件时也会根据一些过滤条件进行过滤,例如:fileindex或者delevectors。

Sink

RowDataStoreWriteOperator

主要将数据写入到磁盘,以及做compaction其中compaction中还有一些快照过期等操作。
写数据时,会首先写入writerbuffer中(此处调用sun.misc.Unsafe使用的堆外内存自己管理释放),如果buffer满了之后在flush到磁盘,另外在snapshotshot之前会强制flush到磁盘。写入数据时会根据不同的mergerfunction进行合并。写入changelog时会根据changlog producer,Input模式会直接写入,none不写入,lookup以及fullcompaction时会在compaction时写入数据。

CommitterOperator

主要将上游产出的元数据写入到磁盘。
在processElement时会首先将上游传来的数据存储到内存里Deque
在Snapshot时把内存中的所有 Committable 根据 CheckpointId 来做聚合成一些ManifestCommittable。之后存到state里面。
notifyComplete时,会将元数据信息提交到外部存储。在提交时还会有一些冲突检测,如果snapshot冲突(两个writer同时写)会抛弃这次写入,在写一次并且合并上次snapshot产出的元数据文件(paimon实现是一个while(true)的循环)。
File冲突,主要是因为compaction时标记量文件为逻辑删除,例如上个快照已经标记某个file文件为逻辑删除状态了,当前状态中又标记了某文件为逻辑删除,这会产生不一致,因此需要重启,抛弃这次的compaction快照。

概述

索引是用于加速数据查询和访问的重要数据结构,用户可以对某些字段设置索引,进行查询时可以加快检索的速度,当前Paimon 支持的索引有BloomFilter与Bitmap两种索引,当前0.9.0版本索引支持append only表结构,代码master分支已经支持了主键表。

File Index原理

文件索引本质上是在写入数据时格外针对进行索引的字段写一份用于索引的索引文件,然后在用户进行数据查询时根据用户指定的where 语句里面的匹配规则先根据索引文件进行一次过滤.
Paimon整体过滤流程如下:

读取

index1.jpg
Flink 在使用consumerid模式消费paimon时会产生两个节点,一个是monitor节点(读取元数据产出元数据)一个是reader节点(真正去并发读取数据),其中monitor主要是用来读取快照信息,并根据一些过滤条件对paimon的元数据进行过滤,最终产出split(经过一系列过滤产出的元数据信息)下发到reader的节点。reader节点在根据splits信息去真正到hdfs上读取数据。
Paimon的Index有两个地方可以存储一个是存储到Manifest中(当index文件较小时),另外是存储在datafile中(当index文件较大时)threshold是500bytes。(如果index特别大,放在monitor中读取有OOM风险)
我们可以看上图,通过索引进行过滤可以在scan时进行,也可以在真正读取数据时进行。Paimon在实现FlinkSource时继承实现了Flink的SupportsFilterPushDown会将filter信息传输给Paimon如下图:
index2.png
Index在元数据
Paimon获取到Flink传来的Filter之后会转换成自己的Predicate,之后逐级传输下去,最终在AbstractFileStoreScan&plan中对获取的元数据进行过滤,如下图在我圈出来的地方都会进行过滤,不只是根据index进行过滤Paimon之前也有些过滤Partition等等之类的优化也在这块。
index3.png
index在数据文件
读取数据文件相关逻辑在Flink的ReadOperater中,在processElement方法读取Split时对数据进行过滤。
index4.png

写入

写入就是在写数据之前向index文件中写一份。
index5.png
存储格式

  _____________________________________    _____________________
|     magic    |version|head length |
|-------------------------------------|
|            column number            |
|-------------------------------------|
|   column 1        | index number   |
|-------------------------------------|
|  index name 1 |start pos |length  |
|-------------------------------------|
|  index name 2 |start pos |length  |
|-------------------------------------|
|  index name 3 |start pos |length  |
|-------------------------------------|            HEAD
|   column 2        | index number   |
|-------------------------------------|
|  index name 1 |start pos |length  |
|-------------------------------------|
|  index name 2 |start pos |length  |
|-------------------------------------|
|  index name 3 |start pos |length  |
|-------------------------------------|
|                 ...                 |
|-------------------------------------|
|                 ...                 |
|-------------------------------------|
|  redundant length |redundant bytes |
|-------------------------------------|    ---------------------
|                BODY                 |
|                BODY                |
|                BODY                 |             BODY
|                BODY                 |
|_____________________________________|    _____________________

column number:索引列数量
column 1:被索引的某一列
index number:这一列设置的索引类型个数(支持某一列设置多个索引)
index name 1 |start pos |length :索引名,以及索引的开始位置,长度。
BODY:具体索引内容

Bloom Filter

使用方式
file-index.bloom-filter.columns配置,配置用户想要增加索引的字段。
file-index.bloom-filter.<column_name>.fpp配置此列允许的错误率 默认0.1
file-index.bloom-filter.<column_name>.items配置此列预期的非重复项 默认100000
限制

  1. 对于新建的表来说直接设置'file-index.bloom-filter.columns'字段就可以,对于旧表,需要回刷一下索引文件回刷接口CALL sys.rewrite_file_index(table => 'test_db.T'),并且写入旧表的任务重启下确保索引相关配置生效。
  2. 不支持的数据类型 Array、mutiset、map、row、decimal、boolean

原理
Bloom Filter主要是对于=进行过滤,当用户查询时select * from t where b=1;首先会查找bloom过滤中是否有这种数据 bloomfiter中如果没有此数据就直接返回空,如果有的话在进一步查寻具体的数据表。

Bitmap

使用方式
在配置中添加file-index.bitmap.columns
限制

  1. 对于新建的表来说直接设置'file-index.bitmap.columns'字段就可以,对于旧表,需要回刷一下索引文件CALL sys.rewrite_file_index(table => 'test_db.T'),并且写入旧表的任务重启下确保索引相关配置生效。
  2. 不支持的数据类型

    Map
    Row
    Mutiset
    Array
    Decimal
    Binary
    Varbinary
    

原理
Bitmap 索引 会将索引的字段存储到bitmap中,每次where 条件中有bitmap中的字段,会先在bitmap查询数据是否存在,如果存在的话在继续查询读取数据,如果不存在直接返回空,可以对in,=,not in等过滤。

概述
Deletion vector 是用来提升paimon表的读取性能的一种配置,是paimon0.8版本新增的一种机制。主要是通过在写入时生成deletion file(牺牲了部分写入性能),这样在读取数据时,可以根据deletion file对需要读取的数据进行过滤,这样就避免了不同文件的合并成本。文件存储在:manifest-index-manifest-5d670043-da25-4265-9a26-e31affc98039-0

使用方式
配置中指定'deletion-vectors.enabled' = 'true'。
使用限制
changlog-producer 需要被设置成none或者lookup
changlog-producer.lookup-wait 不能设置为false.
merge-engine不能是first-row
这个模式需要过滤过滤level-0层数据,因此在使用时间旅行读取APPEND快照时,将存在数据延迟。
实现
当用户对旧数据进行更新时,会产生一个delete file,此文件主要用来标识data file中哪一条数据被删除了。
paimon-deve.png
delete file文件的结构如下:
paimon-deve-2.png
一个bucket中一个delete file,delete file 中数据的存储结构为map<file_name, bitmap>,当读取指定的数据文件时,首先将delete file 读取进来根据file_name 构建一个bitmap,之后在读取数据文件并根据bitmap将数据过滤。
在compact时生成新的delete file并且标记旧的delete file删除。delete file依赖对应的快照。
JSON

{
  "org.apache.paimon.avro.generated.record": {
    "_VERSION": 1,
    "_KIND": 0,
    "_PARTITION": "\u0000\u0000\u0000\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000p\u0000\u0000\u0000\u0000\u0000\u0000",
    "_BUCKET": 0,
    "_TYPE": "DELETION_VECTORS",
    "_FILE_NAME": "index-32f16270-5a81-4e5e-9f93-0e096b8b58d3-0",
    "_FILE_SIZE": x,
    "_ROW_COUNT": count of the map,
    "_DELETION_VECTORS_RANGES": "binary Map<String, Pair<Integer, Integer>>", key is the fileName, value is <start offset of the serialized bitmap in Index file, size of the serialized bitmap>
  }
}

Write
基于compact+lookup 的deleteFile的生成机制:

  1. 新数据被写入到level0层。
  2. 每次写入后执行压缩,并且强制合并level0层数据
  3. 实现一个类似LookupDeleteFileMergeFunctionWrapper的合并,它具有以下特征:
    a. 当记录不属于level0层时,不产生删除。
    b. 当记录属于level0层+level x层时,不生成删除。(compact时选中的被压缩的层 level 0 层与level x层,都有此数据)
    c. 当记录只属于level 0层时,查找其他层生成 deletefile的map(compact时选中的被压缩的层只有level 0层有此数据)
  4. compact结束后,旧文件中的bigmap不再使用,会生成一个新的文件里面有新的bigmap。

Read
Compaction的优化主要在于批式读取时候可以并发读取单个bucket的文件,之后借助deletefile将历史文件中的数据清除就可以。如果没有delefile,MOR读取方式需要单个并发度去读取一个bucket,因为需要做排序,去除历史的数据。由于deletefile是在compaction时产出,因此读取时候不能读取Level0层的文件结果。
示例:
paimon-deve-3.png
测试
本次测试只是针对数据准确性的测试,不再进行压测,官方压测结果可参考https://mp.weixin.qq.com/s/7VptRdZU6mGQlPiv4silEA
新增一些数据
SQL

insert into test_ver values(1,1);
insert into test_ver values(2,2);
insert into test_ver values(3,33);
update test_ver set age = 2 where (user_id=1 or user_id = 2);

查看生成的index file
JSON

{
        "org.apache.paimon.avro.generated.record": {
                "_VERSION": 1,
                "_KIND": 0,
                "_PARTITION": "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
                "_BUCKET": 0,
                "_INDEX_TYPE": "DELETION_VECTORS",
                "_FILE_NAME": "index-6d72d7bc-a6b8-4643-9e34-80bdb80ffd4c-0",
                "_FILE_SIZE": 33,
                "_ROW_COUNT": 1,
                "_DELETIONS_VECTORS_RANGES": {
                        "array": [{
                                "org.apache.paimon.avro.generated.record__DELETIONS_VECTORS_RANGES": {
                                        "f0": "data-f854406a-f936-449e-a66c-1c4e1446c5b1-0.orc",
                                        "f1": 1,
                                        "f2": 24
                                }
                        }]
                }
        }
}

注意
设置'deletion-vectors.enabled' = 'true',读取全量数据依赖compact快照,如果将表设置成write-only表并且没有启动compact任务,使用批查询,或者流式查询历史全量的datafile将查询不到数据。

1.B站关注的up主

flink官方runtime视频

2.老白

https://www.cnblogs.com/bethunebtj/p/9168274.html

https://cloud.tencent.com/developer/article/1172583

3.公众号 微云

https://www.jianshu.com/p/e5387fa6c6a0

https://blog.csdn.net/qq_21653785/article/details/79499127

https://zhuanlan.zhihu.com/p/22736103

算子

https://www.jianshu.com/p/2e379f242272

4.源码阅读笔记

https://blog.jrwang.me/2019/flink-source-code-streamgraph/

http://wuchong.me/blog/2016/05/04/flink-internal-how-to-build-streamgraph/

5.源码阅读总结

http://litianmin.com:9001/blog/post/litm7@qq.com/Flink%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB%E6%80%BB%E7%BB%93

6.github

https://github.com/wangzzu/awesome/issues/28 十分推荐

http://chenyuzhao.me/2017/02/06/flink%E7%89%A9%E7%90%86%E8%AE%A1%E5%88%92%E7%94%9F%E6%88%90/

简述:从log 日志中读取,然后设置不同的type,传输到kafka

Filebeat.yml

filebeat.config.inputs:
  enabled: true
  path: configs/*.yml  #input配置文件的路径
output.kafka:
  hosts: ["xxx.xx.xx.xx:9100"]
  topic: '%{[fields.type]}'  #根据设置的不同的fields.type 输出到不同的kafka的topic。

input.yml

- type: log           #指定输入类型
  backoff: "1s"                #到底之后 多久在检测
  #多行过滤
  multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
  multiline.negate: true
  multiline.match: after
  paths:           #日志路径
    - /home/logs/systemlog/access/*
  fields:       #给日志设置type
    type: systemlog_access

多行过滤文档

filebeat可以配置processors,来统一对多种日志进行过滤或增强 processor文档

Filebeat可以将运行状况发送到ES监控集群,然后在kibana上监控 文档