首页 > 其他分享 >大厂的视频推荐索引构建解决方案

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

时间:2024-03-07 11:14:22浏览次数:30  
标签:缓存 解决方案 写入 索引 大厂 链路 数据 ES

关注我,紧跟本系列专栏文章,咱们下篇再续!

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

负责:

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

目前主攻降低软件复杂性设计、构建高可用系统方向。

参考:

1 背景

在视频推荐场景:

  • 让新启用的视频尽可能快的触达用户,对新闻类内容尤为关键
  • 快速识别新物品的好坏,通过分发的流量,以及对应的后验数据,来判断新物品是否值得继续分发流量

这两点对索引先验数据和后验数据的延迟都高要求。下文介绍视频推荐的索引构建方案。

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

2 视频推荐整体架构

数据链路角度,从下往上:

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

视频在用户侧曝光后,从上到下,是另一条数据链路:用户对视频的行为,如曝光、点击、播放、点赞、评论等经过上报至日志服务,然后通过实时/离线处理产生特征回到存储层,由此形成循环。

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

3 方案设计

旧方案的索引每半小时定时构建,无法满足近实时要求。分析索引构建方案,发现挑战:

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

3.1 业界主流方案调研

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

可选方案主要在自研或开源成熟方案。研究发现:

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

最终选择基于ES的索引服务。不选Solr,主要因为ES有更成熟社区及云厂商PaaS服务支持,使用更灵活方便。

3.2 数据链路图

3.2.1 方案介绍

数据链路角度分两块:

  • 先验数据链路,数据源主要来自内容中心,通过解析服务写入到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写模块,需先读数据,累加后再写入

Redis写模块,需先读数据,累加后再写入。先读后写,需要保证原子性,而这里可能存在同时有其他线程在同一时间写入,造成数据不一致。

解决方案1是通过redis加锁来完成;解决方案2如下图所示,在kafka队列中,使用rowkey作为分区key,确保同一rowkey分配至同一分区,而同一只能由同一消费者消费,也就是同一rowkey由一个进程处理,再接着以rowkey作为分线程key,使用hash算法分线程,这样同一rowkey就在同一线程内处理,因此解决了此处的一致性问题。另外,通过这种方案,同一流内的一致性问题都可以解决。

② Redis写模块,Redis写入需先消费kafka的消息

这就要求kafka消息commit和redis写入需要在一个事务内完成,即需保证原子性。

如果这里先commit再进行redis写入,那么如果系统在commit完且写入redis前宕机了,那么这条消息将丢失掉;如果先写入,在commit,那么这里就可能会重复消费。

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

③ 写入ES有3个独立进程

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

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

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

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

3.2.3 写入平滑

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

此处监控间隔是10秒,可以看到,由于聚合窗口是1min,每分钟前10秒写入达到峰值,后面逐渐减少,然后新的一分钟开始时又周期性重复这种情况。

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

最终我们使用以下方案来平滑写入:

使用自适应限流器来平滑写,通过统计前1min接收的消息总量,来计算当前每秒可发送的消息总量。具体实现如图,将该模块拆分为读线程和写线程,读线程统计接收消息数,并把消息存入队列;令牌桶数据每秒更新;写线程获取令牌桶,获取不到则等待,获取到了就写入。最终平滑写入后效果:




不同时间段,均达到平滑效果。

4 召回性能调优

4.1 高并发场景优化

由于存在多路召回,所以召回系统有读放大的问题,我们ES相关的召回,总qps是50W。这么大的请求量如果直接打入ES,一定是扛不住的,那么如何来进行优化呢?

由于大量请求的参数是相同的,并且存在大量的热门key,因此我们引入了多级缓存来提高召回的吞吐量和延迟时间。

多级缓存方案:

方案架构清晰,简单明了,整个链路:本地缓存(BigCache)<->分布式缓存(Redis)<->ES。

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

该方案还考虑缓存穿透和雪崩问题,上线后不久就发生一次雪崩,ES全部请求失败,且缓存全部未命中。起初还分析究竟缓存失效导致ES失败orES失败导致设置请求失效,实际就是经典缓存雪崩问题。

该方案解决了:

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

4.2 ES性能调优

4.2.1 设置合理的primary_shards

primary_shards即主分片数,是ES索引拆分的分片数,对应底层Lucene的索引数。这个值越大,单请求的并发度就越高,但给到上层MergeResult的数量也会增加,因此这个数字不是越大越好。

根据我们的经验结合官方建议,通常单个shard为150G比较合理,由于整个索引大小10G,我们计算出合理取值范围为110个,接下里我们通过压测来取最合适业务的值。压测结果:


根据压测数据,我们选择6作为主分片数,此时es的平均rt13ms,99分位的rt为39ms。

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

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

