案例与解决方案汇总页:
阿里云实时计算产品案例&解决方案汇总

一. 背景介绍

菜鸟的物流数据本身就有链路复杂、实操节点多、汇总维度多、考核逻辑复杂的特点,对于实时数据的计算存在很大挑战。经过仓配ETL团队的努力,目前仓配实时数据已覆盖了绝大多数场景,但是有这样一类特殊指标:“晚点超时指标”(例如:出库超6小时未揽收的订单量),仍存在实时汇总计算困难。原因在于:流计算是基于消息触发计算的,若没有消息到达到则无法计算,这类指标恰好是要求在指定的超时时间计算出有多少未达到的消息。然而,这类指标对于指导实操有着重要意义,可以告知运营小二当前多少订单积压在哪些作业节点,应该督促哪些实操人员加快作业,这对于物流的时效KPI达成至关重要。

之前的方案是:由产品前端根据用户的请求查询OLAP数据库,由OLAP从明细表出结果。大促期间,用户请求量大,加之数据量大,故对OLAP的明细查询造成了比较大的压力。

二. 解决方案

2.1   问题定义

“超时晚点指标” 是指,一笔订单的两个相邻的实操节点node_n-1 、node_n 的完成时间 time_n-1、time_n,
当满足 : time_n is null  && current_time - time_n-1 > kpi_length 时,time_flag_n 为 true , 该笔订单计入 超时晚点指标的计数。
如下图,有一笔订单其 node_1 为出库节点,时间为time_1 = '2018-06-18 00:00:00' ,运营对出库与揽收之间考核的时长 kpi_length = 6h, 那么当前自然时间 current_time > '2018-06-18 06:00:00' 时,且node_2揽收节点的time_2 为null,则该笔订单的 timeout_flag_2 = true , “出库超6小时未揽收订单量” 加1。由于要求time_2 为null,即要求没有揽收消息下发的情况下让流计算做汇总值更新,这违背了流计算基于消息触发的基本原理,故流计算无法直接算出这种“超时晚点指标”。

决问题的基本思路是:在考核时刻(即 kpi_time = time_n-1+kpi_length )“制造”出一条消息下发给流计算,触发汇总计算。继续上面的例子:在考核时刻“2018-06-18 06:00:00”利用MetaQ定时消息功能“制造”出一条消息下发给流计算汇总任务,触发对该笔订单的 time_out_flag_2 的判断,增加汇总计数。同时,还利用 Blink 的Retraction 机制,当time_2 由null变成有值的时候,Blink 可以对 time_out_flag_2 更新,重新计数。

2.2 方案架构

如上图所示:
Step1:  Blink job1 接收来自上游系统的订单数据,做清洗加工,生成订单明细表:dwd_ord_ri,利用TT下发给Blink job2 和 Blink job3。
Step2:Blink job2 收到 dwd_ord_ri后,对每笔订单算出考核时刻 kpi_time = time_n-1+kpi_length,作为MetaQ消息的“TIMER_DELIVER_MS” 属性,写入MetaQ。MetaQ的定时消息功能,可以根据用户写入的TIMER_DELIVER_MS 在指定时刻下发给消费者,即上图中的Blink job3。
Step3:Blink job3 接收 TT、MetaQ 两个消息源,先做Join,再对time_flag判断,最后做Aggregate计算。同一笔订单,dwd_ord_ri、timing_msg任意一个消息到来,都会触发join,time_flag判断,aggregate重新计算一遍,Blink的Retraction可对结果进行实时更新。

2.3 实现细节

本方案根据物流场景中多种实操节点、多种考核时长的特点,从Blink SQL代码 和 自定义Sink两方面做了特殊设计,从而实现了灵活配置、高效开发。
(1) Blink job2 --- 生成定时消息
关键Blink SQL 代码如下。约定每条record的第一个字段为投递时间列表,即MetaQ向消费者下发消息的时刻List,也就是上面所说的多个考核时刻。第二个字段为保序字段,比如在物流场景中经常以订单code、运单号作为保序主键。该代码实现了对每个出库的物流订单,根据其出库时间,向后延迟6小时(21600000毫秒)、12小时(43200000毫秒)、24小时(86400000毫秒)由MetaQ向消费者下发三个定时消息。

