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

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

简介    


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

主要技术是用分布式缓存做多次相同请求的幂等处理和用有限状态机来解决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一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
2月前
|
存储 分布式计算 大数据
HBase分布式数据库关键技术与实战:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析了HBase的核心技术,包括数据模型、分布式架构、访问模式和一致性保证,并探讨了其实战应用,如大规模数据存储、实时数据分析及与Hadoop、Spark集成。同时,分享了面试经验,对比了HBase与其他数据库的差异,提出了应对挑战的解决方案,展望了HBase的未来趋势。通过Java API代码示例,帮助读者巩固理解。全面了解和掌握HBase,能为面试和实际工作中的大数据处理提供坚实基础。
130 3
|
15天前
|
缓存 安全 算法
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
12 0
|
27天前
|
消息中间件 NoSQL Java
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
75 0
|
5天前
|
负载均衡 NoSQL Java
|
12天前
|
Web App开发 物联网 Unix
操作系统的演变:从单任务到多任务再到并发与分布式
本文旨在探讨操作系统的发展历程,着重分析其从处理单一任务的原始阶段,经历多任务处理能力的增强,直至支持并发计算和分布式架构的现代转型。我们将追溯关键时间节点,审视技术创新如何塑造了今日操作系统的复杂性与多样性,并预测未来可能的发展趋势。
|
22天前
|
机器学习/深度学习 人工智能 分布式计算
编程语言未来发展趋势探析:简化与标准化、并发与分布式、智能应用新篇章
编程语言未来发展趋势探析:简化与标准化、并发与分布式、智能应用新篇章
37 1
|
15天前
|
设计模式 存储 缓存
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
19 0
|
15天前
|
设计模式 安全 NoSQL
Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
19 0
|
15天前
|
设计模式 存储 缓存
Java面试题:结合建造者模式与内存优化,设计一个可扩展的高性能对象创建框架?利用多线程工具类与并发框架,实现一个高并发的分布式任务调度系统?设计一个高性能的实时事件通知系统
Java面试题:结合建造者模式与内存优化,设计一个可扩展的高性能对象创建框架?利用多线程工具类与并发框架,实现一个高并发的分布式任务调度系统?设计一个高性能的实时事件通知系统
23 0
|
15天前
|
设计模式 存储 缓存
Java面试题:结合单例模式与Java内存模型,设计一个线程安全的单例类?使用内存屏障与Java并发工具类,实现一个高效的并发缓存系统?结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:结合单例模式与Java内存模型,设计一个线程安全的单例类?使用内存屏障与Java并发工具类,实现一个高效的并发缓存系统?结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
16 0

相关实验场景

更多