5年迭代5次,抖音推荐系统演进历程( 三 )

  • SortedMap<int, int>: 存储 topk 二维计数 ;
  • LinkedList :存储 id_list 类型数据;
  • HashMap<int, List >:存储二维 id_list;
  • 自定义类型,业务可以根据需求 FeaturePayload 里面自定义数据类型
  • 状态层更新的业务接口:输入是 SQL 抽取 / 拼接层抽取出来的 RawFeature,业务方可以根据业务需求实现 updateFeatureInfo 接口对状态层的更新 。对于常用的特征类型内置实现了 update 接口,业务方自定义特征类型可以继承 update 接口实现 。
    /** * 特征状态 update 接口 */ publicinterfaceFeatureStateApiextendsSerializable{ /** * 特征更新接口, 上游每条日志会提取必要字段转换为 fields, 用来更新对应的特征状态 * * @paramfields * context: 保存特征名称、主键 和 一些配置参数 ; * oldFeature: 特征之前的状态 * fields: 平台 / 配置文件 中的抽取字段 * @return */ FeaturePayLoad assign(Context context,FeaturePayLoad feature, Map<String, Object> rawFeature); }当然对于无状态的 ETL 特征是不需要状态存储层的 。
    计算层
    特征计算层完成特征计算聚合逻辑,有状态特征计算输入的数据是状态存储层存储的带有切片的 FeaturePayload 对象 。简单的 ETL 特征没有状态存储层,输入直接是 SQL 抽取层的数据 RawFeature 对象,具体的接口如下:
    /** * 有状态特征计算接口 */ publicinterfaceFeatureStateApiextendsSerializable{/*** 特征聚合接口,会根据配置的特征计算窗口, 读取窗口内所有特征状态,排序后传入该接口** @paramfeatureInfos, 包含 2 个 field * timeslot: 特征状态对应的时间槽* Feature: 该时间槽的特征状态* @return*/FeaturePayLoad aggregate(Context context, List<Tuple2<Slot, FeaturePayLoad>> slotStates);
    }
    有状态特征聚合接口
    /*** 无状态特征计算接口*/publicinterfaceFeatureConvertApiextendsSerializable{/*** 转换接口, 上游每条日志会提取必要字段转换为 fields, 无状态计算时,转换为 gauss 内的 feature 类型 ;** @paramfields * fields: 平台 / 配置文件 中的抽取字段* @return*/FeaturePayLoad convert(Context context, FeaturePayLoad featureSnapshot, Map<String, Object> rawFeatures);
    【5年迭代5次,抖音推荐系统演进历程】}

    无状态特征计算接口
    另外通过触发机制来触发特征计算层的执行,目前支持的触发机制主要有:
    5年迭代5次,抖音推荐系统演进历程

    文章插图
    业务落地
    目前在字节推荐场景,新一代特征架构已经在 抖音直播、电商、推送、抖音推荐等场景陆续上线了一些实时特征 。主要是有状态类型的特征,带有窗口的一维统计类型、二维倒排拉链类型、二维 TOPK 类型、实时 CTR/CVR Rate 类型特征、序列类型特征等 。
    在业务核心指标达成方面成效显著 。在直播场景,依托新特征架构强大的表达能力上线了一批特征之后,业务看播核心指标、互动指标收益非常显著 。在电商场景,基于新特征架构上线了 400+ 实时特征 。其中在直播电商方面,业务核心 GMV、下单率指标收益显著 。在抖音推送场景,基于新特征架构离线状态的存储能力,聚合用户行为数据然后写入下游各路存储,极大地缓解了业务下游数据库的压力,在一些场景中 QPS 可以下降到之前的 10% 左右 。此外,抖音推荐 Feed、评论等业务都在基于新特征架构重构原有的特征体系 。
    值得一提的是,在电商和抖音直播场景,Flink 流式任务状态最大已经达到 60T,而且这个量级还在不断增大 。 预计不久的将来,单任务的状态有可能会突破 100T,这对架构的稳定性是一个不小的挑战 。
    性能优化
    Flink State Cache
    目前 Flink 提供两类 StateBackend:基于 Heap 的 FileSystemStateBackend 和基于 RocksDB 的 RocksDBStateBackend 。对于 FileSystemStateBackend,由于数据都在内存中,访问速率很快,没有额外开销 。而 RocksDBStateBackend 存在查盘、序列化 / 反序列化等额外开销,CPU 使用量会有明显上升 。在字节内部有大量使用 State 的作业,对于大状态作业,通常会使用 RocksDBStateBackend 来管理本地状态数据 。RocksDB 是一个 KV 数据库,以 LSM 的形式组织数据,在实际使用的过程中,有以下特点 :
    1. 应用层和 RocksDB 的数据交互是以 Bytes 数组的形式进行,应用层每次访问都需要序列化 / 反序列化;
    2. 数据以追加的形式不断写入 RocksDB 中,RocksDB 后台会不断进行 compaction 来删除无效数据 。

    3. 推荐阅读