包大小由26k减小到5k,带来的收益是提升了30%的吞吐性能和降低3ms左右的rt。

4.2.3 设置合理routing字段

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

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

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

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

通过索引模板,我们将可以将不需要索引的字段指定为"index":false,将不需要排序的字段指定为"doc_values":false。这里经测试,给ES整体带来了10%左右的吞吐性能提升。

本文由博客一文多发平台 OpenWrite 发布!

标签:缓存,解决方案,写入,索引,大厂,链路,数据,ES
From: https://www.cnblogs.com/JavaEdge/p/18058453

相关文章

  • 智能便捷_AIRIOT智慧充电桩管理解决方案
    现如今随着对可持续交通的需求不断增加,电动车市场正在迅速扩大,建设更多更智能的充电桩,并通过管理平台提高充电设施的可用性和效率成为一项重要任务。传统的充电桩管理平台在对充电设施进行管理过程中,存在如下痛点:设备管理能力差:平台应具备对充电桩的基本信息(如位置、型号、充电......
  • 2.4/5GHz双频Wi-Fi®+Bluetooth® 5.2解决方案:88W8987SA2-NYE2A0G2、88W8987-A2-NYE2I
    88W8987 2.4/5GHz双频1x1Wi-Fi®5(802.11ac)+Bluetooth®5.2解决方案简介88W8987是高度集成的Wi-Fi(2.4/5GHz)和蓝牙单芯片解决方案,专为满足超高吞吐量(VHT)产品的速度、可靠性和质量要求而设计。片上系统(SoC)提供IEEE802.11ac(Wave2)、数据传输速率高达MCS9(433Mbit/s)的......
  • 索引
    索引是什么?索引是对数据库表中一列或多列的值进行排序的一种结构。MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。B+树:是通过二叉查找树,再由平衡二叉树,B树演化而来    创建索引的三种方式#方式一:createtablet5(idint......
  • 科技大厂、手机厂商、企服领域齐发力,手机智能体成AI Agent新趋势
     AIAgent涌向移动终端,手机智能体势不可挡还没搞清楚什么是AIAgent,手机Agent就已经横空出世AIGC为何涌向移动端?背后有哪些逻辑?什么是手机智能体?一文看明白科技大厂、手机厂商、企服领域都在发力,手机智能体成AIAgent新趋势AIAgent迎来移动端大爆发,手机智能体将成企业AI......
  • mysql没走索引原因分析(转)
    原文:https://juejin.cn/post/71149875593818603821、问题工作中,经常遇到这样的问题,我明明在MySQL表上面加了索引,为什么执行SQL查询的时候却没有用到索引?同一条SQL有时候查询用到了索引,有时候却没用到索引,这是咋回事?原因可能是索引失效了,失效的原因有以下几种,看你有没有踩过类......
  • AI赋能RK3588核心板在智慧消防智能监管系统的解决方案
      随着科技的飞速发展,机器视觉技术在消防领域的应用日益广泛。而RK3588核心板作为高性能、低功耗的处理器,正成为机器视觉消防产品的得力助手。    这款核心板集成了多种强大功能,内置NPU,支持INT4/INT8/INT16/FP16混合运算,运算能力高达6Tops。支持深度学习框架,基于Tens......
  • pandas笔记(一)-- 大的国家(逻辑索引、切片)
    题目描述如果一个国家满足下述两个条件之一,则认为该国是大国:面积至少为300万平方公里人口至少为2500万编写解决方案找出大国的国家名称、人口和面积按任意顺序返回结果表,如下例所示测试用例输入:namecontinentareapopulationgdpAfghanistanAsia65223......
  • Linux使用问题之长时间连接ssh不操作自动断开问题解决方案
    1.概要一般情况下,在使用SSHSecureShellClient的过程中,经常会遇到当用SSHSecureShell连接登录Linux后,如果几分钟没有任何操作,连接就会自动断开,提示Serverresponded"Connectionclosed.",必须重新登录才可以。2.原理主要由以下两个参数控制:ClientAliveInterval:指定了服......
  • 分布式事务解决方案详解
    1:分布式事务简介大多数场景下,我们的应用都只需要操作单一的数据库,这种情况下的事务称之为本地事务(LocalTransaction)。本地事务的ACID特性是数据库直接提供支持。本地事务应用架构如下所示:但是在微服务架构中,完成某一个业务功能可能需要横跨多个服务,操作多个数据库。这就涉......
  • 聚集索引与非聚集索引的区别
     按照物理实现方式,索引可以分为两大类:1)聚集索引:在聚集索引里,表中数据行按索引的排序方式进行存储,对查找行很有效。只有当表包含聚集索引时,表内的数据行才会按找索引列的值在磁盘上进行物理排序和存储。每张表只能有一个聚集索引,原因很简单,因为数据行本身只能按一个顺序存储。......