点击上方“服务端思维”,选择“设为星标”
回复”669“获取独家整理的精选资料集
回复”加群“加入全国服务端高端社群「后端圈」
作者 | 马骎
出品 | http://m6z.cn/6oFglu
可靠性保障是一个复杂的系统工程,特别对于可靠性已经出现问题的线上服务,在业务迭代、成本约束、人力投入等方面的约束下 ,提升其可用性就不再是单纯的技术问题了。
微博推荐引擎作为各类推荐业务在线服务的枢纽环节支持着微博热门流、小视频后推荐等业务,在快速的迭代过程中,其可靠性问题逐渐暴露出来。同时随着业务需求的变化,其在物料规模、已读过滤等方面的限制逐渐成为了限制迭代的瓶颈点。频发的抖动与宕机,快速膨胀到几十万行的代码,极大地消耗了开发同学的精力。在多重的压力下,推荐引擎已经滑向了失控的边缘。
在 QCon 全球软件开发大会(2021)北京站上,微博研发中心基础架构部架构师马骎分享了微博推荐引擎在数月的时间里从不可控回到可控,可用性由不足 2 个 9 提升至 3 个 9 以上,同时提升业务支持能力的经验。我们整理了他的演讲,以期帮你系统性解决可靠性问题。(下文以马骎老师第一人称叙述)
我从去年 9 月底开始负责微博推荐引擎的改造,历时三个月大幅提升了其性能。今天我将分享该项目经验,包括:微博推荐引擎架构及当时情况的介绍、在线业务稳定性分析、推荐引擎中的改造实践。
1微博推荐引擎介绍
微博推荐引擎服务于微博各类推荐业务,如服务热门流、热点流、视频后推荐等,是推荐系统的枢纽,需结合特征、模型、物料等环节驱动业务运行,其架构如下图所示:
推荐引擎架构
用户请求推荐内容时会先到达推荐前端,随后在总控上开启推荐流程。第一步,总控会获取本次刷新相关的信息,如用户兴趣、引流微博特征、已读信息等。
第二步,总控将相关信息输入召回引擎,召回引擎根据这些信息获得备选微博 ID。召回分两类:一类为标签召回,即根据用户信息、热点业务规则进行排序;另一类为模型召回,即变换数据形式,用向量的方式通过本地或远程模型服务获取物料。
第三步,获取备选 ID 后,排序引擎会先补充相关特征信息将备选 ID 构造成完整物料,通过 Hash 等方式将之转化为可供排序模型使用的特征向量,送到排序模型打分,完成排序
第四步,总控在插入广告后通过前端填充内容,完成推荐。
此外,训练将接收引擎及客户端用户行为日志,实时更新排序、召回模型;物料将实时更新物料库,将特征的更新总结为物料包流和更新流,供引擎实时更新和加载。
推荐引擎可靠性挑战
微博推荐引擎快速迭代中暴露的问题主要是 稳定性和业务支持。
稳定性表现为单台引擎(如前文排序引擎)工作几个小时后即会发生一次宕机、内存溢出、超时启停等问题。如有突发流量更疲于应对。此外,当时物料规模、已读存储能力等方面的设计已无法满足现在业务的需求。
改造系统比打造新系统更难,不仅需要梳理数 10 万行代码,同时改造中系统还在迭代不能下线,再加上团队人力不足,外部的压力(如公司对成本、机器利用率等的要求)等,该问题已经超越了技术问题。
系统可靠运行的因素
在线系统稳定运行依赖于三个方面:系统本身架构设计和代码的质量;自动化的工具(如扩缩容、异常治理等);运维、监控人员人力。 这三方面如同一个木桶,有一个长板即可支持较大的流量:如若系统健壮则运行时必然问题较少,或若运维人力足沛也可解决多数问题。
然而事实上,多数公司均难以 100% 保证某一长板,此时需要结合公司具体情况保证基本质量,出现错误时多数依靠工具解决,少数依靠运维人员。
对于当时的微博推荐引擎来说,质量为核心问题,但投入大、见效慢;虽有如异常处置等简单工具建设,但是组织简单且互有冲突,甚至无扩缩容工具,开发空间大,只需适配微博内部成熟工具体系,即可乘高决水,事半功倍;同时急需从零到一引入运维团队。
2改造实践
微博推荐引擎改造分为三个阶段 。第一,通过工具建设先稳住系统,保障后期改造的精力;第二,集中人力大量重写核心环节,提升系统质量;第三,再次优化工具建设,降低维护稳定所需人力。
具体我将分享:物料存储结构改造、已读服务改造和扩缩容工具。
初始阶段,我们接入了微博成熟的运维工具,组合了原有自动处置工具、优化了上线脚本,实现了基于 QPS 和超时率的简单自动缩扩容功能。
质量改造 - 物料
排序引擎运行的第一步为将物料初始化为带特征的物料,一次需处理数万条数据,原物料携带特征多,一次请求所需信息量大,因此我们选择了单机存储所有物料。
存储原使用基于内存映射的外部存储引擎。该引擎沟通速度慢,沟通占用大,存在内存性能问题(微博推荐引擎的核心问题所在),还限制了物料规模。因此我们重写了该引擎,重写时考虑了两个方面:单条物料存储和整体物料存储。
物料具有以下特征:特征数量数百但平均填充率较低,整体数据较稀疏,大量特征为字符串型。 若用类实现则稀疏数据会造成内存浪费,大量字符串会造成内存碎片浪费,长期使用无法保证稳定性。因此 物料的结构设计需满足三方面要求:内存需连续不可有碎片;稀疏情况下空间的节约;不可影响系统性能。
我们实现了如下图的二级索引结构:
如图所示,我们将物料分成了四段,白色部分为头部,保存基本信息,红色部分为一级索引,黄色部分为二级索引,绿色部分为实际数据段。
该结构一级索引为 Bitmap,每一位均可表示是否有一个字段存在物料中, 实现了稀疏的支持。二级索引为所有存在字段的偏移量位置,对于字符串为编译量,对于数字或浮点数存储数据本身,保证了存储速度。此外该存储结构内存连续,满足了上述三条要求。
整体物料存储我们采用了Concurrent HashMap结构, 更新速度可达每秒钟数万,满足了物料数量的要求。
质量改造 - 已读
已读功能为推荐流程的核心环节,推荐系统需要依赖用户已读数据,将用户未读内容进行排序。微博推荐系统原已读是基于 bloom filter 实现的。
如图为微博原 30 天已读方案实例:共四个 filter,每十天存储一个 filter,每次读取覆盖最近 30 天的四个 filter,取回 bloom filter 后通过或运算将其合并成一个 bloom filter 供后续业务使用。
该方案第一 结构不合理,面对所有用户 bloom filter 大小均不变,因此:高消费的用户使用微博频率高,填充率高,则误判高;低消费用户阅读量小,空间利用率低,浪费资源。第二,该方案直接读取存储的 Redis,存储一旦出错服务也难免受牵连,稳定性差。第三,该方案各业务直接读取资源本身,判断逻辑需各服务独立实现。
因此我们做了如下改造:第一,将以读独立成为一个服务,各个业务调取服务而非缓存;将常用判断逻辑封装为 SDK,便于业务改动。
第二,存储方式上保持了 bloom filter 形式,但是串的长度和单位的大小均可变。 在写入时不按照固定时长写入,而是前一个 filter 填充率达到阈值时才开启一个新的 bloom filter,根据前一个 filter 填充速度选择下一个 filter 的大小。如此可安全节省原来一半以上的空间:高消费用户 bloom filter 串虽较长,但体积也会较大,可减少误判;超高消费用户限制最大串长度,已读记录时长虽会缩短,但是能保证其已读内容相对长久;低消费用户可用较小的 bloom filter 完成已读记录。
第三,在稳定性上,一方面我们 建立了独立的短期(如几个小时)已读存储,在主要资源不可用时提供降级服务;另一方面,我们 优化了 Redis 的资源访问方式,Meta 信息及最新一个 bloom fileter 需从主库读取, 保证信息时效性,已不更新的其他信息读取从库即可,可缓解 Redis 的存储资源。
外部工具 - 扩缩容
外部工具扩缩容一般应对两类问题:日常流量波动,如中高峰晚高峰需自动扩容应对流量高峰;热点事件突发流量,需要基于冗余度的自动扩缩容和热点应对机制。
日常流量应对较为简单,此处不再赘述。突发流量特征如下:
图中红线代表流量,绿线代表系统承稳能力(可理解为机器数量),绿线在红线之上方可保证系统正常运行。绿线高于红线的部分为冗余度。
流量在 t1 时刻到来,此时红线会快速上升,在 t2 时刻超过绿线,扩容系统会在 t1 后某点发现流量,触发扩容,最终机器在 t3 时刻到位。
实现该突发流量扩容需做到:第一,在 t1 到 t2 之间快速发现流量的到来,如此时还未做处理,到 t2 后便已超时;第二,建立降级策略以供扩容时暂用,如停止某些次要功能、减少推荐处理条数。第三,减少扩容时间(即 t1 到 t3 的时间),优化程序启动速度。
具体问题可根据历史流量数据和公司情况处理:如公司成本压力小可将冗余度调高,将绿线整体上移;如服务自身启动快,可省略降级策略。
微博推荐引擎依赖微博已有的成熟扩容基础设施,解决了流量快速发现问题;结合前文的物料改造,引擎启动速度从 20 分钟提高至了 5 分钟。
此外,微博推荐引擎在各环节上均加入了计算量条数和请求的动态降级能力,根据当前实际 QPS 与承载能力选择降级比例。例如当前可处理计算量条数的 80%,如果流量增加则只处理 70%。自动机制之外,如有热点事件预警可全公司提前动员,每日 push 场景可提前处理。
灵活的工作方法
灵活的工具可提高开发效率。我们在接入微博现有的工具体系时,先做了一个可手动查看效果及接管自动扩容逻辑的界面,提高了掌控系统的速度。利用大数据类的分析工具可通过录制大量请求、查看其 UID 或者某些特症等分析异常请求原因。
此外,本次改造中大量工作为梳理旧业务代码,繁琐无聊,团队士气也至关重要。
微博推荐改造项目共历时三个月,正确处理请求比例从不到 99% 提升至 99.9% 以上,服务耗时降低 25%,不增加资源支持单机 500 万 -1000 万物料,启动速度提升至原先的 4 倍。
— 本文结束 —
关注我,回复 「加群」 加入各种主题讨论群。
对「服务端思维」有期待,请在文末点个在看
喜欢这篇文章,欢迎转发、分享朋友圈
在看点这里