赞
踩
Redis是一个高性能、开源、内存键值存储数据库,同时也支持丰富的数据结构。它由 Salvatore Sanfilippo(又名 antirez)创建并在2009年开始公开发布。Redis以其优异的性能、灵活的数据模型和广泛的适用性而著称,已经成为现代应用程序开发中不可或缺的组件之一。以下是Redis的详细介绍:
Redis 数据持久化是指将内存中的数据保存到硬盘中,以防止服务重启或系统崩溃时数据丢失。Redis 提供了两种主要的数据持久化机制:
从 Redis 4.0 版本开始,还支持将 RDB 和 AOF 结合使用。在这种模式下,重启 Redis 时首先加载 RDB 文件快速恢复大部分数据,然后重放 AOF 文件中记录的增量命令,从而既提高了恢复速度,又降低了数据丢失的风险。
这些数据结构使得Redis能够灵活应对各种数据存储和处理的需求,无论是简单的数据缓存,还是复杂的消息队列和分布式系统,Redis都能提供高效、可靠的支持。
Redis的线程模型主要是基于Reactor模式开发的网络事件处理器,这个处理器被称为文件事件处理器(file event handler)。它是单线程的,所以Redis也被称为单线程模型。虽然从严格意义上讲,Redis的其他模块也会用到多个线程,但在网络请求模块,Redis确实使用了单个线程来处理所有的网络请求。
文件事件处理器使用IO多路复用(multiplexing)程序来同时监听多个套接字(socket),并根据套接字当前执行的任务来为套接字关联不同的事件处理器。当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
这种模型使得Redis能够高效地处理大量的网络请求,避免了线程切换和竞态产生的消耗,也避免了不必要的上下文切换和竞争条件,从而实现了高性能的网络通信。同时,由于Redis内部线程模型的简单性,它也更容易进行扩展和维护。
需要注意的是,虽然Redis的网络请求处理是单线程的,但在执行命令时,Redis仍然可以利用多核CPU资源,因为Redis会将命令的执行计划拆分给多个工作线程去执行。
此外,由于多个客户端发送的命令的执行顺序是不确定的,因此在使用Redis时,需要注意避免一些可能导致数据不一致的操作。
Redis的网络模型主要基于IO多路复用和事件派发机制。这种模型使得Redis能够高效地处理大量的网络请求,实现高性能的网络通信。
在Redis的网络模型中,服务端会创建一个ServerSocket,并将其文件描述符(fd)注册到事件循环实例上。同时,会为这个事件绑定一个连接应答处理器,用于处理客户端的连接请求。当客户端连接上来时,会产生一个事件,IO多路复用程序监听到ServerSocket上有事件就绪,就会调用连接应答处理器,和客户端建立连接。
建立连接后,Redis会为客户端创建对应的socket,获取socket的读事件,并为其绑定命令请求处理器。这样,当客户端向主服务器发送命令请求时,Redis就能够通过读事件和命令请求处理器来接收并处理这些请求。
整个过程中,Redis使用单线程模型来处理网络请求,避免了线程切换和竞态产生的消耗。同时,由于Redis内部线程模型的简单性,它也更容易进行扩展和维护。
总的来说,Redis的网络模型是一个高效、可靠且易于扩展的模型,能够支持大量的并发连接和请求处理,使得Redis在各种应用场景中都能表现出色。
命令队列:
MULTI
命令开启一个事务,此后客户端发送的所有命令都不会立即执行,而是被放入一个队列中待处理。原子性:
EXEC
命令触发),它们会按照先进先出(FIFO)顺序执行完毕,即使其中某个命令执行失败,后续命令仍然会尝试执行,这就是所谓的“部分原子性”。监控与检查:
WATCH
命令可以监控一个或多个 key,当 EXEC
执行前,如果被监控的 key 被其他客户端修改,那么整个事务将会被中止,EXEC
返回 null
表示事务未执行。这是 Redis 实现的一种乐观锁机制,用于在执行事务前检测 key 是否被并发修改。事务控制:
DISCARD
命令可以取消当前事务,清除事务队列,放弃执行事务中的所有命令。UNWATCH
命令取消之前使用 WATCH
设置的所有 key 监控。执行:
EXEC
命令提交并执行事务队列中的所有命令。如果在 EXEC
之前执行了 DISCARD
或者被 WATCH
的 key 发生改变,EXEC
不会执行任何命令。由于 Redis 是单线程模型,事务中的命令在执行时彼此间不会互相影响,但并不保证事务内部命令间的原子性,即不能保证事务中的多个命令作为一个整体被原子地执行或回滚。此外,Redis 的事务不存在隔离级别,同一时间内只有一个事务在执行,但不同客户端之间的事务执行是无序的。这意味着在一个事务执行过程中,其他客户端的命令请求只能等待事务结束后才能得到服务。
复制:
Redis 复制(Replication)是一种在多个 Redis 实例之间同步数据的技术,旨在提供数据冗余、读写分离、灾难恢复等能力。Redis 的复制分为主从复制(Master-Slave Replication)和通过哨兵(Sentinel)实现的自动故障转移。
从节点(Slave):
SYNC
或 PSYNC
命令来启动复制过程。复制优势:
Redis Sentinel 是一个分布式系统,用于监控 Redis 主从集群,当主节点出现故障时,Sentinel 系统能够自动完成故障发现和故障转移,并通知客户端新的主节点地址,从而实现了自动化的高可用性。
通过哨兵模式,Redis 的复制得以升级,能够更好地应对主节点故障的情况,确保服务的持续可用性。同时,Sentinel 还提供了监控、通知以及主从角色切换等功能。
Redis 分布式通常指的是 Redis 集群(Redis Cluster),这是一种原生的 Redis 分布式解决方案,允许在多个节点上划分数据并共同提供服务,以达到水平扩展的目的,从而提高系统整体的读写能力和容错性。
Redis 集群的主要特点包括:
数据分片(Sharding):
节点通信与数据迁移:
客户端透明路由:
高可用性:
写操作的限制:
通过 Redis 集群,开发者可以构建大规模、高可用的分布式缓存和存储系统,适用于大数据量、高并发的场景,同时保持Redis本身高性能的特性。
原子性:
Redis 执行 Lua 脚本时会保证整个脚本的执行是原子性的,也就是说,在执行脚本期间,不会有其他客户端的命令插入执行,从而避免了因并发操作可能导致的数据不一致问题。
性能:
由于 Lua 脚本在 Redis 服务器端执行,减少了客户端与服务器之间的网络往返延迟,提高了整体性能。同时,Lua 解释器本身小巧且高效,特别适合于嵌入式脚本环境。
复用性:
Lua 脚本可以被 Redis 缓存并重复使用,从而节省网络带宽和计算资源。通过 SCRIPT LOAD
命令可以将脚本加载到 Redis 中,之后使用 EVALSHA
命令通过脚本的 SHA1 校验和来执行缓存的脚本。
功能扩展:
Lua 脚本能处理复杂逻辑,例如条件判断、循环、数据处理等,还可以调用 Redis 命令。Redis 提供了 redis.call()
和 redis.pcall()
两个函数,分别用于执行Redis命令并返回结果(前者在遇到错误时会停止脚本执行,后者则捕获错误并返回错误信息)。
使用实例:
命令相关:
EVAL
和 EVALSHA
命令用于执行 Lua 脚本。
SCRIPT LOAD
命令用于加载脚本而不执行。
SCRIPT EXISTS
检查脚本是否已经被加载过。
SCRIPT FLUSH
清除所有已加载的脚本。
SCRIPT KILL
终止当前正在执行的长时间运行的脚本。
Lua 脚本在 Redis 中的应用极大地丰富了 Redis 的功能,特别是在需要执行多条命令组合且需要保持原子性的情景下,是非常理想的解决方案。
Redis 的 LRU(Least Recently Used,最近最少使用)回收策略是一种内存管理策略,用于在内存不足以容纳所有数据时,自动选择并删除最近最少使用的数据,以便腾出空间存储新数据。然而,Redis 实现的 LRU 并非完全意义上的 LRU 算法,因为它并未真正记录所有键的使用时间顺序,而是采用了近似 LRU 的方法。
在 Redis 早期版本中,实现了一种随机采样的 LRU 替代算法。Redis 会在每个键上维护一个额外的字段(称为 LFU 利用次数或 LRU 时间标记),并且使用一个循环双向链表来按 LRU 近似原则组织数据。当需要释放内存时,Redis 会选择链表尾部的键进行淘汰,假设这部分键是最久未使用的。
随着 Redis 的发展,尤其是从 Redis 4.0 开始,提供了两种更加精细化的 LRU 算法实现:
volatile-lru:
仅针对带有过期时间(TTL)的键采用 LRU 策略,也就是说,当内存达到最大限制时,优先从即将过期的键中淘汰最近最少使用的。
allkeys-lru:
对所有键(无论是否设置过期时间)都采用 LRU 策略,当内存满时,同样会基于最近最少使用的标准淘汰数据。
这两种策略都是通过采样和概率估算的方式来近似实现 LRU,而非真正的 O(1) 查找时间复杂度的 LRU 算法。Redis 通过维护一个小样本集合,跟踪最近一段时间内哪些键被访问过,以此来决定哪些键可能是最近最少使用的。
另外,Redis 还引入了 LFU(Least Frequently Used,最近最不常用)策略,它是基于访问频率而不是访问时间来决定淘汰数据的优先级。volatile-lfu 和 allkeys-lfu 类似于 volatile-lru 和 allkeys-lru,区别在于它们是基于访问频率来淘汰数据。
总之,Redis凭借其高性能、易用性以及强大的数据处理能力,成为了一个高度可扩展的解决方案,适用于多种互联网业务场景。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。