点一下关注吧!!!非常感谢!!持续更新!!!
🚀 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采用单进程+单线程的架构设计,这种设计有以下特点:
- 所有操作都是原子性执行的,避免了多线程环境下的锁竞争问题
- 通过I/O多路复用技术处理大量并发连接
- 单线程简化了数据结构的实现,提高了性能
Redis协议(RESP)
Redis Serialization Protocol (RESP)是应用系统与Redis服务端交互的通信协议,主要特点包括:
协议格式
RESP定义了5种数据类型:
- 简单字符串(Simple Strings):以"+"开头,如 "+OK\r\n"
- 错误(Errors):以"-"开头,如 "-ERR unknown command\r\n"
- 整数(Integers):以":"开头,如 ":1000\r\n"
- 批量字符串(Bulk Strings):以"6\r\nfoobar\r\n"
- 数组(Arrays):以"*"开头,如 "*2\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
应用场景
- 客户端库实现:各种语言的Redis客户端库都需要实现RESP协议
- 命令行交互:redis-cli工具通过RESP与服务器通信
- 主从复制:Redis集群中的主从节点通过RESP协议同步数据
协议优势
- 简单易实现
- 人类可读
- 高效解析
- 支持二进制安全的数据传输
响应模式
概念介绍
Redis 协议位于 TCP 层上,即客户端和Redis实例保持双工的连接。
串行模式
串行模式是一种最基本的客户端-服务器通信方式,其工作流程如下:
-
连接建立阶段:
- 客户端与服务端通过TCP/IP协议建立持久的长连接
- 连接建立后,双方通过心跳机制(ping-pong)保持连接活性
- 典型的心跳间隔通常为30-60秒,通过ACK应答确认连接状态
-
请求-响应流程:
- 客户端发送第一个请求报文
- 服务端处理该请求并返回响应
- 客户端必须完整接收到第一个响应后,才能发起第二个请求
- 每个请求都需要等待前一个请求完成才能继续
-
典型应用场景:
- Telnet协议:用于远程终端连接的标准协议
- Redis-cli工具:Redis数据库的默认命令行接口
- 简单的RPC调用场景
-
性能特点:
- 网络延迟显著影响总吞吐量(RTT时间累加)
- 无法充分利用网络带宽(存在大量空闲等待时间)
- 服务端资源利用率低(处理请求时存在等待间隔)
- 实现简单,无需考虑请求乱序问题
-
改进方向:
- 引入管道化(Pipeline)技术
- 采用多路复用(Multiplexing)方案
- 实现并行请求处理
这种模式虽然简单可靠,但因其串行处理的特性,在现代高并发场景中通常不是最优选择。
双工模式
双工模式是指通信双方可以同时进行双向数据传输的工作方式。在计算机网络中,TCP协议就是一种典型的全双工通信协议。
批量请求与批量响应
在双工模式下,系统支持:
- 客户端可以一次性发送多个请求
- 服务器可以一次性返回多个响应
- 请求和响应可以交叉进行而不会混淆(得益于TCP的双工特性)
Pipline技术详解
Pipline(管道)是一种优化网络通信性能的重要技术:
工作原理:
- 客户端将多个命令打包成一个批次
- 通过单个网络调用发送给服务器
- 服务器按顺序执行这些命令
- 将执行结果按顺序打包后返回
性能优势:
- 减少网络往返时间(RTT)
- 提高吞吐量
- 降低网络延迟影响
技术特点:
- 一次pipline操作包含:
- 多条命令的批量发送
- 仅需一次网络传输时间
- 命令执行结果的批量返回
应用场景:
- 数据库批量操作
- 消息队列的批量生产/消费
- 缓存系统的批量读取/写入
示例: 在Redis中,使用pipline可以显著提高批量操作的效率:
# 不使用pipline
for i in 1..100
redis.set("key#{i}", "value#{i}")
end
# 使用pipline
redis.pipelined do
100.times do |i|
redis.set("key#{i}", "value#{i}")
end
end
后者只需一次网络往返即可完成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));
}
// 将封装后一次性发给redis
pipe.sync();
Redis通信协议详解
RESP协议概述
Redis客户端与服务器之间的交互采用REdis Serialization Protocol(RESP)序列化协议。这是一种简单高效的二进制安全协议,专为Redis设计,具有以下特点:
请求格式
请求以字符串数组的形式表示要执行的命令及其参数:
*<参数数量>\r\n$<参数1长度>\r\n<参数1数据>\r\n$<参数2长度>\r\n<参数2数据>\r\n...
响应格式
Redis使用以下特有数据类型作为回复:
- 简单字符串(Simple Strings):以"+"开头
- 错误(Errors):以"-"开头
- 整数(Integers):以":"开头
- 批量字符串(Bulk Strings):以"$"开头
- 数组(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
- 错误响应:
-ERR unknown command 'FOO'\r\n
- 整数响应:
:100\r\n
- 批量字符串响应:
$11\r\n
Hello World\r\n
性能优化
- 管道机制(pipelining):允许一次性发送多个命令而不需要等待每个回复
- 连接复用:保持长连接减少TCP握手开销
- 批量操作命令:如MSET、MGET等减少网络往返次数
内联格式
可以使用 telnet 工具进行测试,发送一些内容过去
telnet h121.wzk.icu 6379
xxx
xxx
xxx
处理流程
处理流程
- 服务器启动监听
- 接受命令请求并解析
- 执行命令请求
- 返回命令回复
具体的过程图可以看下边的流程图片:
处理机制
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模式核心组件
-
事件驱动架构:
- 整个系统围绕事件进行组织
- 事件包括:连接建立、数据到达、超时等
- 事件触发相应的处理逻辑
-
输入源(Event Sources):
- 一个或多个并发输入源(如网络Socket)
- 可以是客户端连接、定时器事件等
- Redis中主要包括网络I/O事件和时间事件
-
服务处理器(ServiceHandler):
- 也称为Dispatcher或Event Demultiplexer
- 负责监听和收集所有事件源产生的事件
- 在Redis中由aeEventLoop实现
-
请求处理器(RequestHandlers):
- 多个具体的事件处理器
- 每个处理器负责处理特定类型的事件
- Redis中包括:连接处理器、命令处理器等
工作流程
-
事件注册:
- 各种事件源向ServiceHandler注册感兴趣的事件
- 例如:注册Socket的可读事件
-
事件循环:
- ServiceHandler通过I/O多路复用API(如epoll)等待事件
- 当事件发生时,ServiceHandler被唤醒
-
事件分发:
- ServiceHandler同步地将事件分发给对应的RequestHandler
- 分发过程通常是通过回调机制实现的
-
事件处理:
- RequestHandler执行具体的业务逻辑
- 在Redis中,这包括解析命令、执行命令、返回响应等
Redis中的具体实现
在Redis源码中,Reactor模式的主要实现包括:
- aeEventLoop:事件循环的核心结构体
- aeApiPoll:封装底层I/O多路复用API
- aeCreateFileEvent:注册文件事件
- aeCreateTimeEvent:注册时间事件
Redis的事件处理流程示例:
- 客户端连接到Redis服务器的连接请求到达
- aeEventLoop通过epoll检测到新的连接事件
- 调用acceptTcpHandler处理新连接
- 当客户端发送命令数据时,触发读事件
- 调用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优点
能处理大量数据,性能较高。