客户端请求处理完整链路源码分析 一、概述 当客户端向 Redis 发送一条命令(如 SET key value)时,请求会经历一个完整的处理链路:从网络数据接收、协议解析、命令查找、命令执行、结果返回,直到最终发送响应。本文将深入分析这个完整的请求处理链路,帮助读者理解 Redis 如何高效地处理每一条命令。
请求处理链路概览:
1┌─────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ 2│ 网络读取 │ -> │ 协议解析 │ -> │ 命令查找 │ -> │ 命令执行 │ -> │ 结果封装 │ -> │ 响应发送 │ 3└─────────┘ └──────────┘ └───────────┘ └──────────┘ └──────────┘ └─────────┘ 4 │ │ │ │ │ │ 5 ▼ ▼ ▼ ▼ ▼ ▼ 6read() processMulti- lookupCommand call() addReply() write() 7 bulkBuffer() 二、整体架构图 1┌─────────────────────────────────────────────────────────────────────────────────────┐ 2│ Redis 客户端请求处理完整链路 │ 3├─────────────────────────────────────────────────────────────────────────────────────┤ 4│ │ 5│ ┌─────────────┐ │ 6│ │ Client │ │ 7│ │ (客户端) │ │ 8│ └──────┬──────┘ │ 9│ │ TCP 连接 │ 10│ ▼ │ 11│ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 12│ │ 1.
文件事件(File Event)源码详解 一、概述 Redis 基于 Reactor 模式实现了一套高效的事件驱动机制,其中**文件事件(File Event)**是其核心组件之一。文件事件用于处理网络 I/O 操作,包括客户端连接建立、命令接收、响应发送等。通过 I/O 多路复用技术,Redis 能够在单线程中高效地处理大量并发连接。
本文将深入剖析 Redis 文件事件的实现原理,从数据结构到核心 API,再到实际应用场景。
二、核心数据结构 2.1 文件事件结构体 aeFileEvent 1// src/ae.h:71-76 2typedef struct aeFileEvent { 3 int mask; // 事件类型掩码:AE_READABLE | AE_WRITABLE | AE_BARRIER 4 aeFileProc *rfileProc; // 读事件回调函数 5 aeFileProc *wfileProc; // 写事件回调函数 6 void *clientData; // 用户自定义数据 7} aeFileEvent; 字段解析:
mask:标识事件的类型,支持以下取值:
AE_NONE (0):无事件注册 AE_READABLE (1):可读事件,当 fd 可读时触发 AE_WRITABLE (2):可写事件,当 fd 可写时触发 AE_BARRIER (4):屏障标志,用于控制读写事件的触发顺序 rfileProc:读事件触发时的回调函数指针
wfileProc:写事件触发时的回调函数指针
clientData:传递给回调函数的用户数据(通常是 client 结构体指针)
时间事件(Time Event)源码详解 一、概述 Redis 的事件驱动机制中,**时间事件(Time Event)**是与文件事件并列的另一类核心事件。时间事件用于处理定时任务,如服务器定时维护、客户端超时检测、AOF 持久化、主从复制心跳等。Redis 通过时间事件实现了一个轻量级的定时器机制,在单线程中高效地管理各类周期性任务。
本文将深入剖析 Redis 时间事件的实现原理,从数据结构到核心 API,再到实际应用场景。
二、核心数据结构 2.1 时间事件结构体 aeTimeEvent 1// src/ae.h:78-88 2typedef struct aeTimeEvent { 3 long long id; // 时间事件唯一标识符,全局递增 4 long when_sec; // 触发时间的秒数部分(绝对时间) 5 long when_ms; // 触发时间的毫秒数部分(绝对时间) 6 aeTimeProc *timeProc; // 时间事件回调函数 7 aeEventFinalizerProc *finalizerProc; // 事件销毁时的清理函数(可选) 8 void *clientData; // 用户自定义数据,传递给回调函数 9 struct aeTimeEvent *next; // 指向下一个时间事件,形成单向链表 10} aeTimeEvent; 字段解析:
id:时间事件的唯一标识符,全局递增,用于删除特定事件 when_sec、when_ms:事件触发的绝对时间(秒 + 毫秒) timeProc:事件触发时的回调函数,返回值决定事件是否继续周期执行 finalizerProc:事件被删除时的清理回调(可选) clientData:传递给回调函数的用户数据 next:指向下一个时间事件节点,时间事件以无序链表组织 2.
Redis 核心数据结构总览(对象系统设计) Redis支持五种基本数据类型:String、List、Set、Hash、ZSet,还有Stream和Module类型。但底层实现不是一对一的,而是通过对象系统(redisObject)抽象,让一种类型可以有多种编码方式,根据数据特征自动选择最优实现。
一、redisObject:统一的对象抽象 所有Redis值都封装成redisObject:
1// server.h 2typedef struct redisObject { 3 unsigned type:4; // 类型,4位,取值0-15 4 unsigned encoding:4; // 编码,4位,取值0-15 5 unsigned lru:LRU_BITS; // LRU时间(24位)或LFU 数据 6 int refcount; // 引用计数 7 void *ptr; // 指向实际数据的指针 8} robj; 16字节的结构体,包含了Redis值的全部信息。
1.1 type:对象类型 1#define OBJ_STRING 0 // 字符串 2#define OBJ_LIST 1 // 列表 3#define OBJ_SET 2 // 集合 4#define OBJ_ZSET 3 // 有序集合 5#define OBJ_HASH 4 // 哈希 6#define OBJ_MODULE 5 // 模块类型 7#define OBJ_STREAM 6 // 流 TYPE key 命令返回的就是这个type字段。
Redis 配置加载机制源码分析 redis.conf 里的那些配置项,Redis 是怎么读到内存里去的?运行时用 CONFIG SET 改了配置,重启后还能生效吗?这篇文章来拆解配置加载的完整流程。
一、配置加载入口 启动时,main() 函数调用 loadServerConfig():
1void loadServerConfig(char *filename, char *options) { 2 sds config = sdsempty(); // 创建空的 sds 字符串,用于存放配置内容 3 char buf[CONFIG_MAX_LINE+1]; // 行缓冲区,CONFIG_MAX_LINE 是 1024 4 5 if (filename) { // filename 可能为 NULL(只用命令行参数时) 6 FILE *fp; 7 if (filename[0] == '-' && filename[1] == '\0') { 8 // "redis-server -" 表示从 stdin 读配置 9 fp = stdin; 10 } else { 11 if ((fp = fopen(filename,"r")) == NULL) { 12 serverLog(LL_WARNING, "Fatal error, can't open config file '%s'", filename); 13 exit(1); 14 } 15 } 16 // 逐行读取文件内容,拼接到 config 字符串 17 while(fgets(buf,CONFIG_MAX_LINE+1,fp) !
yum配置镜像源 1# 备份源文件 2mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 3 4# 下载阿里的替换 5wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo Docker配置 一些数据库配置 1# mongodb 2docker run -d \ 3 --name mongodb \ 4 -p 27017:27017 \ 5 -v /data/mongodb:/data/db \ 6 -e MONGO_INITDB_ROOT_USERNAME=root \ 7 -e MONGO_INITDB_ROOT_PASSWORD=123456 \ 8 mongo --bind_ip_all 9 10 11# redis 12docker run -d \ 13 --name myredis \ 14 -p 6379:6379 \ 15 -e REDIS_PASSWORD=123456 \ 16 redis:latest \ 17 redis-server --requirepass 123456 18 19# etcd