导航
功能
- 分布式锁:通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁。
- 限流:一般是通过 Redis + Lua 脚本的方式来实现限流。
- 消息队列:Redis 自带的 list 数据结构可以作为一个简单的队列使用。Redis5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。它比较类似于 Kafka,有主题和消费组的概念,支持消息持久化以及 ACK 机制。
- 复杂业务场景:通过 Redis 以及 Redis 扩展(比如 Redisson)提供的数据结构,我们可以很方便地完成很多复杂的业务场景比如通过 bitmap 统计活跃用户、通过 sorted set 维护排行榜
多路 io 复用
Redis 基于 Reactor 模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器(file event handler)。文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
虽然文件事件处理器以单线程方式运行,但通过使用 I/O 多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接,这保持了 Redis 内部单线程设计的简单性。
可以看出,文件事件处理器(file event handler)主要是包含 4 个部分:
- 多个 socket(客户端连接)
- IO 多路复用程序(支持多个客户端连接的关键)
- 文件事件分派器(将 socket 关联到相应的事件处理器)
事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
select
- 修改入参数组
- 最大监听 1024
- 需要轮询返回数据的 socket
- 线程不安全
- 文件描述符被另一个线程关闭的话,结果不唯一
- poll
- 去掉 1024 的限制(链表)
- 不修改入参数组
- 线程不安全
- epoll
- 可确定那个 socket 有数据
- 线程安全
单线程与多线程
- 4.0 后增加了对多线程的支持
- 主要是针对一些大键值对的删除操作的命令,使用这些命令就会使用主处理之外的其他线程来“异步处理”。
- 6.0 之后为何引入了多线程
- 主要是为了提高网络 IO 读写性能
- 只是在网络数据的读写这类耗时操作上使用了,执行命令仍然是单线程顺序执行。
- 默认是禁用的,只使用主线程。如需开启需要修改 redis 配置文件
redis.conf
- 开启多线程后,还需要设置线程数,否则是不生效的。同样需要修改 redis 配置文件
redis.conf
:
事务
- 隔离性:redis 是单进程的程序,保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。所以 redis 的事务支持隔离性。
- redis 会将一个事务中的所有命令序列化,然后按顺序执行。redis 不可能在一个事务的执行过程中插入执行另一个客户端发出的请求。可以保证 Redis 将这些命令作为一个单独的隔离操作执行。
- 不支持回滚
aof
- 若开启了 aof 持久化,启动时优先 aof 还原数据
- 过程
- append 命令追加:完成写命令,按格式追加至 aof_buf 缓冲区的末尾
- append 追加后,调用 flushAppendOnluFile 函数确定是否写入文件
- 策略:appendfsync 配置
- always:每次追加到 aof 文件时都 fsync 到磁盘
- everysec:默认
- no:何时 fsync 由 os 决定
AOF 重写缓存区:
- redis 是单线程工作,当 AOF 文件较大时重写时间会比较长,在重写 AOF 期间,redis 将长时间无法处理客户端请求。为了解决这个问题,可以将 AOF 重写程序放到子进程中执行,好处如下:
- 子进程进行 AOF 重写期间,服务器进程(父进程)可以继续处理其它客户端请求。
- 子进程带有父进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性。
- 子进程中 AOF 重写导致的问题:
- 子进程在进行 AOF 重写期间,服务器进程依然可以处理其它客户端请求,这就会导致数据库状态已经发生了改变,使得当前数据库数据状态和重写后的 AOF 文件中的数据不一致。
- 也就是出现了 AOF 文件和数据库中数据不一致的问题。
- 数据状态不一致解决办法:
- redis 服务器设置了一个 AOF 重写缓冲区。这个缓冲区在创建子进程后开始使用,当 redis 服务器执行一个客户端的写请求命令,之后将这个写命令也发送到 AOF 重写缓冲区(同时将命令追加到 AOF 缓冲区和 AOF 重写缓冲区)
- 当子进程完成 AOF 日志重写之后,给父进程发送信号,父进程接收此信号后,将 AOF 重写缓冲区的内容写到新的 AOF 文件中,保持数据的一致性。
- 改名覆盖
过期回收
1 | Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。 |
- 定期:每隔一段时间抽取一批 key 执行删除过期 key 操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。
- 惰性