微服务广播模式实践:维护内存数据的缓存一致性

本文分享自华为云社区《微服务广播模式实践》,作者:张俭 。

微服务广播模式,指的是在微服务多实例部署的场景下,将消息广播到多个微服务实例的一种模式。

广播模式,一般用来维护微服务的内存数据,根据数据类型的不同,有助于解决两类问题。通常广播模式会使用支持发布订阅的消息中间件实现(如Redis、Kafka、Pulsar等),本文也基于消息中间件进行讨论。

利用广播模式维护一致的缓存

这应该是广播模式利用最多的一种场景,假想一个拥有海量用户的电商网站、或是一个亿级设备连接的IoT平台。势必会存在一些缓存数据,像是用户的购物车信息,或是设备的密钥缓存。如果没有广播模式,可能会存在这样的问题

当用户更新了它的购物车之后,微服务实例1的数据发生了更新,数据库的数据也成功更新。但是微服务实例2中的缓存数据未能更新,那么如果用户的请求均衡到了实例2,就会发生意想不到的后果。

这种情况下我们可以让微服务1在广播通道中发送一个缓存的invalidate消息,将微服务实例2中该用户的缓存清零,使得微服务实例2在下一次处理该用户的请求时,从数据库中读取最新的消息。

使用该模式需要注意的点:

  • 每个微服务实例应该使用不同的消费组,可以通过微服务的IP、主机名、UUID等拼装成订阅组名称,这才称得上广播之名
  • 微服务消费消息的时候,应从Latest开始消费,避免从Earliest开始消费无用的缓存清理消息
  • 由于每一次微服务重启都会产生一个新的消费组,需要注意消费组的老化,可以通过消息中间件自带的不活跃消费组老化能力兜底,建议通过gracefulExit、监听kill信号等机制来主动删除消费组信息

为什么说消费组老化比较重要呢,因为很多监控系统都会根据消费组的积压来做告警,很容易产生误告警。

利用广播模式维护内存中的数据

这种模式相对比较少见,常见于key的基数不是很大,能够将数据完整地存储在内存中,比如电商平台的企业卖家个数、物联网平台的用户个数等,并且对数据的一致性要求不是很高(因为广播模式情况下,对于两个微服务实例来说没有一致性保障)。像Apache Pulsar设计的TableView,在我看来,就是做这个事的一个最佳实践。Pulsar内部大量使用了topic存储数据,就是采用这个方式。

使用该模式需要注意的点:

  • 同上,需要使用不同的消费组名称
  • 微服务消费消息的时候,应该从Earliest开始消费,保证所有微服务内存中的消息视图一致
  • 同上,需要注意消费组的老化

为什么需要消费组老化作为保底手段

因为在极端场景下,无论是graceful的代码,还是监听kill信号的代码,都不能保证代码百分百地被执行。需要兜底。

Kafka消费组老化

Kafka通过offsets.retention.minutes参数控制消费组中offsets保留时间,在此时间内如果没有提交offset,offsets将会被删除。Kafka判定消息组中没有在线的消费者(如empty状态),且没有offsets时,将会删除此消费组。

Pulsar消费组老化

pulsar的消费组老化策略更加灵活,可以配置到namespace级别。

sql 复制代码
bin/pulsar-admin namespaces | grep expiration
    get-subscription-expiration-time      Get subscription expiration time for 
      Usage: get-subscription-expiration-time [options] tenant/namespace
    set-subscription-expiration-time      Set subscription expiration time for 
      Usage: set-subscription-expiration-time [options] tenant/namespace
            Subscription expiration time in minutes
    remove-subscription-expiration-time      Remove subscription expiration 
      Usage: remove-subscription-expiration-time [options] tenant/namespace

这里注意要合理地配置消费组的老化时间,在pulsar的当前版本(2.11版本)下,catch up读,也就是说消费组平时积压量不大。如果将消费组的老化时间配置大于等于消息的老化时间,会出现消费组老化不了的现象。

当然,由于消费组和消息老化都是定时任务,预估时间时,要考虑一定的buffer。

这里让我们稍稍dive一下原理,消费组的老化是通过判断Cursor游标的LastActive time来判断能否老化的。如果该消费组的游标位置到达了消息老化区域,被老化掉了,消费组的游标位置就会强制更新到一个可用的位置,这个时候会更新游标的LastActive time到当前时间,周而复始,导致消费组无法老化。举个🌰

假设消费组的老化时间为4h,消息的老化时间为3h,就可能会发生这样的事情

总结

广播模式在微服务架构中起到了重要的角色,尤其是在需要在微服务实例之间同步数据的场景中,它具有显著的优势。它能够帮助维护内存数据的缓存一致性。希望本篇文章能提供您全面的广播模式的知识。

点击关注,第一时间了解华为云新鲜技术~

相关推荐
用户21411832636029 分钟前
白嫖Google Antigravity!Claude Opus 4.5免费用,告别token焦虑
后端
爬山算法29 分钟前
Hibernate(15)Hibernate中如何定义一个实体的主键?
java·后端·hibernate
飞舞花下30 分钟前
微服务架构栈
微服务·云原生·架构
用户26851612107562 小时前
常见的 Git 分支命名策略和实践
后端
程序员小假2 小时前
我们来说一下 MySQL 的慢查询日志
java·后端
南囝coding2 小时前
《独立开发者精选工具》第 025 期
前端·后端
To Be Clean Coder2 小时前
【Spring源码】从源码倒看Spring用法(二)
java·后端·spring
想用offer打牌3 小时前
你真的懂Thread.currentThread().interrupt()吗?
java·后端·架构
程序员NEO3 小时前
LangChain4j 工具调用实战
后端