写点什么

大数据 -48 Redis 深入理解 Redis 通信机制:从 RESP 协议到 Reactor 事件驱动模型

作者:武子康
  • 2025-07-22
    美国
  • 本文字数:4809 字

    阅读完需:约 16 分钟

大数据-48 Redis 深入理解Redis通信机制:从RESP协议到Reactor事件驱动模型

点一下关注吧!!!非常感谢!!持续更新!!!

🚀 AI 篇持续更新中!(长期更新)

AI 炼丹日志-30-新发布【1T 万亿】参数量大模型!Kimi‑K2 开源大模型解读与实践,持续打造实用 AI 工具指南!📐🤖

💻 Java 篇正式开启!(300 篇)

目前 2025 年 07 月 21 日更新到:Java-77 深入浅出 RPC Dubbo 负载均衡全解析:策略、配置与自定义实现实战 MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务正在更新!深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300 篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解


Redis 采用单线程+多路复用架构,通过事件驱动实现高并发处理。通信基于 RESP 协议,定义了简单字符串、错误、整数、批量字符串和数组五种数据格式,具有可读性强、易解析、支持二进制等优点。通信默认使用 TCP 长连接,支持串行和双工模式,其中 Pipeline 机制可显著提升吞吐量。Redis 内部使用 Reactor 模式处理 IO 事件,通过 aeEventLoop 统一管理网络事件和时间事件,底层利用 epoll 或 kqueue 实现高效的 IO 多路复用,避免多线程带来的锁竞争和上下文切换开销。整体设计简单高效,是其高性能关键所在。


章节内容

上节我们完成了:


  • Redis 的缓存机制

  • Redis 的淘汰策略

  • LRU LFU 等机制


通信协议

Redis 的单线程模型

Redis 采用单进程+单线程的架构设计,这种设计有以下特点:


  1. 所有操作都是原子性执行的,避免了多线程环境下的锁竞争问题

  2. 通过 I/O 多路复用技术处理大量并发连接

  3. 单线程简化了数据结构的实现,提高了性能

Redis 协议(RESP)

Redis Serialization Protocol (RESP)是应用系统与 Redis 服务端交互的通信协议,主要特点包括:

协议格式

RESP 定义了 5 种数据类型:


  1. 简单字符串(Simple Strings):以"+"开头,如 "+OK\r\n"

  2. 错误(Errors):以"-"开头,如 "-ERR unknown command\r\n"

  3. 整数(Integers):以":"开头,如 ":1000\r\n"

  4. 批量字符串(Bulk Strings):以"6\r\nfoobar\r\n"

  5. 数组(Arrays):以"*"开头,如 "*2\r\n3\r\nfoo\r\n3\r\nbar\r\n"

通信示例

客户端发送命令:


*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n
复制代码


服务端响应:


+OK\r\n
复制代码

应用场景

  1. 客户端库实现:各种语言的 Redis 客户端库都需要实现 RESP 协议

  2. 命令行交互:redis-cli 工具通过 RESP 与服务器通信

  3. 主从复制:Redis 集群中的主从节点通过 RESP 协议同步数据

协议优势

  1. 简单易实现

  2. 人类可读

  3. 高效解析

  4. 支持二进制安全的数据传输

响应模式

概念介绍

Redis 协议位于 TCP 层上,即客户端和 Redis 实例保持双工的连接。


串行模式

