Dieser Artikel stellt Ihnen die Dateiereignisse in Redis vor. Er hat einen gewissen Referenzwert. Ich hoffe, er wird Ihnen hilfreich sein.
Der Redis-Server ist ein ereignisgesteuertes Programm, unterteilt in Dateiereignisse
und Zeitereignisse
文件事件
和时间事件
【相关推荐:Redis视频教程】
它们都被封装到aeEventLoop
结构体中
typedef struct aeEventLoop { int stop; // 标识事件是否结束 aeFileEvent *events; // 文件事件数组,存储已注册的文件事件 aeFireEvent *fired; // 存储被触发的文件事件 aeTimeEvent *timteEventHead; // 多个时间事件形成的链表 void *apidata; // I/O模型的封装 aeBeforeSleepProc *beforesleep; // 进程阻塞前执行 aeBeforeSleepProc *aftersleep; // 进程被唤醒后执行 } aeEventLoop;
事件驱动程序实际上也是通过while/for
循环,循环等待事件的发生
while (! eventLoop->stop) { if (eventLoop->beforesleep != NULL) eventLoop->beforesleep(eventLoop) aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP); }
aeProcessEvents
为事件处理主函数
Redis 客户端通过 TCP socket 与服务端交互,文件事件指的就是 socket 的可读可写事件。一般使用非阻塞模式,相关的 I/O 多路复用有select/epoll/kqueue
等,不同的操作系统不同的实现。
以epoll
为例,它是 Linux 内核为处理大量并发网络连接而提出解决方案。epoll
提供3个 API
epoll_create 创建一个 epoll 专用的文件描述符,用于后续 epoll 相关 API 调用
int epoll_create(int size) // size 告知内核程序期望注册的网络连接数目,Linux 2.6.8后改为内核动态分配 // 返回参数是 epoll 专用的文件描述符
epoll_ctl 函数向 epoll 注册、修改或删除需要监控的事件
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) // epfd 函数 epoll_create 返回的 epoll 文件描述符 // op 操作类型 EPOLL_CTL_ADD:注册事件; EPOLL_CTL_MOD:修改网络连接事件; EPOLL_CTL_DEL:删除事件 // fd 网络连接的 socket 文件描述符 // event 需要监控的事件
epoll_wait 函数会会阻塞进程,直到监控的若干网络连接有事件发生
int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout) // epfd 函数epoll_create返回的epoll文件描述符 // epoll_event 作为输出参数使用,用于回传已触发的事件数组 // maxevents 每次能处理的最大事件数目 // timeout epoll_wait 函数阻塞超时时间,如果超过 timeout 时间还没有事件发生,函数就不再阻塞直接返回;当 timeout 等于0是函数立即返回,timeout 等于-1时函数一直阻塞到有事件发生
Reids 没有直接使用 epoll 的 API,而是同时支持4种I/O多路复用模型,对这些模型的 API 进行了封装。然后在编译阶段检查操作系统支持的I/O多路复用模型,并按照策略来决定复用那张模型。
还是以 epoll 为例,Redis 进行了如下封装
// 对应 epoll_create static int aeApiCreate(aeEventLoop *eventLoop) // 对应 epoll_ctl 添加事件 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) // 对应 epoll_ctl 删除事件 static int aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) // 对应 epoll_wait static int aeApiPool(aeEventLoop *eventLoop, struct timeval *tvp)
回忆一下上面提到的eventLoop
结构体,其成员 apidata 指向4种I/O多路复用模型对象;events 存储需要监控的事件数组,以 socket 文件描述符作为数组索引存取元素;fired 存储已触发的事件数组。
文件事件的结构体定义如下:
typedef struct aeFileEvent { int mask; // 文件事件类型 AE_READABLE 可读事件;AE_WRITEABLE 可写事件 aeFileProc *rfileProc; // 读事件处理函数指针 aeFileProc *wfileProc; // 写事件处理函数指针 void *clientData; // 指向对应的客户端对象 } aeFileEvent;
看一下创建文件事件 aeCreateFileEvent 的实现
int aeCreateFileEvent (aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) { aeFileEvent *fe = &eventLoop->evnts[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; return AE_OK; }
Redis 服务器会通过创建各类文件事件来处理事务,比如:
aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler, NULL);
aeCreateFileEvent(server.el, fd, AE_READABLLE, readQueryFromClient, c);
aeCreateFileEvent(server.el, c->fd, AE_READABLLE, sendReplyToClient, c);
Redis 所有事件的执行都是通过aeProcessEvents
[Verwandte Empfehlungen: Redis-Video-Tutorial】
Sie sind alle in der aeEventLoop
-Struktur eingekapselt aeProcessEvents
ist die Hauptereignisverarbeitungsfunktion
epoll
Der Redis-Client interagiert mit dem Server über den TCP-Socket. Dateiereignisse beziehen sich auf die lesbaren und beschreibbaren Ereignisse des Sockets. Im Allgemeinen wird der nicht blockierende Modus verwendet, einschließlichselect/epoll/kqueue
usw. Verschiedene Betriebssysteme haben unterschiedliche Implementierungen. epoll
als Beispiel. Dabei handelt es sich um eine vom Linux-Kernel vorgeschlagene Lösung zur Verarbeitung einer großen Anzahl gleichzeitiger Netzwerkverbindungen. epoll
stellt 3 APIs bereit
int aeProcessEvents(aeEventLoop *eventLoop, int flags) { shortest = aeSearchNearestTimer(eventLoop); long long ms = (shortest->when_sec - now_sec) * 1000 + \ shortest->when_ms - now_ms; // 阻塞事件发生 numevents = aeApiPoll(eventLoop, ms); for (j=0; j < numevents; j++) { aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j]].fd]; // 处理文件事件,即根据类型执行rfileProc或wfileProc } // 处理时间事件 processed += processTimeEvents(eventLoop); }
eventLoop
-Struktur. Ihre Mitglieds-Apidaten zeigen auf 4 Arten von E/A-Multiplex-Modellobjekten. Speichern Sie das Ereignis Array, das überwacht werden muss, und den Socket-Dateideskriptor als Array-Index verwenden, um auf die ausgelösten Elemente zuzugreifen, speichert das ausgelöste Ereignis-Array. 🎜🎜Die Struktur des Dateiereignisses ist wie folgt definiert: 🎜rrreee🎜Sehen Sie sich die Implementierung des Dateierstellungsereignisses aeCreateFileEvent an🎜rrreee🎜Der Redis-Server verarbeitet Transaktionen, indem er verschiedene Dateiereignisse erstellt, wie zum Beispiel: 🎜🎜🎜Socket erstellen beim Start und abhören, warten Client-Verbindung🎜rrreee🎜🎜Nachdem der Client eine Socket-Verbindung mit dem Server hergestellt hat, wartet der Server auf die Befehlsanforderung des Clients🎜rrreee🎜🎜Nachdem der Server die des Clients verarbeitet hat Bei der Befehlsanforderung wird die Befehlsantwort vorübergehend im Pufferspeicher der Clientstruktur zwischengespeichert. Es wird keine tatsächliche Befehlsantwort an den Client gesendet, bis das beschreibbare Ereignis des Clientdateideskriptors auftritt🎜rrreee🎜Redis Alle Ereignisse werden ausgeführt über die Funktion aeProcessEvents steuern. Unter anderem führt die Ausführung von Dateiereignissen zu einer Blockierung (epoll_wait). Wenn das Blockierungsereignis zu lang ist, wird die Ausführung von Zeitereignissen (Timing) verhindert. Es wird durch Berechnen des frühesten Zeitereignisses erhalten aeProcessEvents-Funktion implementieren. Ereignisbezogene Informationen werden in aeEventLoop aufgezeichnet. Rufen Sie zunächst das Ausführungszeitintervall n des kürzesten Zeitereignisses über die Funktion aeSearchNearestTimer ab, rufen Sie dann die Funktion aeApiPoll auf, um den überwachten Socket abzurufen, führen Sie schließlich die dem Socket entsprechenden Ereignisverarbeitungsfunktionen rfileProc und wfileProc aus und führen Sie schließlich das Zeitereignis aus Funktion ProcessTimeEvents . 🎜🎜Ein vollständiges Client-Server-Verbindungsereignis: 🎜🎜🎜🎜Der Server wartet auf das AE_READABLE-Ereignis des Pakets. Wenn der Client eine Verbindungsanforderung sendet, wird ein AE_READABLE-Ereignis generiert und festgelegt der Client Mit der AE_READABLE-Ereignis- und Befehlsanforderungsverarbeitungsfunktion (aeFileProc) der Schnittstelle kann der Client eine Befehlsanforderung an den Server senden 🎜🎜🎜🎜Der Client sendet eine Befehlsanforderung an den Server, der Client-Socket generiert ein AE_READABLE-Ereignis und löst den Befehl aus Verarbeitung Der Server führt es aus und die Ausführung des Befehls generiert eine entsprechende Befehlsantwort. Der Server verknüpft das AE_WRITABLE-Ereignis des Client-Sockets mit der Befehlsantwort-Verarbeitungsfunktion (aeFileProc). Das AE_WRITABLE-Ereignis wird generiert und löst die Ausführung des Befehlsantwortprozessors aus. Wenn der Befehlsantwortprozessor alle Befehlsantworten in den Socket schreibt, stellt der Server eine Verbindung zwischen dem AE_WRITABLE-Ereignis des Client-Sockets und der Befehlsantwortverarbeitungsfunktion her (aeFileProc).<p>Weitere Programmierkenntnisse finden Sie unter: <a href="https://www.php.cn/course.html" target="_blank" textvalue="编程视频">Programmiervideo</a>! ! </p>
Das obige ist der detaillierte Inhalt vonEin Artikel über Epoll- und Dateiereignisse in Redis. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!