Maison >base de données >Redis >Un article pour parler d'epoll et des événements de fichiers dans Redis
Cet article vous présentera les événements de fichiers dans Redis. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.
Le serveur Redis est un programme piloté par des événements, divisé en Événements de fichier
et Événements de temps
文件事件
和时间事件
【相关推荐: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
[Recommandations associées : Tutoriel vidéo Redis】
Ils sont tous encapsulés dans la structure aeEventLoop
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); }Le pilote d'événement attend en fait que l'événement se produise via la boucle
while/for
rrreee
aeProcessEvents
est la principale fonction de traitement des événements
select/epoll/kqueue
, etc. Différents systèmes d'exploitation ont des implémentations différentes. epoll
comme exemple. C'est une solution proposée par le noyau Linux pour gérer un grand nombre de connexions réseau simultanées. epoll
fournit 3 API
rrreee
eventLoop
mentionnée ci-dessus, son membre apidata pointe vers 4 types d'objets de modèle de multiplexage d'E/S Stockez l'événement ; tableau qui doit être surveillé et utilise le descripteur de fichier socket comme index du tableau pour accéder aux éléments ; Fired stocke le tableau d'événements déclenchés. 🎜🎜La structure de l'événement de fichier est définie comme suit : 🎜rrreee🎜Regardez l'implémentation de l'événement de création de fichier aeCreateFileEvent🎜rrreee🎜Le serveur Redis gérera les transactions en créant divers événements de fichier, tels que : 🎜🎜🎜Créer un socket au démarrage et écoutez, attendez la connexion du client🎜aeProcessEvents pour contrôler. Parmi eux, l'exécution des événements de fichier provoquera un blocage (epoll_wait). Si l'événement bloquant est trop long, cela gênera l'exécution des événements de temps (timing). Pour éviter cette situation, le temps d'attente passé lors de l'implémentation des événements de fichier, Il est obtenu en calculant le premier événement temporel survenu🎜rrreee🎜🎜Résumé🎜🎜🎜Jetons maintenant un aperçu global du processus de la commande correspondante du serveur Redis🎜🎜🎜🎜🎜La fonction aeMain planifie les événements de fichier et les événements temporels en appelant la fonction aeProcessEvents implémentée. Les informations relatives à l'événement sont enregistrées dans aeEventLoop. Tout d'abord, obtenez l'intervalle de temps d'exécution n de l'événement temporel le plus court via la fonction aeSearchNearestTimer, puis appelez la fonction aeApiPoll pour obtenir le socket surveillé, et enfin exécutez les fonctions de traitement d'événements rfileProc et wfileProc correspondant au socket, et enfin exécutez l'événement temporel fonction processTimeEvents . 🎜🎜Un événement de connexion client-serveur complet : 🎜🎜🎜🎜Le serveur écoute l'événement AE_READABLE du package Lorsque le client envoie une demande de connexion, un événement AE_READABLE est généré et défini. le client La fonction de traitement des événements et des demandes de commande AE_READABLE de l'interface (aeFileProc), le client peut envoyer une demande de commande au serveur 🎜🎜🎜🎜Le client envoie une demande de commande au serveur, le socket client générera un événement AE_READABLE, déclenchant la commande traitement Le serveur l'exécute et l'exécution de la commande générera une réponse de commande correspondante. Le serveur associe l'événement AE_WRITABLE du socket client à la fonction de traitement de réponse de commande (aeFileProc). Lorsque le client tente de lire la réponse de commande, le socket client. L'événement AE_WRITABLE sera généré, déclenchant l'exécution du processeur de réponse de commande. Lorsque le processeur de réponse de commande écrit toutes les réponses de commande sur le socket, le serveur contactera la connexion entre l'événement AE_WRITABLE du socket client et la fonction de traitement de réponse de commande. (aeFileProc).<p>Pour plus de connaissances sur la programmation, veuillez visiter : <a href="https://www.php.cn/course.html" target="_blank" textvalue="编程视频">Vidéo de programmation</a> ! ! </p>
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!