串行模式是一种最基本的客户端-服务器通信方式,其工作流程如下:


  1. 连接建立阶段

  2. 客户端与服务端通过 TCP/IP 协议建立持久的长连接

  3. 连接建立后,双方通过心跳机制(ping-pong)保持连接活性

  4. 典型的心跳间隔通常为 30-60 秒,通过 ACK 应答确认连接状态

  5. 请求-响应流程

  6. 客户端发送第一个请求报文

  7. 服务端处理该请求并返回响应

  8. 客户端必须完整接收到第一个响应后,才能发起第二个请求

  9. 每个请求都需要等待前一个请求完成才能继续

  10. 典型应用场景

  11. Telnet 协议:用于远程终端连接的标准协议

  12. Redis-cli 工具:Redis 数据库的默认命令行接口

  13. 简单的 RPC 调用场景

  14. 性能特点

  15. 网络延迟显著影响总吞吐量(RTT 时间累加)

  16. 无法充分利用网络带宽(存在大量空闲等待时间)

  17. 服务端资源利用率低(处理请求时存在等待间隔)

  18. 实现简单,无需考虑请求乱序问题

  19. 改进方向

  20. 引入管道化(Pipeline)技术

  21. 采用多路复用(Multiplexing)方案

  22. 实现并行请求处理


这种模式虽然简单可靠,但因其串行处理的特性,在现代高并发场景中通常不是最优选择。


双工模式

双工模式是指通信双方可以同时进行双向数据传输的工作方式。在计算机网络中,TCP 协议就是一种典型的全双工通信协议。

批量请求与批量响应

在双工模式下,系统支持:


  1. 客户端可以一次性发送多个请求

  2. 服务器可以一次性返回多个响应

  3. 请求和响应可以交叉进行而不会混淆(得益于 TCP 的双工特性)

Pipline 技术详解

Pipline(管道)是一种优化网络通信性能的重要技术:


工作原理:


  1. 客户端将多个命令打包成一个批次

  2. 通过单个网络调用发送给服务器

  3. 服务器按顺序执行这些命令

  4. 将执行结果按顺序打包后返回


性能优势:


  • 减少网络往返时间(RTT)

  • 提高吞吐量

  • 降低网络延迟影响


技术特点:


  • 一次 pipline 操作包含:

  • 多条命令的批量发送

  • 仅需一次网络传输时间

  • 命令执行结果的批量返回


应用场景:


  1. 数据库批量操作

  2. 消息队列的批量生产/消费

  3. 缓存系统的批量读取/写入


示例:在 Redis 中,使用 pipline 可以显著提高批量操作的效率:


# 不使用piplinefor i in 1..100  redis.set("key#{i}", "value#{i}")end
# 使用piplineredis.pipelined do 100.times do |i| redis.set("key#{i}", "value#{i}") endend
复制代码


后者只需一次网络往返即可完成 100 次 set 操作。


我们使用 Jedis 库可以很轻松的使用 pipline:


Jedis redis = new Jedis("h121.wzk.icu", 6379);redis.auth("111111");Pipeline pipe = jedis.pipelined();for (int i = 0; i <50000; i++) {    pipe.set("key_"+String.valueOf(i),String.valueOf(i));}// 将封装后一次性发给redispipe.sync();
复制代码

Redis 通信协议详解

RESP 协议概述

Redis 客户端与服务器之间的交互采用 REdis Serialization Protocol(RESP)序列化协议。这是一种简单高效的二进制安全协议,专为 Redis 设计,具有以下特点:

请求格式

请求以字符串数组的形式表示要执行的命令及其参数:


*<参数数量>\r\n$<参数1长度>\r\n<参数1数据>\r\n$<参数2长度>\r\n<参数2数据>\r\n...
复制代码

响应格式

Redis 使用以下特有数据类型作为回复:


  1. 简单字符串(Simple Strings):以"+"开头

  2. 错误(Errors):以"-"开头

  3. 整数(Integers):以":"开头

  4. 批量字符串(Bulk Strings):以"$"开头

  5. 数组(Arrays):以"*"开头

通信机制

连接方式

  • 采用 TCP 协议建立连接

  • 默认服务端口号:6379(可以通过配置修改)

  • 支持 TLS 加密连接(需配置)

数据分隔

  • 每条命令和数据都必须以 CRLF(\r\n)结尾

  • 示例:SET key value命令实际传输为*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n

二进制安全特性

  • 所有参数都是二进制安全的,可以包含任意字节

  • 支持处理包含 null 字节(\x00)的数据

  • 字符串长度按字节计算而非字符

