实战并发-使用分布式缓存和有限状态机

简介: 实战并发-使用分布式缓存和有限状态机

简介    


这里的并发不是高并发,只是将正式环境的一小段流量同时打到我的自测环境。一个请求同时多次发送,真正意义上并发处理同一个数据,主要需求是保证数据幂等性和正确性。

主要技术是用分布式缓存做多次相同请求的幂等处理和用有限状态机来解决MQ消息的不保证有序。

 

场景


k8s集群可以进行事件监听,静儿这次使用了一个美团内网线下的小集群。把这个小集群的对node节点和pod节点的监听事件发送到MQ,3台服务器在同时工作。也就是说一个事件会被重复收到三次。其中两台机器事件发送基本上是同时的,剩下一台是我自己的电脑。因为在家里,连着vpn,连接公司内网大概有2.5ms的延时。


在MQ事件的接收端,美团内部监控系统CAT上看到数据如下:


1112728-20190313123821463-1346205467.png


问题



当一个请求被重复在并发和有延迟的情况下会被重复收到。k8s自身也会短时间发送一些相同的请求。这些重复的请求在不考虑重复执行的副作用前提下,每次都同样的方式执行,后端的压力也会非常大。如果考虑重复执行的副作用,就是说重复的请求不幂等,数据不准确了,整个服务就非常糟糕了。


另外,不管是MQ还是k8s事件,接收处理事件的服务都不能保证先收到的事件是先产生的。多台机器的情况下,就算是先产生的,也会因为不同机器的处理速度不一样,导致后产生的事件先被执行。

 

解决


如果下面解决方法中的概念不是很清楚,可以先看5W,再回来看方法。


使用分布式缓存解决请求去重的问题


首先考虑对请求处理的维度。比如静儿举例的场景中,对node节点的watch事件,可以用node作为缓存的key,用node需要处理的关键字段作为value。如果请求中的信息与缓存中的一致,则直接返回不处理。不一致则先更新缓存为最新值,再进行处理。

注意,因为保证消息不会被并发处理。刚才的缓存值获取get和重设put操作都是用分布式锁进行了加锁的。


使用有限状态机解决乱序的问题


之所以有「乱序」这个定义,说明系统本身是消息的顺序是有要求的。顺着这个思路来考虑,可以顺理成章的得到解决方案:设定好原本的一个介绍顺序。如果收到事件A则执行事件B。如果收到事件B则执行事件C。如果没收到事件A先收到了事件B,则把MQ消息打回去重发。在打回去的阶段事件A收到处理完了,这时候再收到事件B就可以继续执行了。


刚才说的这种执行顺序的方法就是有限状态机。有限状态机在程序里的实现主要有两种。一种是通过switch case的方法。就是如果A则B的最容易理解的实现。通常被称为“可执行代码”方式。


另外一种方式是:如果每种状态要做的处理比较复杂。用switch case比较难看。就可以将处理方法抽象成一个类。将这些类的实例放到映射表里。这种实现通常被称为“被动数据”方式。

 

5W


Q:为什么MQ消息不保证有序?


A:因为MQ消息在服务器上是分区存储的,每个分区自己是有序的。分区被接收端消费的时候。一般也是多个接收端一起消费。中间的每个环节都是只能保证局部有序。如果想全局有序。就需要分区只有一个,并且接收端服务器是单点,而且一次只处理一个请求。


Q:MQ的使用上还有什么关键注意点?


A:一般情况下MQ除了不保证消息有序还不保证消息不重复。因为在「网络不可达」的情况下,MQ不能确认消息接收方收到了消息必然会重试。重试除了本文讲的幂等处理外,还可以采用每个消息有唯一的ID+去重表实现。


Q:什么是分布式缓存?


A:分布式缓存有时候也叫「集中式缓存」。是相对于「本地缓存」而言的。因为在目前的多服务器部署(分布式)时代。「本地缓存」这种将信息存储于当前服务器上,其他服务器无法感知。这时候采用一个专门的缓存服务器就可以解决这个问题。这就是分布式缓存了。


Q:什么是有限状态机?


A:有限状态机也称为FSM(Finite State Machine),是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。FSM可以把模型的多状态、多状态建的转换条件解耦。可以使维护变得容易,代码也更加具有可读性。

 

总结


并发问题对系统的影响


