1. 问题
业务系统的订单金额会被修改或者新增, 从一些维度实时计算订单汇总金额。
2. 解决问题
- 离线没法搞,最多是加快处理频率,最多到分钟级。
- flink的回撤流很容易解决这个问题
3. 实验数据:
通过cdc获取了一个订单的回撤流,订单值从100 一次更新成101,102,103.
回撤流是试试生成的。
+----+--------------------------------+-------------+
| op | ipv4 | value1 |
+----+--------------------------------+-------------+
| +I | 10.10.28.240 | 100 |
| -U | 10.10.28.240 | 100 |
| +U | 10.10.28.240 | 101 |
| -U | 10.10.28.240 | 101 |
| +U | 10.10.28.240 | 102 |
| -U | 10.10.28.240 | 102 |
| +U | 10.10.28.240 | 103 |
对上面数据简单sum:
遇到+I +U 做加法, 遇到-U,-D 做减法。 简单累加得下面结果, 也是回撤流。
+----+-------------+
| op | EXPR$0 |
+----+-------------+
| +I | 100 |
| -D | 100 |
| +I | 101 |
| -D | 101 |
| +I | 102 |
| -D | 102 |
| +I | 103 |
4. 回撤流获得
上面是cdc直接拿到的回撤流。
基于纯日志流, 通过sum, top n 等有key的计算,都会获得回撤流。
比如上面的订单数据, 如果没给cdc流, 但是每次变更给了一条数据流怎么办呢。
基于订单id ,通过rownumber +time 取 这个订单id的最新一条记录,这个就是回撤流。 然后对这个回撤流做sum。非常重要: 通过这个手段获得回撤流时, 一定要评估好状态保留时间。如果时间设置的太小, 订单在状态被删除后更新, 就会再生成一条+I的数据。 导致这个订单呗计算两次。
topic 的最后一条记录模拟订单的最新记录, 状态不过期。对下面数据进行sum结果是准确的。
select * from (
select topic ,
2 as value1,
row_number() over (partition by topic order by ts desc) rn
from source_table
) where rn=1
+----+--------------------------------+-------------+----------------------+
| op | topic | value1 | rn |
+----+--------------------------------+-------------+----------------------+
| +I | test1 | 2 | 1 |
| -U | test1 | 2 | 1 |
| +U | test1 | 2 | 1 |
| -U | test1 | 2 | 1 |
| +U | test1 | 2 | 1 |
| -U | test1 | 2 | 1 |
| +U | test1 | 2 | 1 |
| -U | test1 | 2 | 1 |
| +U | test1 | 2 | 1 |
但是如果状态过期,就会得到下面的回撤流, 对其进行sum时, 将重复计算。
+----+--------------------------------+-------------+----------------------+
| op | topic | value1 | rn |
+----+--------------------------------+-------------+----------------------+
| +I | test1| 2 | 1 |
| +I | test1| 2 | 1 |