典型交互示例

命令发送示例

发送GET counter命令:


   *2\r\n   $3\r\n   GET\r\n   $7\r\n   counter\r\n
复制代码


发送SET message "Hello World"命令:


   *3\r\n   $3\r\n   SET\r\n   $7\r\n   message\r\n   $11\r\n   Hello World\r\n
复制代码

响应示例

成功响应:


   +OK\r\n
复制代码


  1. 错误响应:


   -ERR unknown command 'FOO'\r\n
复制代码


  1. 整数响应:


   :100\r\n
复制代码


  1. 批量字符串响应:


   $11\r\n   Hello World\r\n
复制代码

性能优化

  • 管道机制(pipelining):允许一次性发送多个命令而不需要等待每个回复

  • 连接复用:保持长连接减少 TCP 握手开销

  • 批量操作命令:如 MSET、MGET 等减少网络往返次数

内联格式

可以使用 telnet 工具进行测试,发送一些内容过去


telnet h121.wzk.icu 6379
xxxxxxxxx
复制代码

处理流程

处理流程


  • 服务器启动监听

  • 接受命令请求并解析

  • 执行命令请求

  • 返回命令回复


具体的过程图可以看下边的流程图片:


处理机制

Redis 服务器是典型的事件驱动系统,Redis 将事件分为两大类:


  • 文件事件

  • 时间事件

文件事件

文件事件即 Socket 读写事件,也就是 IO 事件,比如客户端连接、命令请求、数据回复、连接断开等等。

Reactor 模式详解

Redis 中的 Reactor 模式实现

Redis 采用单线程的 Reactor 模式作为其核心事件处理机制,这种设计使其能够在单个线程中高效处理大量并发连接。Reactor 模式属于 I/O 多路复用技术的一种典型实现方式,特别适合高并发、低延迟的场景。

I/O 多路复用基础

I/O 多路复用(Input/Output Multiplexing)是指使用单个线程管理多个 Socket 连接的技术。通过系统调用(如 select、poll、epoll 或 kqueue)监视多个文件描述符的状态变化,当某个 Socket 就绪时,应用程序就能立即得到通知并进行处理,而不需要为每个连接创建独立线程。

Reactor 模式核心组件

  1. 事件驱动架构

  2. 整个系统围绕事件进行组织

  3. 事件包括:连接建立、数据到达、超时等

  4. 事件触发相应的处理逻辑

  5. 输入源(Event Sources)

  6. 一个或多个并发输入源(如网络 Socket)

  7. 可以是客户端连接、定时器事件等

  8. Redis 中主要包括网络 I/O 事件和时间事件

  9. 服务处理器(ServiceHandler)

  10. 也称为 Dispatcher 或 Event Demultiplexer

  11. 负责监听和收集所有事件源产生的事件

  12. 在 Redis 中由 aeEventLoop 实现

  13. 请求处理器(RequestHandlers)

  14. 多个具体的事件处理器

  15. 每个处理器负责处理特定类型的事件

  16. Redis 中包括:连接处理器、命令处理器等

工作流程

  1. 事件注册

  2. 各种事件源向 ServiceHandler 注册感兴趣的事件

  3. 例如:注册 Socket 的可读事件

  4. 事件循环

  5. ServiceHandler 通过 I/O 多路复用 API(如 epoll)等待事件

  6. 当事件发生时,ServiceHandler 被唤醒

  7. 事件分发

  8. ServiceHandler 同步地将事件分发给对应的 RequestHandler

  9. 分发过程通常是通过回调机制实现的

  10. 事件处理

  11. RequestHandler 执行具体的业务逻辑

  12. 在 Redis 中,这包括解析命令、执行命令、返回响应等

Redis 中的具体实现

在 Redis 源码中,Reactor 模式的主要实现包括:


  • aeEventLoop:事件循环的核心结构体

  • aeApiPoll:封装底层 I/O 多路复用 API

  • aeCreateFileEvent:注册文件事件

  • aeCreateTimeEvent:注册时间事件