create table metaq_timing_msg
(
deliver_time_list       varchar comment '投递时间列表', -- 约定第一个字段为投递时间list
lg_code           varchar comment '物流订单code', -- 约定第二字段为保序主键
node_name               varchar comment '节点名称',
node_time               varchar comment '节点时间',
)
WITH
(
type = 'custom',
class = 'com.alibaba.xxx.xxx.udf.MetaQTimingMsgSink',
tag = 'store',
topic = 'blink_metaq_delay_msg_test',
producergroup = 'blinktest',
retrytimes = '5',
sleeptime = '1000'
);
insert into metaq_timing_msg
select
concat_ws(',',
cast( (UNIX_TIMESTAMP(store_out_time)*1000 + 21600000) as varchar),  --6小时
cast( (UNIX_TIMESTAMP(store_out_time)*1000 + 43200000) as varchar),  --12小时
cast( (UNIX_TIMESTAMP(store_out_time)*1000 + 86400000) as varchar)   --24小时
)   as deliver_time_list,
lg_code,
'wms'  as node_name,
store_out_time  as node_time
from
(
select
lg_code,
FIRST_VALUE(store_out_time) as store_out_time
from srctable
group by lg_code
)b
where store_out_time is not null  ;

(2) Blink 自定义Sink --- MetaQTimingMsg Sink
Blink的当前版本还不支持 MetaQ的定时消息功能的Sink,故利用 Blink的自定义Sink功能,并结合菜鸟物流数据的特点开发了MetaQTimingMsg Sink。关键代码如下(实现 writeAddRecord 方法)。

