闲鱼如何一招保证推荐流稳如泰山

简介: 风雨不动安如山

作者:闲鱼技术——习武

背景

近几年互联网的快速发展中,互联网业务发展越来越复杂,业务也被拆分得越来越细,阿里内部业务也发生着翻天覆地的变化,从最初的单体应用,到后面的分布式集群,再到最近几年大中台小前台的业务形态,作为后端开发,依赖的服务方越来越多,同时依赖服务方的故障因素也会越来越多的会影响到闲鱼的上层业务的稳定。例如在闲鱼主推商品流的业务场景中,商品中台数据库的抖动会造成主推商品流的卡顿或者页面显示空窗现象,个性化算法中台向量集群的扩容也会造成推荐内容延时被拖到非常长,后面还有可能依赖其他的业务中台,作为上层业务如何保证依赖的中台越来越多的情况下,还能保证服务的稳定性运行呢?

业界主流溜一遍

根据日常解决问题的经验,不能直接解决业务问题本身,可以折中解决业务问题也是一个不错的办法。上述业务问题中,当业务出现问题的时候,可以折中提前置备好所需的业务数据返回给业务,也是一个不错的办法。在闲鱼主推商品流的业务场景中,对可靠性要求非常高,因为推荐商品失败,用户看到推荐页出现空窗,业务所需的数据量大概是5页的推荐商品数据流,大概为3M左右。在实际解决问题中,笔者从业务所需的数据量级、可靠性要求级别等角度调研了业界一些通用解决办法。
image.png
为了给用户良好的业务体验,笔者主要使用服务端数据冗余、客户端数据冗余、熔断机制等方法,来确保用户对闲鱼App流畅的业务体验。笔者主要服务端数据冗余聊聊本地缓存,根据笔者在阿里断网演练的经验,断网演练时,某个区域的所有服务不可用,所以笔者在技术选型的时候没有考虑分布式缓存Redis,Memcache之类等。目前就业界本地缓存库有Guava、Caffeine、Ehcache、Cache2K、ConcurrentHashMap、Varnish、JackRabbit等,笔者选取了几个性能比较优越的缓存库比较,下面笔者从功能上、性能上、易用性、集群能力、可视化报表上等分别比较。
image.png
笔者对照目前业务需求对比了上述四个组件,在定时失效策略能力上,除了ConcurrentHashMap都是使用定时失效能力,并且三个组件时间复杂度都是O(n)。在集群能力上,Ehcache依赖自身网络协议保证集群数据一致性,不能使用现有集团内部组件保证数据一致性。在本地缓存能力上,Caffeine的写能力[1]优与Guava。在组件通用性上,Guava组件更加通用。最终笔者选用了Guava组件作为本地缓存组件,因为Guava 组件更加通用,并且很方便与阿里内部中间件集成配合使用。在集群数据同步能力,通过配置中心中间件实现数据同步,在可视化报表能力,通过定时任务打印日志,日志采集系统采集展示数据报表。接下来笔者介绍如何添加上述三种能力和优化Guava本地缓存能力。

我的集群Cache组件

Guava Caching提供了定时失效、最后访问失效、最后写入失效策略等能力,笔者主要使用了定时失效能力,在首次写入Key后,指定时间过后,该Key会失效,业务获取该Key时,会调用reload方法重新同步加载该Key。如果使用invalid方法使该Key无效,业务并发再次获取该Key,多线程加载该Key时,只有一个业务线程调用load方法加载该Key,其他线程等待该Key,加载完成后重新进入指定时间后流程。笔者在原来Guava Cache本地缓存能力上结合Spring自动注入能力,进行工程化,添加了业务所需的如下三种能力

  • 当key失效,本地缓存reload异步加载
  • 失效本地缓存key,整个集群机器上key失效能力
  • 定时上报本机Cache内各个Key在本地缓存大小

根据上述业务能力,整体流程图如下所示
image.png集群本机Cache组件的整体结构类图如下:
image.png

  • AbstractCacheLoader重写父类CacheLoader的reload方法,添加异步加载能力
  • LocalCacheManager管理所有实现AbstractCacheConfig的子类,并上报各自本地缓存大小。
  • 实现AbstractCacheConfig的业务配置子类,例如CurrentCacheConfig等,调用invalidate方法时,会通知集群本机Cache中Key消息。

业务同学在使用集群本机Cache组件时,只需要继承AbstractCacheConfig抽象类,声明为Bean,即用集群本机Cache组件,业务同学无需关心集群环境问题等。相比Guava cache组件,提供了集群本机Cache Key失效能力,以及对Key集中管理和监控,减少了单独使用Guava cache带来内存无法管理的问题。
接下来笔者介绍使用集群本机Cache组件能力的典型案例: 自动置备兜底组件。

典型栗子

自动置备兜底组件

