使用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 选择单线程模型
-
避免了线程切换的开销:线程切换会带来 CPU 上下文切换的开销。由于 Redis 的操作通常非常快速,线程切换的成本可能会比操作本身还高。
-
简化了代码实现:单线程模型避免了多线程编程中的竞态条件、死锁等复杂问题,使代码更加简单可靠。
-
利用 IO 多路复用技术:Redis 使用了 IO 多路复用机制,通过
epoll
、kqueue
等系统调用,同时监听多个文件描述符(客户端连接),当某个文件描述符就绪时,主线程会处理相应的事件。
Redis 的多线程优化
尽管 Redis 的核心操作是单线程的,但在 Redis 6.0 及以后的版本中,引入了 多线程 IO 特性,用于优化网络 IO 的性能。
多线程 IO 模型
-
背景:在高并发环境下,网络数据的读写会占用 Redis 主线程的部分时间,导致处理请求的效率下降。
-
实现方式:Redis 在接收客户端的请求时,使用多线程并行地读取网络数据,将请求数据读入内存缓冲区。
-
工作流程:
-
主线程:负责接受新的客户端连接,管理客户端状态,以及执行具体的命令操作。
-
IO 线程:在读取阶段,多个 IO 线程并行地从已就绪的客户端连接中读取请求数据。在回复阶段,IO 线程也可以并行地将响应数据写回给客户端。
-
注意事项
-
线程安全:Redis 确保在多线程模型下的数据安全性,IO 线程仅负责数据的读写,不涉及对数据的修改操作。
-
性能提升:在网络带宽高、CPU 多核的环境下,启用多线程 IO 可以显著提升 Redis 的吞吐量。
Redis 的事件循环机制
Redis 的单线程通过 事件循环 来管理所有的事件,包括网络事件和定时任务。事件循环主要包括以下部分:
-
文件事件处理器:基于 Reactor 模式,使用 IO 多路复用机制监听套接字事件,将就绪的事件放入队列中处理。
-
时间事件处理器:处理定时任务,如键的过期检查、异步任务等。
-
事件调度器:循环地从事件队列中取出事件,调用相应的事件处理器。
总结
-
单线程核心:Redis 的核心操作(如命令执行)依然是单线程的,这使得 Redis 在处理数据时避免了锁的竞争,保证了操作的原子性。
-
多线程 IO 优化:从 Redis 6.0 开始,引入了多线程 IO,以优化网络数据的读写,提高高并发环境下的性能。
-
适用场景:对于多数使用场景,默认的单线程模型已经足够高效。只有在网络 IO 成为瓶颈时,才需要考虑启用多线程 IO。
-
感谢你看到最后,最后再说两点~
①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。
②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~感兴趣的可以关注公众号一起学习,我会不定期发布学习和一些有意思的见闻。