Redis 的事件处理流程示例:


  1. 客户端连接到 Redis 服务器的连接请求到达

  2. aeEventLoop 通过 epoll 检测到新的连接事件

  3. 调用 acceptTcpHandler 处理新连接

  4. 当客户端发送命令数据时,触发读事件

  5. 调用 readQueryFromClient 处理命令请求

优势与局限

优势


  • 单线程避免了多线程的上下文切换开销

  • 通过事件驱动实现高并发处理

  • 逻辑简单,避免多线程同步的复杂性


局限


  • 受限于单线程,无法充分利用多核 CPU

  • 长时间运行的命令会阻塞整个事件循环

  • 大键操作可能影响响应时间


Redis 通过以下方式弥补局限:


  • 对耗时操作(如持久化)使用子进程

  • 6.0+版本支持 I/O 多线程(但仍保持单线程命令处理)

Reactor 图

下面这些图片可以让你更好地理解 Reactor 模式:



多路复用

IO 多路复用机制就是通过一种机制,一个进程可以监视多个描述符(Socket),一旦某个描述符就绪,能够通知程序进行相应的复写操作。IO 多路复用机制有这么几种:


  • select

  • poll

  • epoll

  • kqueue

Select

select 函数监视的文件描述符分 3 类:


  • writefds

  • readfds

  • exceptfds


调用后 select 函数会阻塞,直到有描述符就绪或者超时,函数返回。当 select 函数返回后,可以通过 fd 列表遍历,来找到就绪的描述符。

Select 优点

几乎在所有平台上都有支持,跨平台支持。

Select 缺点

单个进程打开文件描述有一定的限制,有 FD_SETSIZE 设置,默认是 1024 ,采用数组存储,另外在检查数组中是否有文件描述符需要读写时,采用的是线性的扫描(不管是否活跃都扫描轮询),效率较低。

Poll

poll 使用一个 pollfd 的指针实现,pollfd 结构包含了要监视的 Event 和 发生的 Event,不再使用 select 的参数值传递的方式。

Poll 优点

采用链表的形式存储,它监听的描述符数量没有限制,可以超过 select 默认限制的 1024 大小

Poll 缺点

另外在检查链表中是否有文件描述符需要读写时,采用线性扫描的方法,即不管 Socket 是不是活跃的,都轮询一次,效率较低。

epoll

epoll 子啊 Linux2.6 内核中提出的,是之前 select 和 poll 的加强版本。相对于 select 和 poll 来说,epoll 更加灵活,没有描述符限制。


epoll 使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的 copy 就只需要一次。

epoll 优点

epoll 没有最大并发连接限制,上限是最大能打开文件的数目,比如 1GB 内存大约能打开 10 万文件左右。epoll 最大的优点就在于只处理活跃的连接,而不需要轮询遍历,所以效率很高。

kqueue

kqueue 是 unix 下的一个 IO 多路复用库。最初是 2000 年在 FreeBSD 系统上开发的一个高性能的事件的事件通知接口。注册一批 Socket 描述符 kqueue 后,当其中描述符状态发生改变时,kqueue 将一次性通知应用程序哪些描述符可读可写或出错。

kqueue 优点

能处理大量数据,性能较高。

发布于: 刚刚阅读数: 4
用户头像

武子康

关注

永远好奇 无限进步 2019-04-14 加入

Hi, I'm Zikang,好奇心驱动的探索者 | INTJ / INFJ 我热爱探索一切值得深究的事物。对技术、成长、效率、认知、人生有着持续的好奇心和行动力。 坚信「飞轮效应」,相信每一次微小的积累,终将带来深远的改变。

评论

发布
暂无评论
大数据-48 Redis 深入理解Redis通信机制:从RESP协议到Reactor事件驱动模型_Java_武子康_InfoQ写作社区