兜底是在服务遇到外部依赖异常(超时、不可用、数据异常等),可能导致服务无可以返回的正常数据时,服务通过使用兜底数据提供服务的一种降级行为。自动置备兜底组件使用集群本机cache的本机缓存能力和集群失效能力,很方便完成兜底数据置备。在闲鱼的业务场景中使用兜底置备组件的场景非常多,例如闲鱼主推商品流等。
兜底自动置备组件原理如下:
image.png

  • 使用定时任务scheduleX2定时触发服务集群中的一台服务器,执行兜底置备,更新tair缓存内容,失效本地缓存,即失效集群server的本地缓存。
  • 当业务请求获取key时,会获取tair中最新内容,并缓存到本地,再次请求,直接本地获取。

详细业务请求流程图如下所示
image.png自动兜底组件已经在闲鱼的多个业务场景得到使用,在断网演练情况下,服务端RT延时和成功率有了明显的提升,闲鱼主要业务场景的提升效果如下:
image.png

展望

在集群本机cache组件使用过程中也发现一些问题,例如有时候集群本机cache缓存错误的配置,需要重启集群或者等待key失效,所以需要集群本机cache组件web管理功能。在集群本机cache组件推广中,发现有些业务场景的缓存key对应的缓存对象比较大,或者缓存key的数量比较多,后期按照key使用频率等级,考虑对于长期不使用的key存储到本机磁盘上,让业务方不关心缓存Key过大可能造成的问题。




参考:
[1]: Halodoc Caching Analysis

相关文章
|
24天前
|
消息中间件 Java Kafka
Kafka不重复消费的终极秘籍!解锁幂等性、偏移量、去重神器,让你的数据流稳如老狗,告别数据混乱时代!
【8月更文挑战第24天】Apache Kafka作为一款领先的分布式流处理平台,凭借其卓越的高吞吐量与低延迟特性,在大数据处理领域中占据重要地位。然而,在利用Kafka进行数据处理时,如何有效避免重复消费成为众多开发者关注的焦点。本文深入探讨了Kafka中可能出现重复消费的原因,并提出了四种实用的解决方案:利用消息偏移量手动控制消费进度;启用幂等性生产者确保消息不被重复发送;在消费者端实施去重机制;以及借助Kafka的事务支持实现精确的一次性处理。通过这些方法,开发者可根据不同的应用场景灵活选择最适合的策略,从而保障数据处理的准确性和一致性。
60 9
|
24天前
|
消息中间件 存储 Kafka
【Kafka大揭秘】掌握这些秘籍,让你的消息状态跟踪稳如老狗,再也不怕数据丢失的尴尬时刻!
【8月更文挑战第24天】Kafka作为一个领先的分布式流数据平台,凭借其出色的性能和扩展性广受青睐。为了保障消息的可靠传输与处理,Kafka提供了一系列核心机制:生产者确认确保消息成功到达;消费者位移管理支持消息追踪与恢复;事务性消息保证数据一致性;Kafka Streams的状态存储则适用于复杂的流处理任务。本文将详细解析这些机制并附带示例代码,帮助开发者构建高效稳定的消息处理系统。
30 5
|
9月前
|
前端开发 Cloud Native 大数据
坑爹,线上同步近 3w 个用户导致链路阻塞引入发的线上问题,你经历过吗?
坑爹,线上同步近 3w 个用户导致链路阻塞引入发的线上问题,你经历过吗?
|
存储 NoSQL 算法
线上真实排队系统重构案例分享——实战篇
线上真实排队系统重构案例分享——实战篇
475 0
|
搜索推荐 5G 定位技术
「第三期」宝藏级5G消息应用号推荐:这么好用的5G消息发现了吗?
新一批“5G消息应用号”已经到货啦!还不知道有哪些宝藏级5G消息应用号可以体验的小伙伴赶紧看过来啦~
「第三期」宝藏级5G消息应用号推荐:这么好用的5G消息发现了吗?
闲鱼 - 如何关闭多余的推送消息但又不想错失客户消息?
闲鱼 - 如何关闭多余的推送消息但又不想错失客户消息?
169 0
闲鱼 - 如何关闭多余的推送消息但又不想错失客户消息?
|
消息中间件 存储 数据库
蚂蚁二面:MQ消费端遇到瓶颈除了横向扩容外还有其他解决办法?
蚂蚁二面:MQ消费端遇到瓶颈除了横向扩容外还有其他解决办法?
蚂蚁二面:MQ消费端遇到瓶颈除了横向扩容外还有其他解决办法?
|
机器学习/深度学习 智能设计 自然语言处理
无尽流场景优化总结
无尽流场景优化总结
190 0
无尽流场景优化总结
|
缓存 负载均衡 网络协议
婚恋源码实现稳定直播,需要数据快速分发
CDN是基于现有网络实现的,它在现有网络的基础上,新加了一层网络架构,然后将婚恋源码的内容分发到各个节点上,方便该节点附近的用户就近访问,这样就能解决网络拥堵、用户访问延迟高等问题,提高访问命中率。