一、什么是实时数据
一般来说,实时数据指的是对数据的传输、处理或最后交付发生在数据刚产生的短暂瞬间,如实时同步、实时消息处理等。用来衡量实时的指标是数据从产生端到消费端的传输时延。
另外一种实时数据,则指的是对查询或者计算的响应是否足够快速,更多针对于数据库的内建分析或者查询引擎。这种实时数据技术的衡量指标是响应时间。如果传输时延或者响应时间能够控制在亚秒或者数秒内,我们可以称这些技术是”实时数据”技术。
从用户的角度看,他们能够感受到的是一个“交互”式的体验,例如我执行一次查询,或者调取一个最新统计数字,结果通常在 1-3 秒之内返回,就是一种较为理想的实时体验。
二、什么是准实时数据
实时数据和T+1数据几个最最明显的特征:
| 特征 | 实时数据 | 准实时数据 | 离线数据 |
|---|---|---|---|
| 时效性 | 低延迟(秒级、毫秒级) | 中延迟(小时级) | 高延迟(T+1) |
| 计算模式 | 流处理 | 批处理 | 批处理 |
| 访问数据范围 | 访问窗口内的数据 | 访问全部数据 | 访问全部数据 |
| 数据特征 | 动态的,无边界 | 静态的,有边界 | 静态的,有边界 |
| 准确性 | 低 | 较高 | 高 |
| 开发周期 | 长 | 短 | 短 |
| 数据可回溯周期 | 短 | 短 | 长 |
| 应用场景 | 大屏可视化、推荐系统、DSP、实时数据监控 | 实时数据监控和统计 | 离线报表和数据分析 |
1,时效性:
顾名思义,这个特征恐怕就是我们对实时数据、准实时数据和离线数据三种数据最能有感知的点
2,计算模式:
当前大数据领域所有的数据处理方式只有两种方式,一种就是流处理,另一种就是批处理,这两者的世界观大致是这样的:
| 流处理 | 批处理 |
|---|---|
| 无界,实时,无需对整个数据集执行操作,只对系统传输的每个数据项执行操作;适合实时统计 | 有界且大量、持久,适合访问全套记录才能完成的计算工作;适合离线统计 |
由此可以看出:
准实时是对数据时效性有一定的延迟,但是延迟小于t+1的数据,对这些数据进行监控或者统计分析
三、准实时数据的意义
离线数仓解决了各项目对于设备向物联网平台上报的大量数据的统计问题,解决了业务端对于统计类数据指标查询慢的问题。
但是这种解决也是对于t+1的数据统计的解决;对于当日数据还是需要用户请求时查询数据库进行计算;
这种方式对于简单的统计类业务还好,用户等待时间并不长;但是对于复杂的业务统计来说,对用户的体验就不友好了。
准实时数据就是将实时数据按照一定时间维度内的数据进行计算,对统计类的数据指标按这个维度提前计算出结果,存到数据库,或者直接推送到业务端;减少用户请求时的查询时间,使请求能迅速响应,增加用户体验感。
四、基于当前业务的准实时设计方案(目前是基于水机能耗的统计需求的方案)
基于当前业务,我们的数据统计类业务目前不需要小时级的统计,而是分钟级别统计居多,所以我们将准实时设计为以下这种方式:
| 特征 | 准实时数据 |
|---|---|
| 时效性 | 低延迟(5,10,15.....等分钟级) |
| 计算模式 | 流处理 |
| 访问数据范围 | 访问时间范围内数据 |
| 数据特征 | 动态的,无边界 |
| 准确性 | 较高 |
| 开发周期 | 短 |
| 数据可回溯周期 | 短 |
| 应用场景 | 业务端项目中调用高的统计类需求 |
基于以上设计方案,我们使用补全数据对业务端需求对设备指标进行五分钟,十分钟级的统计;
考虑到我们是物联网项目,设备量只能是越来越多,而开窗统计这种方式对于这种五分钟,十分钟级别的开窗会占用大量CPU,内存资源。我们对定时器功能进行研究调研,决定使用定时器+状态存储的方式;
1,定时器+状态的好处:
对于设备数据进行实时计算,定时输出方式;不需要缓存时间段内所有数据,不需要开窗操作,不需要占用太多内存存储窗口内的所有数据;
定时器可以灵活的进行开启关闭操作,对于离线设备,我们可以关闭定时输出,一定程度上降低了资源占用;
并且flink为了保证定时触发操作,与正常处理操作的线程安全问题,做了同步处理,在调用触发时必须要获取到锁,也就是二者同时只能有一个执行;
如果不做通不处理,当正常处理实时数据的方法会对状态进行更新操作,定时器中进行查询操作或者清空操作时,两者会发生线程安全问题
状态管理使用内存+磁盘方式,在保证程序低延时的情况下,降低了临时数据对于缓存的高占用问题;
2,定时器的局限性:
ProcessingTime类型的定时器触发是由注册时候的延时调度触发,会不断从队列弹出定时器触发onTimer方法,当获取到的InternalTimer对象中的时间大于延时调度时间时,会停止弹出定时器并触发onTimer方法,重新针对队列元素建立新的延迟调度
因此定时器并不能保证完全一致的时间间隔内输出(5分钟定时器):
3,开发逻辑设计:
服务对补全数据进行实时消费,根据设备号做分组聚合操作;
以设备号为单元,开启定时器;
设备首次上报在线数据时,开启定时器;设备上报离线数据时关闭定时器;(这样有利于降低资源,并且避免无效数据的输出);
分组内对补全数据进行计算统计,并将结果记录到状态中;(按业务需求)
定时器输出时,获取设备存储在状态内的数据进行汇总统计输出;
输出到数据库供业务端查询,或者直接"实时推送"到项目端
五、flink程序的API的调用
Timer(定时器)是Flink Streaming API提供的用于感知并利用处理时间/事件时间变化的机制。
我们在其processElement()方法中注册Timer,然后覆写其onTimer()方法作为Timer触发时的回调逻辑。根据时间特征的不同:
处理时间——调用Context.timerService().registerProcessingTimeTimer()注册;onTimer()在系统时间戳达到Timer设定的时间戳时触发。
事件时间——调用Context.timerService().registerEventTimeTimer()注册;onTimer()在Flink内部水印达到或超过Timer设定的时间戳时触发。
例如当前的水机耗电量统计,我们按实时统计,每五分钟进行清空重新计算,我们就可以在processElement()方法里注册Timer。
public void processElement(Tuple2<String, JSONObject> value, KeyedProcessFunction<String, Tuple2<String, JSONObject>, JSONObject>.Context ctx, Collector<JSONObject> out) throws Exception {
......
ctx.timerService().registerProcessingTimeTimer(System.currentTimeMillis()+300000);
}
再在onTimer()方法里执行state.clear()。
public void onTimer(long timestamp, KeyedProcessFunction<String, Tuple2<String, JSONObject>, JSONObject>.OnTimerContext ctx, Collector<JSONObject> out) throws Exception {
......
state.clear();
}