Redis源码分析

本文通过分析Redis源码,详细阐述了Redis从启动、网络层、协议层到业务层的数据保存流程。重点关注启动过程、自定义网络事件处理、通信协议及数据在dict中的形态变化。同时,介绍了如何在Redis中定义新的数据类型。
摘要由CSDN通过智能技术生成

前言

  • 前言
  • 宏观梳理
  • 启动过程
  • 网络层
  • 协议层
  • 业务层
  • 在保存到dict 的过程中,数据的形态也一直在变化
  • 定义新的数据类型
  • 小结

参考《Apache Kafka源码分析》——server服务端网络开发的基本套路

宏观梳理

整个轴线是redisServer 初始化并启动eventloop, eventLoop 创建redisClient 及驱动processCommand 方法进而 执行redisCommand 向 dict 中保存数据

本文 以一个SET KEY VALUE 来分析redis的 启动和保存流程

启动过程

redis.c

int main(int argc, char **argv) {
	...
	// 初始化服务器
	initServerConfig();
	...
	// 将服务器设置为守护进程
	if (server.daemonize) daemonize();
	// 创建并初始化服务器数据结构
	initServer();
	...
	// 运行事件处理器,一直到服务器关闭为止
	aeSetBeforeSleepProc(server.el,beforeSleep);
	aeMain(server.el);
	// 服务器关闭,停止事件循环
	aeDeleteEventLoop(server.el);
	return 0
}

网络层

Redis的网络监听没有采用libevent等,而是自己实现了一套简单的机遇event驱动的API,具体见ae.c。事件处理器的主循环

void aeMain(aeEventLoop *eventLoop) {
	eventLoop->stop = 0;
	while (!eventLoop->stop) {
		// 如果有需要在事件处理前执行的函数,那么运行它
		if (eventLoop->beforesleep != NULL)
			eventLoop->beforesleep(eventLoop);
		// 开始处理事件
		aeProcessEvents(eventLoop, AE_ALL_EVENTS);
	}
}

Redis 中的事件循环

int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
	struct timeval tv, *tvp;
	... 
    // 获取最近的时间事件
    if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
        shortest = aeSearchNearestTimer(eventLoop);
    if (shortest) {
        // 如果时间事件存在的话,那么根据最近可执行时间事件和现在时间的时间差来决定文件事件的阻塞时间
        // 计算距今最近的时间事件还要多久才能达到,并将该时间距保存在 tv 结构中
        aeGetTime(&now_sec, &now_ms);
    } else {
        // 执行到这一步,说明没有时间事件,那么根据 AE_DONT_WAIT 是否设置来决定是否阻塞,以及阻塞的时间长度
    }
    // 处理文件事件,阻塞时间由 tvp 决定
	// 类似于 java nio 中的select
    numevents = aeApiPoll(eventLoop, tvp);
    for (j = 0; j < numevents; j++) {
        // 从已就绪数组中获取事件
        aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
        int mask = eventLoop->fired[j].mask;
        int fd = eventLoop->fired[j].fd;
        // 读事件
        if (fe->mask & mask & AE_READABLE) {
            fe->rfileProc(eventLoop,fd,fe->clientData,mask);
        }
        // 写事件
        if (fe->mask & mask & AE_WRITABLE) {
            if (!rfired || fe->wfileProc != fe->rfileProc)
                fe->wfileProc(eventLoop,fd,fe->clientData,mask);
        }
    }
	// 执行时间事件
	if (flags & AE_TIME_EVENTS)
		processed += processTimeEvents(eventLoop);
}

这个event loop的逻辑可不孤单,netty中也有类似的EventLoop 中的 Loop 到底是什么?

Redis 中会处理两种事件:时间事件和文件事件。在每个事件循环中 Redis 都会先处理文件事件,然后再处理时间事件直到整个循环停止。 aeApiPoll 可看做文件事件的生产者(还有一部分文件事件来自accept等),processEvents 和 processTimeEvents 作为 Redis 中发生事件的消费者,每次都会从“事件池”(aeEventLoop的几个列表字段)中拉去待处理的事件进行消费。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值