系统压力造成的可用性问题、多个请求同时对同一个数据产生作用产生的数据准确性问题。


解决方案


可用性问题可以从设计上在业务逻辑层之前对数据去重,例如可以使用分布式锁,让真正耗时的业务逻辑对相同的多个请求只执行一次。


数据准确性问题可以通过有限状态机保证不论收到请求顺序如何,都按照正确的逻辑来执行。

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
4月前
|
缓存 安全 Android开发
Android经典实战之用Kotlin泛型实现键值对缓存
本文介绍了Kotlin中泛型的基础知识与实际应用。泛型能提升代码的重用性、类型安全及可读性。文中详细解释了泛型的基本语法、泛型函数、泛型约束以及协变和逆变的概念,并通过一个数据缓存系统的实例展示了泛型的强大功能。
45 2
|
4天前
|
NoSQL Java Redis
秒杀抢购场景下实战JVM级别锁与分布式锁
在电商系统中,秒杀抢购活动是一种常见的营销手段。它通过设定极低的价格和有限的商品数量,吸引大量用户在特定时间点抢购,从而迅速增加销量、提升品牌曝光度和用户活跃度。然而,这种活动也对系统的性能和稳定性提出了极高的要求。特别是在秒杀开始的瞬间,系统需要处理海量的并发请求,同时确保数据的准确性和一致性。 为了解决这些问题,系统开发者们引入了锁机制。锁机制是一种用于控制对共享资源的并发访问的技术,它能够确保在同一时间只有一个进程或线程能够操作某个资源,从而避免数据不一致或冲突。在秒杀抢购场景下,锁机制显得尤为重要,它能够保证商品库存的扣减操作是原子性的,避免出现超卖或数据不一致的情况。
34 10
|
1月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
2月前
|
NoSQL Java Redis
开发实战:使用Redisson实现分布式延时消息,订单30分钟关闭的另外一种实现!
本文详细介绍了 Redisson 延迟队列(DelayedQueue)的实现原理,包括基本使用、内部数据结构、基本流程、发送和获取延时消息以及初始化延时队列等内容。文章通过代码示例和流程图,逐步解析了延迟消息的发送、接收及处理机制,帮助读者深入了解 Redisson 延迟队列的工作原理。
|
4月前
|
缓存 NoSQL 数据库
go-zero微服务实战系列(五、缓存代码怎么写)
go-zero微服务实战系列(五、缓存代码怎么写)
|
4月前
|
消息中间件 Java Kafka
"Kafka快速上手:从环境搭建到Java Producer与Consumer实战,轻松掌握分布式流处理平台"
【8月更文挑战第10天】Apache Kafka作为分布式流处理平台的领头羊,凭借其高吞吐量、可扩展性和容错性,在大数据处理、实时日志收集及消息队列领域表现卓越。初学者需掌握Kafka基本概念与操作。Kafka的核心组件包括Producer(生产者)、Broker(服务器)和Consumer(消费者)。Producer发送消息到Topic,Broker负责存储与转发,Consumer则读取这些消息。首先确保已安装Java和Kafka,并启动服务。接着可通过命令行创建Topic,并使用提供的Java API实现Producer发送消息和Consumer读取消息的功能。
85 8
|
4月前
|
人工智能 监控 虚拟化
操作系统的演变:从单任务到多任务,再到并发和分布式
随着计算技术的发展,操作系统经历了从简单的单任务处理到复杂的多任务、并发处理,再到现代的分布式系统的转变。本文将探索这一演变过程中的关键里程碑,以及它们如何塑造我们今天使用的计算机系统的架构和性能。
|
4月前
|
缓存 NoSQL Java
惊!Spring Boot遇上Redis,竟开启了一场缓存实战的革命!
【8月更文挑战第29天】在互联网时代,数据的高速读写至关重要。Spring Boot凭借简洁高效的特点广受开发者喜爱,而Redis作为高性能内存数据库,在缓存和消息队列领域表现出色。本文通过电商平台商品推荐系统的实战案例,详细介绍如何在Spring Boot项目中整合Redis,提升系统响应速度和用户体验。
69 0
|
4月前
|
消息中间件 SQL 关系型数据库
go-zero微服务实战系列(十、分布式事务如何实现)
go-zero微服务实战系列(十、分布式事务如何实现)