Redis的IO多路复用和多线程特性会破坏分布式锁的原子性吗?(下)

简介: Redis的IO多路复用和多线程特性会破坏分布式锁的原子性吗?

3.4 结果返回阶段:addReply

调用prepareClientToWrite,并在prepareClientToWrite中调用clientInstallWriteHandler,将待写回客户端加入到全局变量server的clients_pending_write列表。


然后,addReply会调用_addReplyToBuffer等函数,将要返回的结果添加到客户端的输出缓冲区。


至此,这就是一条命令如何从读取,经过解析、执行等步骤,最终将结果返给客户端,该过程以及涉及的主要函数:


1.png

若在前面命令处理过程中,都由I/O主线程处理,则命令执行的原子性肯定能得到保证,分布式锁的原子性也相应得到保证。


但若这个处理过程配合上了I/O多路复用机制和多IO线程机制,那这俩机制是在这个过程的什么阶段发挥作用的?会不会影响命令执行的原子性?


所以现在就要明确,这俩机制到底参与了什么流程,才能知道是否对原子性保证有副作用。

4 I/O多路复用会影响对命令原子性吗?

I/O多路复用机制是在readQueryFromClient执行前发挥作用的。在事件驱动框架中调用aeApiPoll函数,获取一批已就绪的socket描述符。然后执行一个循环,针对每个就绪描述符上的读事件,触发执行readQueryFromClient函数。


如此,即使I/O多路复用机制同时获取了多个就绪的socket描述符,但实际处理时,Redis主线程仍是针对每个事件逐一调用回调函数进行处理。且针对写事件,I/O多路复用机制也是针对每个事件逐一处理。


I/O多路复用机制通过aeApiPoll获取一批事件,然后逐一处理:

1.png

这表明,即使使用I/O多路复用,命令的整个处理过程仍可由I/O主线程完成,也就仍保证命令执行的原子性。如下就是I/O多路复用机制和命令处理过程的关系:

1.png

5 多I/O线程会破坏命令原子性吗?

多I/O线程可执行读操作或写操作。对读操作,readQueryFromClient在执行过程中,会调用 postponeClientRead 将待读客户端加入 clients_pending_read 等待列表。


然后,待读客户端会被分配给多I/O线程执行,每个IO线程执行的函数就是 readQueryFromClient,它会读取命令=》调用processInputBuffer解析命令,该过程和Redis 6.0前代码一致。


而Redis 6.0 processInputBuffer新增了个判断条件:若客户端有CLIENT_PENDING_READ标识,则解析完命令后,processInputBuffer只会把客户端标识改为CLIENT_PENDING_COMMAND,就退出命令解析的循环流程。


此时,processInputBuffer只是解析了第一个命令,不会实际调用processCommand执行命令:

image.png

这样,等所有I/O线程都解析完了第一个命令后,I/O主线程中执行的handleClientsWithPendingReadsUsingThreads会再调用processCommandAndResetClient执行命令及调用processInputBuffer解析剩余命令。


所以,即使使用多I/O线程,其实命令执行阶段也是由主I/O线程完成,所有命令执行的原子性仍得到保证,即不会破坏分布式锁的原子性。

写回数据流程

该阶段,addReply是将客户端写回操作推迟执行的,而此时Redis命令已完成执行,所以,即使有多个I/O线程在同时将客户端数据写回,也只是把结果返给客户端,并不影响命令在Redis Server的执行结果。因此,即使用了多I/O线程写回,Redis同样不会破坏命令执行的原子性。


使用多I/O线程机制后,命令处理过程各个阶段是由什么线程执行:

1.png

6 总结

加锁和解锁操作分别可以使用SET命令和Lua脚本与EVAL命令来完成。那么,分布式锁的原子性保证,就主要依赖SET和EVAL命令在Redis server中执行时的原子性保证了。


Redis中命令处理的整个过程在Redis 6.0版本前都是由主IO线程来执行完成的。虽然Redis使用了IO多路复用机制,但是该机制只是一次性获取多个就绪的socket描述符,对应了多个发送命令请求的客户端。而Redis在主IO线程中,还是逐一来处理每个客户端上的命令的,所以命令执行的原子性依然可以得到保证。


使用Redis 6.0版本后,命令处理过程中的读取、解析和结果写回,就由多IO线程处理。不过多IO线程只是完成解析第一个读到的命令,命令实际执行还是由主IO线程处理。当多IO线程在并发写回结果时,命令就已执行完,不存在多IO线程冲突问题。所以,使用了多IO线程后,命令执行原子性仍可得到保证。


多IO线程实际并不会加快命令的执行,只会将读取解析命令并行化执行,写回结果并行化执行,且读取解析命令还是针对收到的第一条命令。这一设计考虑还是由于网络IO需加速处理。如命令执行本身成为Redis运行时瓶颈,其实可考虑使用Redis切片集群提升处理效率。


目录
相关文章
|
12月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
797 2
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
851 6
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
数据采集 存储 数据可视化
分布式爬虫框架Scrapy-Redis实战指南
本文介绍如何使用Scrapy-Redis构建分布式爬虫系统,采集携程平台上热门城市的酒店价格与评价信息。通过代理IP、Cookie和User-Agent设置规避反爬策略,实现高效数据抓取。结合价格动态趋势分析,助力酒店业优化市场策略、提升服务质量。技术架构涵盖Scrapy-Redis核心调度、代理中间件及数据解析存储,提供完整的技术路线图与代码示例。
2012 0
分布式爬虫框架Scrapy-Redis实战指南
|
11月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
902 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
11月前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
数据采集 存储 NoSQL
基于Scrapy-Redis的分布式景点数据爬取与热力图生成
基于Scrapy-Redis的分布式景点数据爬取与热力图生成
1127 67
|
NoSQL Redis
Lua脚本协助Redis分布式锁实现命令的原子性
利用Lua脚本确保Redis操作的原子性是分布式锁安全性的关键所在,可以大幅减少由于网络分区、客户端故障等导致的锁无法正确释放的情况,从而在分布式系统中保证数据操作的安全性和一致性。在将这些概念应用于生产环境前,建议深入理解Redis事务与Lua脚本的工作原理以及分布式锁的可能问题和解决方案。
450 8
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
3685 7
|
缓存 监控 NoSQL
Redis设计与实现——分布式Redis
Redis Sentinel 和 Cluster 是 Redis 高可用与分布式架构的核心组件。Sentinel 提供主从故障检测与自动切换,通过主观/客观下线判断及 Raft 算法选举领导者完成故障转移,但存在数据一致性和复杂度问题。Cluster 支持数据分片和水平扩展,基于哈希槽分配数据,具备自动故障转移和节点发现机制,适合大规模高并发场景。复制机制包括全量同步和部分同步,通过复制积压缓冲区优化同步效率,但仍面临延迟和资源消耗挑战。两者各有优劣,需根据业务需求选择合适方案。
1100 14