为什么用Redis?说说Redis的线程模型

使用Redis存储相比直接使用Java内存的Map有以下几个优势:

持久化:

Redis支持数据持久化,即使发生服务器重启或意外宕机,数据仍然可以被恢复。而使用Java内存的Map,当应用程序关闭或重启时,数据将会丢失。

分布式支持:

Redis是一个分布式数据库,可以通过配置集群来水平扩展和处理大规模的数据集。相比之下,Java内存的Map仅限于单个应用程序实例,无法进行分布式部署。

高级数据结构:

Redis提供了丰富的数据结构,如字符串、哈希表、列表、集合和有序集合等,并且支持在这些数据结构上执行各种原子操作和高级操作。这使得Redis能够更方便地处理复杂的数据操作和查询。而Java内存的Map只提供了基本的键值对数据结构。

缓存功能:

Redis常用于作为缓存层,可以通过设置过期时间、LRU策略等来自动管理缓存数据,帮助减轻数据库的负载压力。而Java内存的Map没有提供像Redis一样的缓存管理功能。

数据类型灵活:

Redis支持多种操作类型并提供了相应的操作方法,可以满足不同场景下的需求。Java内存的Map只能存储简单的键值对。

需要注意的是,Redis作为一个独立的数据库服务,与应用程序通过网络进行通信。而Java内存的Map直接在程序内部使用。因此,使用Redis可能会引入一些额外的网络开销和延迟。对于较小规模的数据集和简单的数据需求,直接使用Java内存的Map可能更加合适。但对于大规模的、需要持久化、分布式支持以及复杂数据操作的场景,Redis是一个更强大和适用的选择。

为什么要用Redis?

从上面可知:Redis是基于内存,常用作于缓存的一种技术,并且Redis存储的方式是以key-value的形式。

我们可以发现这不就是Java的Map容器所拥有的特性吗,那为什么还需要Redis呢?

1.Java实现的Map是本地缓存,如果有多台实例(机器)的话,每个实例都需要各自保存一份缓存,缓存不具有一致性。

2.Redis实现的是分布式缓存,如果有多台实例(机器)的话,每个实例都共享一份缓存,缓存具有一致性。

3.Java实现的Map不是专业做缓存的,JVM内存太大容易挂掉的。一般用做于容器来存储临时数据,缓存的数据随着JVM摧毁而结束。Map所存储的数据结构,缓存过期机制等等是需要程序员自己手写的。

4.Redis是专业做缓存的,可以用几十个G来做缓存。Redis一般用作缓存,可以将缓存数据保存在硬盘中,Redis重启了后可以将其恢复。原生提供丰富的数据结构、缓存过期机制,等等简单好用的功能。

1、本地缓存资源浪费

多个业务系统的节点每个都要存一份,10个节点的集群就浪费了9份。

2、本地缓存有内存一致性问题

不同节点的本地内存数据,版本会不一致。就是说A节点数据值是x2,但B节点还没来得及更新还是x1。这会导致不同用户请求,甚至在同一个用户请求打到不同节点上,值不一样,造成业务错误。

3、本地缓存的机器内存有限

Redis集群模式,是分片的,内存理论上是可以无限扩展,轻松存个几百G。而业务程序不可能存的下。

Redis的线程模型

Redis最初设计为单线程的服务器,即所有的客户端请求都由主线程顺序地处理。这意味着在同一时间,Redis只能处理一个请求。虽然听起来单线程可能会成为性能瓶颈,但由于 Redis 的核心操作都是在内存中完成的,且单个操作的执行速度非常快,因此单线程模型在大多数情况下都能提供高性能。

为什么 Redis 选择单线程模型

  1. 避免了线程切换的开销:线程切换会带来 CPU 上下文切换的开销。由于 Redis 的操作通常非常快速,线程切换的成本可能会比操作本身还高。

  2. 简化了代码实现:单线程模型避免了多线程编程中的竞态条件、死锁等复杂问题,使代码更加简单可靠。

  3. 利用 IO 多路复用技术:Redis 使用了 IO 多路复用机制,通过 epollkqueue 等系统调用,同时监听多个文件描述符(客户端连接),当某个文件描述符就绪时,主线程会处理相应的事件。

Redis 的多线程优化

尽管 Redis 的核心操作是单线程的,但在 Redis 6.0 及以后的版本中,引入了 多线程 IO 特性,用于优化网络 IO 的性能。

多线程 IO 模型
  • 背景:在高并发环境下,网络数据的读写会占用 Redis 主线程的部分时间,导致处理请求的效率下降。

  • 实现方式:Redis 在接收客户端的请求时,使用多线程并行地读取网络数据,将请求数据读入内存缓冲区。

  • 工作流程

    1. 主线程:负责接受新的客户端连接,管理客户端状态,以及执行具体的命令操作。

    2. IO 线程:在读取阶段,多个 IO 线程并行地从已就绪的客户端连接中读取请求数据。在回复阶段,IO 线程也可以并行地将响应数据写回给客户端。

注意事项
  • 线程安全:Redis 确保在多线程模型下的数据安全性,IO 线程仅负责数据的读写,不涉及对数据的修改操作。

  • 性能提升:在网络带宽高、CPU 多核的环境下,启用多线程 IO 可以显著提升 Redis 的吞吐量。

Redis 的事件循环机制

Redis 的单线程通过 事件循环 来管理所有的事件,包括网络事件和定时任务。事件循环主要包括以下部分:

  1. 文件事件处理器:基于 Reactor 模式,使用 IO 多路复用机制监听套接字事件,将就绪的事件放入队列中处理。

  2. 时间事件处理器:处理定时任务,如键的过期检查、异步任务等。

  3. 事件调度器:循环地从事件队列中取出事件,调用相应的事件处理器。

总结

  • 单线程核心:Redis 的核心操作(如命令执行)依然是单线程的,这使得 Redis 在处理数据时避免了锁的竞争,保证了操作的原子性。

  • 多线程 IO 优化:从 Redis 6.0 开始,引入了多线程 IO,以优化网络数据的读写,提高高并发环境下的性能。

  • 适用场景:对于多数使用场景,默认的单线程模型已经足够高效。只有在网络 IO 成为瓶颈时,才需要考虑启用多线程 IO。

  • 感谢你看到最后,最后再说两点~
      ①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。
      ②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~

    感兴趣的可以关注公众号一起学习,我会不定期发布学习和一些有意思的见闻。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月夜奇术师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值