Redis(135)Redis的网络模型是什么?

Redis的网络模型是基于单线程的事件驱动机制实现的,使用了 Reactor 模式。它主要通过一个事件循环来处理网络I/O和文件I/O。Redis的高性能很大程度上依赖于这个轻量级的网络模型,该模型允许它在单线程中高效地处理大量并发连接。

核心数据结构和组件

1. 事件循环(Event Loop)

Redis使用aeEventLoop结构体来管理事件循环。事件循环本质上是一个无限循环,它处理所有注册的事件(文件事件和时间事件)。

c 复制代码
typedef struct aeEventLoop {
    int maxfd;   /* highest file descriptor currently registered */
    int setsize; /* max number of file descriptors tracked */
    long long timeEventNextId;
    aeFileEvent *events; /* Registered events */
    aeFiredEvent *fired; /* Fired events */
    aeTimeEvent *timeEventHead;
    int stop;
    void *apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc *beforesleep;
    aeBeforeSleepProc *aftersleep;
} aeEventLoop;

2. 文件事件(File Event)

文件事件表示对文件描述符的读写操作。

c 复制代码
typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE) */
    aeFileProc *rfileProc;
    aeFileProc *wfileProc;
    void *clientData;
} aeFileEvent;

3. 时间事件(Time Event)

时间事件用于处理定时任务。

c 复制代码
typedef struct aeTimeEvent {
    long long id; /* time event identifier. */
    long when_sec; /* seconds */
    long when_ms; /* milliseconds */
    aeTimeProc *timeProc;
    aeEventFinalizerProc *finalizerProc;
    void *clientData;
    struct aeTimeEvent *next;
} aeTimeEvent;

核心函数和流程

1. 创建和初始化事件循环

c 复制代码
aeEventLoop *aeCreateEventLoop(int setsize) {
    aeEventLoop *eventLoop;
    int i;

    if ((eventLoop = malloc(sizeof(*eventLoop))) == NULL) goto err;
    eventLoop->events = malloc(sizeof(aeFileEvent) * setsize);
    eventLoop->fired = malloc(sizeof(aeFiredEvent) * setsize);
    if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err;
    eventLoop->setsize = setsize;
    eventLoop->timeEventHead = NULL;
    eventLoop->timeEventNextId = 0;
    eventLoop->stop = 0;
    eventLoop->maxfd = -1;
    eventLoop->beforesleep = NULL;
    eventLoop->aftersleep = NULL;

    if (aeApiCreate(eventLoop) == -1) goto err;

    for (i = 0; i < setsize; i++)
        eventLoop->events[i].mask = AE_NONE;
    return eventLoop;

err:
    if (eventLoop) {
        free(eventLoop->events);
        free(eventLoop->fired);
        free(eventLoop);
    }
    return NULL;
}

2. 注册文件事件

c 复制代码
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
                      aeFileProc *proc, void *clientData) {
    if (fd >= eventLoop->setsize) return AE_ERR;
    aeFileEvent *fe = &eventLoop->events[fd];

    if (aeApiAddEvent(eventLoop, fd, mask) == -1)
        return AE_ERR;
    fe->mask |= mask;
    if (mask & AE_READABLE) fe->rfileProc = proc;
    if (mask & AE_WRITABLE) fe->wfileProc = proc;
    fe->clientData = clientData;
    if (fd > eventLoop->maxfd)
        eventLoop->maxfd = fd;
    return AE_OK;
}

3. 事件循环处理函数

c 复制代码
void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
        if (eventLoop->aftersleep != NULL)
            eventLoop->aftersleep(eventLoop);
    }
}

int aeProcessEvents(aeEventLoop *eventLoop, int flags) {
    int processed = 0, numevents;

    if (!(flags & AE_TIME_EVENTS)) return 0;
    processed += processTimeEvents(eventLoop);

    if (flags & AE_FILE_EVENTS) {
        numevents = aeApiPoll(eventLoop, &tvp);
        for (int 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;
            int rfired = 0;

            if (fe->mask & mask & AE_READABLE) {
                rfired = 1;
                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);
            }

            processed++;
        }
    }

    return processed;
}

