大厂海量视频推荐索引构建解决方案

共 4090字,需浏览 9分钟

 ·

2024-04-11 07:45


点击下方“ JavaEdge ”,选择“ 设为星标

第一时间关注技术干货! 关注我,紧跟本系列专栏文章,咱们下篇再续!

作者简介:魔都技术专家兼架构,多家大厂后端一线研发经验,各大技术社区头部专家博主,编程严选网创始人。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。

负责:中央/分销预订系统性能优化;活动&优惠券等营销中台建设;交易平台及数据中台等架构和开发设计。




1 背景

需求:

  • 新启用视频尽快触达用户
  • 识新物品好坏,通过分发流量及后验数据,判断新物品是否值得继续分发

这就对索引先验数据、后验数据延迟都高要求。

  • 先验数据:视频创建时就带有的数据如tag,作者账号id
  • 后验数据:用户行为反馈的数据如曝光、点击、播放

2 视频推荐整体架构

a5a4ac718112049b003598f544fe2be8.webp
  • 视频由内容中心通过MQ给到,经处理入库、建索引、生成正排/倒排数据,在存储层可召回内容约1000w条
  • 经召回层,通过用户画像、点击历史等特征召回出数千条视频,给到粗排层
  • 粗排将这数千条视频打分,取数百条给到精排层
  • 精排再打分,给到重排
  • 重排根据规则和策略进行打散和干预,最终取10+条给到用户

视频在用户侧曝光后,从上到下:用户对视频的行为,如曝光、点击、播放、点赞、评论等经过上报至日志服务,然后通过实时/离线处理产生特征回到存储层。

需设计一套召回/倒排索引,以实时/近实时延迟来处理所有数据。

3 方案设计

旧方案索引每半小时定时构建,无法满足近实时。分析索引构建方案:

  • 数据虽不要求强一致性,但需保证最终一致性
  • 后验数据写入量极大
  • 召回系统要求高并发、低延迟、高可用

3.1 方案调研

2b48502589b051fdeb0acce3412ad6b8.webp

Redis灵活性差,直接用难,需多定制化开发,排除。

可选方案主要在自研或开源成熟方案:

  • 自研索引开发成本较高
  • 简单自研方案可能无法满足业务需求,完善的自研索引方案所需开发维护成本高

最终选择基于ES的索引服务。

3.2 数据链路

3.2.1 方案

51277c1d812fd188edb77d6da6aeace9.webp

先验数据链路,数据源主要来自内容中心,通过解析服务写入到CDB中。其中这个链路又分为全量链路和增量链路

  • 全量链路主要是在重建索引时才需要的,触发次数少但也重要。 它从DB这里dump数据,写入kafka,然后通过写入服务写入ES

  • 增量链路是确保其实时性的链路,通过监听binlog,发送消息至kafka,写入服务消费kafka然后写入ES


后验数据链路。APP用户行为流水直接打入ES绝对扛不住。需聚合计算

用Flink做了1分钟滚动窗口聚合,然后把结果输到写模块,得到1分钟增量的后验数据。Redis存储近7天的后验数据,写模块消费到增量数据后,需要读出当天的数据,并于增量数据累加后写回Redis,并发送对应的rowkey和后验数据消息给到Kafka,再经由ES写入服务消费、写入ES索引。

3.2.2 数据一致性

① Redis写模块,需先读数据,累加后再写入

先读后写,需保证原子性,这里可能存在同时有其他线程在同一时间写入。

解决方案1 redis加锁;

解决方案2如图,MQ队列使用rowkey作为分区key,确保同一rowkey分配至同一分区,而同一只能由同一消费者消费,也就是同一rowkey由一个进程处理,再接着以rowkey作为分线程key,使用hash算法分线程,这样同一rowkey就在同一线程内处理,因此解决了此处的一致性问题。同一流内的一致性问题顺带解决。

79af6282ec7a37e0da557b9367b0294e.webp
② Redis写模块,Redis写入需先消费kafka的消息

这就要求kafka消息commit和redis写入保证原子性。

如先commit再进行redis写入,那系统在commit完且写入redis前宕机了,那么这条消息将丢失掉;如

先写入,在commit,那么这里就可能会重复消费。

如何解决?先写入redis,且写入的信息里带上时间戳作版本号,再commit消息;写入前会比较消息版本号和redis版本号,若小于,则直接丢弃。

③ 写入ES有3个独立进程

不同流写入同一索引也会引入一致性问题。这里我们可以分析出,主要是先验数据的写入可能会存在一致性问题,因为后验数据写入的是不同字段,而且只有update操作,不会删除或者插入。

若上游的MySQL这里删除一条数据,全量链路和增量链路同时执行,而刚好全量Dump时刚好取到这条数据,随后binlog写入delete记录,那么ES写入模块分别会消费到插入和写入两条消息,而他自己无法区分先后顺序,最终可能导致先删除后插入,而DB里这条消息是已删除的,这就造成了不一致。

