Mr Dk.'s BlogMr Dk.'s Blog
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • ⛸️ Redis Implementation
    • Part 1 - 数据结构与对象

      • Chapter 2 - 简单动态字符串
      • Chapter 3 - 链表
      • Chapter 4 - 字典
      • Chapter 5 - 跳跃表
      • Chapter 6 - 整数集合
      • Chapter 7 - 压缩列表
      • Chapter 8 - 对象
    • Part 2 - 单机数据库的实现

      • Chapter 9 - 数据库
      • Chapter 10 - RDB 持久化
      • Chapter 11 - AOF 持久化
      • Chapter 12 - 事件
      • Chapter 13 - 客户端
      • Chapter 14 - 服务器
    • Part 3 - 多机数据库的实现

      • Chapter 15 - 复制
      • Chapter 16 - Sentinel
      • Chapter 17 - 集群
    • Part 4 - 独立功能的实现

      • Chapter 18 - 发布与订阅
      • Chapter 19 - 事务
      • Chapter 21 - 排序
      • Chapter 22 - 二进制位数组
      • Chapter 23 - 慢查询日志

Chapter 12 - 事件

Created by : Mr Dk.

2020 / 06 / 05 16:17

Nanjing, Jiangsu, China


Redis 服务器是事件驱动的,主要处理两类事件:

  • 文件事件 (file event) - 服务器对 socket 的抽象
  • 时间事件 (time event)

File Event

Redis 通过 I/O 多路复用 来监听多个 socket,当得到 socket 的命令时,与 socket 关联的 handler 就会被调用。由于 Redis 由单进程的方式被实现,所以 I/O 多路复用程序还是会将所有的 socket 放到一个队列中,然后通过这个队列有序、同步地依次处理事件。每个 handler 中定义了对应事件发生时服务器应该执行的动作:

  • accept
  • read
  • write
  • close

I/O 多路复用程序的底层有:

  • select
  • epoll
  • evport
  • kqueue

Redis 在编译时会自动选择系统中性能最佳的多路复用库。

Handler 的具体类型:

  • 连接应答处理器 - 封装了 accept() 函数,对 socket 进行应答
  • 命令请求处理器 - 封装了 read(),从客户端读入命令请求
  • 命令回复处理器 - 封装了 write(),将命令回复发送给客户端

Time Event

Redis 将所有的时间事件都放在一个无序链表中。每当时间事件执行器运行时,就遍历整个链表,对每个已超时的事件调用 handler。

Redis 中的 serverCron() 函数就是时间事件的例子。在这个事件的 handler 中有如下工作:

  • 更新服务器的统计信息
  • 清理过期的 key
  • 关闭和清理连接失效的客户端
  • AOF/RDB 持久化
  • 如果服务器是主服务器,则对从服务器进行定期同步
  • 如果处于集群模式,则对集群进行定期同步和连接测试

这个函数默认每秒运行 10 次,也可以通过配置文件进行调整。


Scheduler

在 Redis 主进程的主循环中,首先计算最近的时间事件还有多久发生。然后在最近的时间事件发生之前,阻塞等待文件事件 (因为文件事件是随机发生的),最久阻塞到下一个时间事件发生前。然后先处理文件事件 (本轮循环中可能没有),再处理时间事件 (本轮循环中也可能没有);最终重新循环。

对事件的处理都是同步、有序、原子地进行的,不存在中断与抢占。因此 handler 应当尽可能减少阻塞时间,并在有必要时让出 CPU:

  • 比如,对 socket 进行 write() 时,写够一定的字节数后,余下的字节下次再写
  • 将持久化操作放到子线程或子进程中

这里的原则与 Vert.x 类似,不要阻塞 event loop。

Edit this page on GitHub
Prev
Chapter 11 - AOF 持久化
Next
Chapter 13 - 客户端