4. 处理时间事件

时间事件主要用于定时任务,通过检查当前时间和事件触发时间来决定是否执行:

c 复制代码
static int processTimeEvents(aeEventLoop *eventLoop) {
    int processed = 0;
    aeTimeEvent *te;
    long long maxId;
    time_t now = time(NULL);

    te = eventLoop->timeEventHead;

    while (te) {
        long now_sec, now_ms;
        long long id;

        aeGetTime(&now_sec, &now_ms);

        if (te->when_sec > now_sec || (te->when_sec == now_sec && te->when_ms > now_ms)) {
            te = te->next;
            continue;
        }

        id = te->id;
        int retval = te->timeProc(eventLoop, id, te->clientData);
        processed++;

        if (retval != AE_NOMORE) {
            te->when_sec = now_sec + retval / 1000;
            te->when_ms = now_ms + retval % 1000;
            if (te->when_ms >= 1000) {
                te->when_sec++;
                te->when_ms -= 1000;
            }
        } else {
            aeDeleteTimeEvent(eventLoop, id);
        }

        te = eventLoop->timeEventHead;
    }

    return processed;
}

示例使用

以下是一个简单的示例,展示了如何使用Redis的网络模型处理文件事件:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ae.h"

void fileEventProc(aeEventLoop *eventLoop, int fd, void *clientData, int mask) {
    char buf[128];
    int n = read(fd, buf, sizeof(buf));
    if (n > 0) {
        buf[n] = '\0';
        printf("Read from fd %d: %s\n", fd, buf);
    } else if (n == 0) {
        printf("EOF on fd %d\n", fd);
        aeDeleteFileEvent(eventLoop, fd, AE_READABLE);
        close(fd);
    } else {
        perror("read");
    }
}

int main(int argc, char **argv) {
    aeEventLoop *eventLoop = aeCreateEventLoop(1024);

    if (aeCreateFileEvent(eventLoop, STDIN_FILENO, AE_READABLE, fileEventProc, NULL) == AE_ERR) {
        fprintf(stderr, "Could not create file event.\n");
        return 1;
    }

    aeMain(eventLoop);

    aeDeleteEventLoop(eventLoop);
    return 0;
}

总结

Redis的网络模型是基于单线程事件驱动机制的,使用 Reactor 模式进行事件处理。这种模型允许 Redis 在单线程环境下高效地处理大量并发连接,通过注册、处理文件事件和时间事件实现高效的 I/O 操作。这种设计不仅简化了编程模型,还显著提升了系统的性能和可维护性。

相关推荐
bcbnb7 小时前
如何解析iOS崩溃日志:从获取到符号化分析
后端
许泽宇的技术分享7 小时前
当AI学会“说人话“:Azure语音合成技术的魔法世界
后端·python·flask
用户69371750013847 小时前
4.Kotlin 流程控制:强大的 when 表达式:取代 Switch
android·后端·kotlin
用户69371750013847 小时前
5.Kotlin 流程控制:循环的艺术:for 循环与区间 (Range)
android·后端·kotlin
vx_bisheyuange7 小时前
基于SpringBoot的宠物商城网站的设计与实现
spring boot·后端·宠物
bcbnb7 小时前
全面解析网络抓包工具使用:Wireshark和TCPDUMP教程
后端
leonardee7 小时前
Spring Security安全框架原理与实战
java·后端
回家路上绕了弯7 小时前
包冲突排查指南:从发现到解决的全流程实战
分布式·后端
爱分享的鱼鱼8 小时前
部署Vue+Java Web应用到云服务器完整指南
前端·后端·全栈
麦麦麦造8 小时前
比 pip 快 100 倍!更现代的 python 包管理工具,替代 pip、venv、poetry!
后端·python