分析到问题之后就比较好办,利用Kfaka回溯能力:在Dump全量数据前记录下当前时间戳t1,Dump完成之后,将增量链路回溯至t1即可。而这段可能不一致的时间窗口1min,业务完全可接受。

线上0停机高可用在线索引升级流程:25542513bd9c040c4c86f8478b29b9f6.webp

3.2.3 写入平滑

由于Flink聚合后的数据大毛刺,导入写入ES时服务不稳定,cpu和rt都大毛刺,写入情况:

ffb5623142d17fec3ba2215fd62130f1.webp

需研究平滑写入方案,这直接使用固定阈值来平滑写入不合适,因为业务不同时间写入量不同,无法给出固定阈值。

最终方案:

c839396b442118f7b42aa6406b240b57.webp

自适应限流器,统计前1min接收的消息总量,计算当前每秒可发送的消息总量。

将该模块拆分为读线程和写线程:

​读线程统计接收消息数,并把消息存入队列;令牌桶数据每秒更新;

写线程获取令牌桶,获取不到则等待,获取到就写。

dcab1f299ad8dee1ff589ad712b9b143.webpaa39a5a5762561da54f4de7a66cdfa8c.webp852d392564420a9e34d997f11775914a.webp

4 召回性能调优

4.1 高并发场景优化

存在多路召回,所以召回系统有读放大问题,ES相关召回总qps是50W。如直接打入ES,一定是扛不住的!大量请求的参数相同并且存在大量热门key,引入多级缓存提高召回的吞吐量和延迟时间。

多级缓存方案

c6ebae4158672158f15de2878b34edb1.webp

本地缓存(BigCache)<->分布式缓存(Redis)<->ES。

整体缓存命中率为95+%,其中本地缓存命中率75+%,分布式缓存命中率20%,打入ES的请求量大约为5%。这大大提高召回吞吐量并降低RT。

该方案还考虑缓存穿透和雪崩,该方案:

  • 本地缓存定时dump到磁盘中,服务重启时将磁盘中的缓存文件加载至本地缓存。
  • 巧妙设计缓存Value,包含请求结果和过期时间,由业务自行判断是否过期;当下游请求失败时,直接延长过期时间,并将老结果返回上游。
  • 热点key失效后,请求下游资源前进行加锁,限制单key并发请求量,保护下游不会被瞬间流量打崩。
  • 最后使用限流器兜底,如果系统整体超时或者失败率增加,会触发限流器限制总请求量。

4.2 ES性能调优

4.2.1 设置合理的primary_shards

ES索引拆分的分片数,对应底层Lucene的索引数。值越大,单请求并发度越高,但给到上层MergeResult的数量也会增加。

经验结合官方建议,单个shard为1~50G合理,由于整个索引大小10G,计算出合理取值范围为1~10个,接着压测取最合适业务值

c0a14fe43151f8955ce8dae76946d3c9.webp4a66e2b227f54d990b59e3a29e932bd4.webp

选6。

4.2.2 请求结果过滤不需要的字段

ES返回结果都是json,而且默认会带上source和_id,_version等字段,我们把不必要的正排字段过滤掉,再使用filter_path把其他不需要的字段过滤掉,这样总共能减少80%的包大小,过滤结果:

045ca5b0294b9eeb61156587c405c1da.webp

4.2.3 设置合理routing字段

ES支持使用routing字段来对索引进行路由,即在建立索引时,可以将制定字段作为路由依据,通过哈希算法直接算出其对应的分片位置。

这样查询时也可根据指定字段路由,到指定分片查询,无需到所有分片查询。根据业务特点,将作者账号id puin 作为路由字段,路由过程:

259288b145cdb4a3db5f478e4c7ffeb9.webp

这样对带有作者账号id的召回的查询吞吐量可以提高6倍,整体来看,给ES带来了30%的吞吐性能提升。

4 关闭不需要索引或排序的字段

通过索引模板,将不需要索引字段指定为"index":false,将不需要排序的字段指定为"doc_values":false。

写在最后

编程严选网(www.javaedge.cn),程序员的终身学习网站已上线!

点击阅读原文,即可访问网站!

欢迎长按图片加好友,我会第一时间和你分享软件行业趋势面试资源学习途径等等。

添加好友备注【技术群交流】拉你进群,更多教程资源应有尽有

关注公众号后,在后台私信:

  • 回复 架构师 ,获取架构师学习资源教程
  • 回复【面试 ,获取最新最全的互联网大厂面试资料
  • 回复【 ,获取各种样式精美、内容丰富的简历模板
  • 回复 路线图 ,获取直升Java P7技术管理的全网最全学习路线图
  • 回复 大数据 ,获取Java转型大数据研发的全网最全思维导图
  • 微信【ssshflz】私信  【副业】 进副业交流群
  • 点击 阅读原文 ,即可访问程序员一站式学习网站
    
                                                            

最近在准备面试,为大家准备一份2024最新最全Java学习路线一条龙

浏览 16
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报