@Override
public void writeAddRecord(Row row) throws IOException {
Object deliverTime = row.getField(0);
String[] deliverTimeList = deliverTime.toString().split(",");
for(String dTime:deliverTimeList){String orderCode = row.getField(1).toString();String key = orderCode + "_" + dTime;Message message = newMessage(row, dTime, key);boolean result = sendMessage(message,orderCode);if(!result){LOG.error(orderCode + " : " + dTime + " send failed");}}
}private  Message newMessage(Row row,String deliverMillisec,String key){//Support Varbinary Type Insert Into MetaQMessage message = new Message();message.setKeys(key);message.putUserProperty("TIMER_DELIVER_MS",deliverMillisec);int arity = row.getArity();Object[] values = new Object[arity];for(int i=0;i<arity;i++){values[i]=row.getField(i);}String lineStr=org.apache.commons.lang3.StringUtils.join(values, FIELD_DELIMITER);try {byte[] bytes = lineStr.getBytes(ENCODING);message.setBody(bytes);message.setWaitStoreMsgOK(true);} catch (UnsupportedEncodingException e) {LOG.error("create new message error",e);}return message;
}private boolean sendMessage(Message message,String orderCode){long retryTime = 0;boolean isSendSuccess = true;if(message != null){message.setTopic(topicName);message.setTags(tagName);}SendResult result = producer.send(message, new MessageQueueSelector() {@Overridepublic MessageQueue select(List<MessageQueue> list, Message message, Object o) {.... // 针对物流订单code的hash算法return list.get(index.intValue());}                    },orderCode);if(!result.getSendStatus().equals(SendStatus.SEND_OK)){LOG.error("" + orderCode +" write to metaq result is " + result.getSendStatus().toString());isSendSuccess = false;}return  isSendSuccess;
}
}

(3)Blink job3 --- 汇总计算
关键Blink SQL 代码如下,统计了每个仓库的“出库超6小时未揽收物理订单”、“出库超12小时未揽收物理订单”、“出库超24小时未揽收物理订单”的汇总值。代码中使用了“stringLast()”函数处理来自dwd_ord_ri的每条消息,以取得每个物流订单的最新出库揽收情况,利用Blink Retraction机制,更新汇总值。

create view dws_store_view as
select t1.store_code,max(t1.store_name)       as store_name,count(case when length(trim(t1.store_out_time)) = 19and t1.tms_collect_time is null and NOW()-UNIX_TIMESTAMP(t1.store_out_time,'yyyy-MM-dd HH:mm:ss') >= 21600then t2.lg_code end ) as tms_not_collect_6h_ord_cnt, ---出库超6小时未揽收物流订单量count(case when length(trim(t1.store_out_time)) = 19and t1.tms_collect_time is null and  NOW()-UNIX_TIMESTAMP(t1.store_out_time,'yyyy-MM-dd HH:mm:ss') >= 43200then t2.lg_code end ) as tms_not_collect_12h_ord_cnt,---出库超6小时未揽收物流订单量count(case when length(trim(t1.store_out_time)) = 19and t1.tms_collect_time is null and  NOW()-UNIX_TIMESTAMP(t1.store_out_time,'yyyy-MM-dd HH:mm:ss') >= 86400then t2.lg_code end ) as tms_not_collect_24h_ord_cnt ---出库超6小时未揽收物流订单量
from
(select lg_code,coalesce(store_code,'-1')   as store_code,store_name,store_out_time,tms_collect_timefrom (select lg_code,max(store_code)          as store_code,max(store_name)          as store_name,stringLast(store_out_time)  as store_out_time,stringLast(tms_collect_time)as tms_collect_time, from dwd_ord_rigroup by lg_code) a
) t1
left outer join
(select lg_code,from timing_msg  where node_name = 'wms'group by lg_code
) t2
on t1.lg_code = t2.lg_code
group byt1.store_code;

三.  方案优势

3.1 配置灵活

我们从“Blink SQL 代码” 和“自定义MetaQ” 两个方面设计,用户可以根据具体的业务场景,在Blink SQL的一个view里就能实现多种节点多种考核时间的定时消息生成,而不是针对每一个实操节点的每一种定时指标都要写一个view,这样大大节省了代码量,提升了开发效率。例如对于仓库节点的出库超6小时未揽收、超12小时未揽收、超24小时未揽收,这三个指标利用上述方案,仅需在Blink job2的中metaq_timing_msg的第一个字段deliver_time_list中拼接三个kpi_length,即6小时、12小时、24小时为一个字符串即可,由MetaQTimingMsg Sink自动拆分成三条消息下发给MetaQ。对于不同的节点的考核,仅需在node_name,node_time填写不同的节点名称和节点实操时间即可。

3.2 主键保序

如2.3节所述,自定义的Sink中 实现了MetaQ的 MessageQueueSelector 接口的 select() 方法,同时在Blink SQL 生成的MetaQ消息默认第二个字段为保序主键字段。从而,可以根据用户自定义的主键,保证同一主键的所有消息放在同一个通道内处理,从而保证按主键保序,这对于流计算非常关键,能够实现数据的实时准确性。

3.3 性能优良

让专业的团队做专业的事。个人认为,这种大规模的消息存储、消息下发的任务本就应该交给“消息中间件”来处理,这样既可以做到计算与消息存储分离,也可以方便消息的管理,比如针对不同的实操节点,我们还可以定义不同的MetaQ的tag。
另外,正如2.2节所述,我们对定时消息量做了优化。考虑到一笔订单的属性字段或其他节点更新会下发多条消息,我们利用了Blink的FIRST_VALUE函数,在Blink job2中同一笔订单的的一种考核指标只下发一条定时消息,大大减少了消息量,减轻了Blink的写压力,和MetaQ的存储。

四. 自我介绍

马汶园    阿里巴巴 -菜鸟网络—数据部      数据工程师
菜鸟仓配实时研发核心成员,主导多次仓配大促实时数据研发,对利用Blink的原理与特性解决物流场景问题有深入思考与理解。

原文链接
本文为云栖社区原创内容,未经允许不得转载。

利用blink+MQ实现流计算中的超时统计问题相关推荐

  1. 利用blink CEP实现流计算中的超时统计问题

    案例与解决方案汇总页: 阿里云实时计算产品案例&解决方案汇总 一. 背景介绍 如<利用blink+MQ实现流计算中的延时统计问题>一文中所描述的场景,我们将其简化为以下案例: 实时 ...

  2. 20流计算中的数据关联:流与流,流与批

    上一讲,我们提到,Structured Streaming 会复用 Spark SQL 所提供的一切数据处理能力,比如数据抽取.过滤.分组聚合.关联.排序,等等.不过,在这些常规的数据处理类型中,有一 ...

  3. 阿里云流计算中维表join VS 流join

    最近业务上使用blink进行清洗数据,使用到了双流join和维表join,今天有同学问我流join和维表join有什么区别.在此我做个简单的说明,描述不对的地方,欢迎大家纠正,后面补充. 流式计算过程 ...

  4. webform计算某几列结果_大数据测试场景科普 流计算篇 (上)

    前言 3年前的时候写过关于一些大数据入门基础的文章, 当时学习的是spark.文章链接如下: 大数据介绍:https://testerhome.com/topics/7988 spark基础操作:ht ...

  5. 流计算引擎数据一致性的本质

    简介: 本篇文章从流计算的本质出发,重点分析流计算领域中数据处理的一致性问题,同时对一致性问题进行简单的形式化定义,提供一个一窥当下流计算引擎发展脉络的视角,让大家对流计算引擎的认识更为深入,为可能的 ...

  6. 阿里云StreamCompute流计算架构

    下图为阿里云流计算全流程系统架构,主要包含:数据采集,流数据,流计算,数据源,数据消费这些过程.  数据采集  用户可以使用流式数据采集工具将数据流式且实时地采集并传输到大数据Pub/Sub系统,该系 ...

  7. 大数据实时流计算详解

    开篇词-攻克实时流计算难点,掌握大数据未来 我曾任职于华为 2012 实验室高斯部门,负责实时分析型内存数据库 RTANA.华为公有云 RDS 服务的研发工作.目前,我专注于移动反欺诈解决方案的研发. ...

  8. S4:分布式流计算平台

    前段时间考虑监控统计面临的两个问题,一是Key太多的问题.客户端输出日志的埋点程序可以通过LRUMap缓解,但是服务端就比较麻烦.对于某些以MapReduce模式实现的日志分析框架,当一个应用的key ...

  9. Storm入门(0)--流计算

    一.静态数据.流数据 以及 批量计算.实时计算 大数据分类两类:静态数据和动态数据(流数据).针对这两类数据的计算模式分别是批量计算和实时计算. 静态数据:历史数据持久化存储在系统里,这类数据的特点是 ...

最新文章

  1. 在计算机视觉方向如何快速提升自己?
  2. laravel token ajax,Laravel中ajax post操作需要传递csrf token的最优化解决方式
  3. python如何安装scrapy_Python爬虫之Scrapy的安装
  4. 图片自动翻转css代码,用css实现图片翻转(示例代码)
  5. 国自然和毕业论文的流程图用这个格式导入Word可无限放大
  6. MySQL表的操作(二)
  7. 基于Django进行简单的微信开发
  8. Makefile 教程(超详细)
  9. Ubuntu 14.04 LTS 安装 文泉驿微米黑 字体到android studio
  10. 机械革命Z3 Pro测试,从开箱到翻车到上岸到发烧(多图预警)
  11. fingerprint模块管理指纹识别
  12. BlenderGIS:No ImageIO解决办法 天地图地图资源
  13. #444 沸腾客厅:在播客里温暖一个冬天
  14. ffmpeg实现将H264裸流封装成.mp4或.avi文件
  15. 大数字类(BigInteger 、BigDecimal)
  16. 【TIANCHI】天池大数据竞赛(学习赛)--- 淘宝用户购物行为数据可视化分析
  17. SQL Server从入门到精通(转)
  18. 网页特效应用二期(电脑新建一个文本文档复制粘贴改后缀名为.html就能用)
  19. 经典提高培养情商最有效的13本书
  20. 性能调优实践-提升cpu利用率

热门文章

  1. 湖南大学计算机网络实验,湖南大学《计算机网络》实验报告
  2. 4接口引脚定义_浅谈USB Type-C接口
  3. python 实现显著性检测_强!汽车车道视频检测:python+OpenCV为主实现
  4. 天正双击墙体不能编辑_今日设计分享:CAD常用快捷键、Ps快捷键大全、天正快捷键总结!...
  5. html 文本溢出,确定HTML元素的内容是否溢出
  6. arm export 汇编_C/C++与汇编混合编程有什么好处?
  7. 悬浮球多功能_一个悬浮球,怎么可以这么贴心~
  8. AI如何用特征、权重和避免过拟合等技术来分辨冬瓜和西瓜?
  9. 被百度AI官方认证的大学,到底是什么水平
  10. “双十一缔造者”张勇