单线程的redis如何实现并发访问?

简介: 在服务器端软件中, 并发和并行性通常被认为是不同的概念。在服务器中, 支持并发 i/o 意味着服务器能够通过执行与那些客户端仅有一个计算单元对应的几个流来为多个客户端提供服务。在这种情况下, 并行性意味着服务器能够同时执行多个操作 (具有多个计算单元), 这是不同的。

在服务器端软件中, 并发和并行性通常被认为是不同的概念。在服务器中, 支持并发 i/o 意味着服务器能够通过执行与那些客户端仅有一个计算单元对应的几个流来为多个客户端提供服务。在这种情况下, 并行性意味着服务器能够同时执行多个操作 (具有多个计算单元), 这是不同的。


例如, 一个酒保可以照顾几个客户, 而他只能准备一次饮料。这样他就可以不并行地提供并发性。


单线程程序绝对可以通过使用 i/o 复用机制和事件循环 (Redis用的是事件循环), 在 i/o 级别上提供并发性。


并行性具有成本: 在现代硬件上可以找到多个套接字/多个内核, 线程之间的同步非常昂贵。另一方面, 像 Redis 这样的高效存储引擎的瓶颈往往是网络--CPU前面的陷阱。因此, 孤立的事件循环 (不需要同步) 被视为构建高效、可伸缩的服务器的良好设计。


Redis 操作是原子的事实仅仅是单线程事件循环的结果。有趣的一点是, 原子性是以不额外的成本提供的 (它不需要同步)。用户可以利用它来实现乐观锁定和其他模式, 而无需支付同步开销。


如果 Redis 是单线程的, 那么为什么需要锁定机制呢?

Redis 确实 (大多是) 单线程, 但当多个客户端尝试在相邻的时间接近时进行不同的事情时, 则需要锁定。在 RiA 中讨论的锁定完全是关于-确保只有一个客户端/线程执行特定任务, 或者确保更新不会出错。

这里有一个例子, 为什么你需要锁定, 尽管 Redis 有单线程性: 假设你有一个值在 Redis, 一个数字, 例如存储在一个名为 foo 的键值下。您的应用程序的代码读取该数字 (GET foo), 做一些事情 (ADD 1) 并将其写回 (SET)。当您在单个线程中运行代码时, 这就是它的外观:

应用程序 Redis

App               Redis
 |---- GET foo ---->|
 |<------ 1 --------|
 |                  |
 | thinking...      |
 |                  |
 |--- SET foo 2 --->|
 |<----- OK --------|


现在让我们看看两个应用程序客户端尝试这样做时会发生什么:

App 1             Redis              App 2
 |---- GET foo ---->|                  |
 |<------ 1 --------|<--- GET foo -----|
 |                  |------- 1 ------->|
 | thinking...      |                  |
 |                  |       thinking...|
 |--- SET foo 2 --->|                  |
 |<----- OK --------|<--- SET foo 2 ---|
 |                  |------ OK ------->|



在这里你可以立即看到发生了什么,因为没有锁定, 尽管服务器 (主要是) 单线程的-得到的结果不是 3, foo 的值最终是2。当您添加更多的线程/客户/应用程序时, 当多个作者尝试修改数据而不进行协调 (即锁定) 时, 事情会变得更加欢快而严重。


乐观锁定只是一种方法, Redis 通过监视机制提供内置。然而, 有时, 乐观-尽管看上去容易且快乐-通常不是正确的解决方案, 所以你需要实施更好/先进/不同的机制, 以防止竞态条件。可以说, 这样的锁可能在 Redis 之外实现, 但如果您已经使用它, 那么在其中管理您的锁也是有意义的。

相关文章
|
7月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
414 83
|
4月前
|
设计模式 缓存 安全
【JUC】(6)带你了解共享模型之 享元和不可变 模型并初步带你了解并发工具 线程池Pool,文章内还有饥饿问题、设计模式之工作线程的解决于实现
JUC专栏第六篇,本文带你了解两个共享模型:享元和不可变 模型,并初步带你了解并发工具 线程池Pool,文章中还有解决饥饿问题、设计模式之工作线程的实现
305 2
|
7月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
444 83
|
9月前
|
机器学习/深度学习 消息中间件 存储
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
360 0
|
9月前
|
设计模式 运维 监控
并发设计模式实战系列(4):线程池
需要建立持续的性能剖析(Profiling)和调优机制。通过以上十二个维度的系统化扩展,构建了一个从。设置合理队列容量/拒绝策略。动态扩容/优化任务处理速度。检查线程栈定位热点代码。调整最大用户进程数限制。CPU占用率100%
580 0
|
9月前
|
存储 缓存 安全
JUC并发—11.线程池源码分析
本文主要介绍了线程池的优势和JUC提供的线程池、ThreadPoolExecutor和Excutors创建的线程池、如何设计一个线程池、ThreadPoolExecutor线程池的执行流程、ThreadPoolExecutor的源码分析、如何合理设置线程池参数 + 定制线程池。
JUC并发—11.线程池源码分析
|
监控 Kubernetes Java
阿里面试:5000qps访问一个500ms的接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
本文由40岁老架构师尼恩撰写,针对一线互联网企业的高频面试题“如何确定系统的最佳线程数”进行系统化梳理。文章详细介绍了线程池设计的三个核心步骤:理论预估、压测验证和监控调整,并结合实际案例(5000qps、500ms响应时间、4核8G机器)给出具体参数设置建议。此外,还提供了《尼恩Java面试宝典PDF》等资源,帮助读者提升技术能力,顺利通过大厂面试。关注【技术自由圈】公众号,回复“领电子书”获取更多学习资料。
|
8月前
|
NoSQL Linux Redis
每天百万访问也不怕,Redis帮你搞定UV统计
本文介绍了使用Redis实现高性能UV统计系统的方法。Redis凭借其内存数据库特性,支持毫秒级响应和自动去重,非常适合高并发场景下的访客统计。核心思路是利用Redis的Set数据结构作为"每日签到墙",通过记录用户访问ID实现自动去重,并设置24小时过期时间。文章提供了Python代码示例,展示如何记录用户访问和获取当日UV统计数据,还可扩展实现多页面UV统计。相比传统数据库方案,Redis方案更加轻量高效,是中小型网站实现流量统计的理想选择。
674 0
|
10月前
|
存储 NoSQL Redis
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 +  无锁架构 +  EDA架构  + 异步日志 + 集群架构