Heim  >  Artikel  >  Datenbank  >  Ein Artikel über Epoll- und Dateiereignisse in Redis

Ein Artikel über Epoll- und Dateiereignisse in Redis

青灯夜游
青灯夜游nach vorne
2021-11-03 10:55:141868Durchsuche

Dieser Artikel stellt Ihnen die Dateiereignisse in Redis vor. Er hat einen gewissen Referenzwert. Ich hoffe, er wird Ihnen hilfreich sein.

Ein Artikel über Epoll- und Dateiereignisse in Redis

Ereignisgesteuert

Der Redis-Server ist ein ereignisgesteuertes Programm, unterteilt in Dateiereignisse und Zeitereignisse文件事件时间事件

  • 文件事件:socket 的可读可写事件
  • 定时任务

【相关推荐: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为事件处理主函数

epoll

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 服务器会通过创建各类文件事件来处理事务,比如:

  • 启动时创建 socket 并监听,等待客户端连接
aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler, NULL);
  • 客户端与服务器建立 socket 连接之后,服务器会等待客户端的命令请求
aeCreateFileEvent(server.el, fd, AE_READABLLE, readQueryFromClient, c);
  • 服务器处理完客户端的命令请求之后,命令回复会暂时缓存在client结构体的buf缓冲区,待客户端文件描述符的可写事件发生时,才会真正往客户端发送命令回复
aeCreateFileEvent(server.el, c->fd, AE_READABLLE, sendReplyToClient, c);

Redis 所有事件的执行都是通过aeProcessEvents

Dateiereignisse: Socket ist lesbar und Ereignisse schreiben Geplante Aufgaben

[Verwandte Empfehlungen: Redis-Video-Tutorial】

Sie sind alle in der aeEventLoop-Struktur eingekapselt aeProcessEvents ist die HauptereignisverarbeitungsfunktionEin Artikel über Epoll- und Dateiereignisse in Redis

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ßlich select/epoll/kqueue usw. Verschiedene Betriebssysteme haben unterschiedliche Implementierungen.
  • Nehmen Sie 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

    • epoll_create erstellt einen Epoll-spezifischen Dateideskriptor für nachfolgende Epoll-bezogene API-Aufrufe
    • 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);
      }

      • epoll_ctl-Funktion registriert, ändert oder löscht Ereignisse, die mit epoll überwacht werden müssen
      rrreee
        🎜epoll_wait-Funktion blockiert den Prozess, bis Ereignisse auf mehreren überwachten Netzwerkverbindungen auftreten🎜🎜
      rrreee🎜🎜Dateiereignisse🎜🎜🎜Reids verwendet die Epoll-API nicht direkt, unterstützt sie aber gleichzeitig Time 4 I/O-Multiplexing-Modelle kapseln die APIs dieser Modelle. Während der Kompilierungsphase wird dann das vom Betriebssystem unterstützte E/A-Multiplexmodell überprüft und entschieden, welches Modell gemäß der Strategie wiederverwendet werden soll. 🎜🎜Am Beispiel von Epoll ist Redis wie folgt gekapselt: 🎜rrreee🎜Erinnern Sie sich an die oben erwähnte 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!

      Stellungnahme:
      Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen