腾讯内容千亿级实时计算和规则引擎实践优化之路( 二 )


腾讯内容千亿级实时计算和规则引擎实践优化之路
文章图片
图3-2动态实时源自适应感知示意图
主要由以下几个模块构成:控制器模块:监测消息队列并通过配置中心异步控制Flink的消费 。 新增Topic时 , 注册到配置中心 。 Topic数据量变大导致消费延迟时 , 增加该Topic的消费并行度 。 配置中心:存放所有拓扑的消息队列 , 如拓扑ID、消费并行度、Kafka配置 。 Flink自适应Source:自适应消费Kafka数据 , 保障数据完整性和时效性 。 在Task内开启消费线程池 , 负责Kafka的消费;并有自适应Client , 负责控制线程池的消费 , 每分钟执行一次 , 保障消费的完整性和时效性 。 步骤1:拉取所有消息队列配置 。 步骤2:生成本Task消费的Topic消费列表 , 保障并行度N的Topic会被N个Task消费 。 总Task数目是M , 每个Task会被分到如下Task中:hash(pipeline_id)%M到(hash(pipeline_id)+N)%M 。 遍历Topic可能被消费的Task列表 , 如果其中包含本Task , 则可对其进行消费 。 步骤3:调整线程池消费列表 , 如果步骤2中添加了Topic , 则添加对应Topic的消费 。
3.1.2十万级QPS高并发ID映射
因每个业务渠道(如腾讯新闻、QQ浏览器等)有自己的内容ID体系 , 为此 , 在整合各渠道的消费流水时 , 我们需要将业务ID映射成腾讯内容中台统一的内容OneID体系 。 如果直接请求现有的ID映射服务 , 大量的网络IO会消耗较大的实时流计算资源 。
为此 , 我们构建了基于二级缓存的ID映射解决方案 , 大幅降低对远程服务的访问 , 可节约上百倍的计算资源 。
腾讯内容千亿级实时计算和规则引擎实践优化之路
文章图片
图3-3基于二级缓存的实时ID映射
如上图所示 , 具体步骤如下:获取中台ID:首先判断应用内状态中是否有该ID的缓存 , 如果有则直接返回中台ID;如果没有 , 则访问ID映射服务 , 并将其更新到State中 。 一级缓存:在程序中构建Flink应用内状态(FlinkState) , 缓存渠道ID到中台ID的映射 。 因为远程拉取中台ID时有缺失 , 缺失时无法判断是当时映射服务有遗漏但是后续请求能映射上 , 还是该渠道ID本身无法映射到中台ID , 为保障数据准确性 , 我们构建了2种State控制ID映射:可以映射的State:存放渠道ID到中台ID的映射 , 为规避状态膨胀 , TTL设置成7天 , 过期时间从最近一次访问时间开始计算 。 不能映射的State:存放未映射上的渠道ID 。 为保障整体数据可用性 , 需要定期强制重新拉取中台ID , 将TTL设置成1小时 , 过期时间从第一次访问时间开始计算 。 二级缓存:远程ID映射服务 , 通过RestApi访问 。 拼接ID:在消费流水中 , 拼接上中台ID 。
3.2信号生产
在实际应用场景中 , 需要提供多样的实时特征信号 , 信号生产过程中 , 我们遇到了多种挑战 , 本章将结合实际问题 , 介绍我们通用自研的解决方案 。
3.2.1千亿次滑动大窗口计算
在内容场景中 , 需要对内容消费数据的大时间窗口(如1天、30天等)的每分钟滑动指标进行日千亿次的实时流计算 , 并基于这样的数据指标来控制业务流转 , 如果我们直接基于Flink内部的窗口函数 , 进行实时计算窗口指标时 , 因不能及时关闭窗口 , 状态数据会占用大量的内存 , 导致计算出现反压的情况 , 程序稳定性差 , 容易出现卡死现象 。
基于上述挑战 , 我们设计了一种高性能的大窗口计算方法 , 主要有如下优点:传统的方式需要每次对大窗口中的全量数据做计算 , 而现有方式可以复用前一次计算结果 , 可极大减少计算量 。 我们方案中大窗口是逻辑上的大窗口 , 相比Flink原生的窗口计算会保留大窗口时间内的原始数据 , 我们在内存中并不存放这些原始数据 , 只存放算法提到的聚合维度的数据 , 同时利用数据淘汰机制 , 防止内存占用过大 , 节约大量的内存资源 。