WRK 的源码详解网上已经有一些了,但是都不是特别详细,最近有时间特意详读了一下,希望能给大家一些参考以及启发
wrk 是一个多线程,内部通过事件驱动模型 +IO 多路复用处理网络连接的一个针对 HTTP/HTTPS 的压测工具(不支持 windows 系统)
wrk 源码在 src 目录下,其中比较重要的文件有 wrk,stats,net,http_parser
wrk 想阅读明白要先理解 AE,在第一个文章中,我会先介绍一下:AE
AE 是 Redis 内置的一个高性能事件驱动器,主要分为文件事件和定时器事件
但也是由于 AE 这套规则只能在符合 POSIX 标准的系统中工作,所以 wrk 不能在 windows 系统中运行
aeEventLoop *aeCreateEventLoop(int setsize);
void aeDeleteEventLoop(aeEventLoop *eventLoop);
setsize 参数表示了 eventloop 可以监听的网络事件 fd 个数,一般这个数字是最大并发数 + 一些预留空间
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData);
void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask);
eventLoop 为上面创建的驱动器,fd 为监听的文件句柄,注册事件类型分别有:AE_READABLE,AE_WRITABLE ,AE_BARRIER,mask 是这几个事件经过或运算后的掩码(例如如果想监听读写事件,则 mask=AE_READABLE|AE_WRITABLE,如果只想监听写事件,则 mask=AE_WRITABLE),proc 为执行的回调函数,clientData 为传给回调参数的值
long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, aeTimeProc *proc, void *clientData, aeEventFinalizerProc *finalizerProc);
int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id);
milliseconds 为超时时间,proc 为超时后的回调函数,finalizerProc 为定时器删除后执行的回调函数
void aeMain(aeEventLoop *eventLoop);
// 事件循环
一般使用方式是创建驱动器,再根据需要添加文件 IO 事件或定时器事件,通过 aeMain 事件循环
FeeBSD 或 Apple 使用的是 kqueue,linux 使用的是 epoll,sunos 使用的是 evport,则默认使用 select,从效率上来看是:evport > epoll > kqueue > select
源码中是这么标注的
#if defined(__FreeBSD__) || defined(__APPLE__)
#define HAVE_KQUEUE
#elif defined(__linux__)
#define HAVE_EPOLL
#elif defined (__sun)
#define HAVE_EVPORT
每个线程创建了一个独立的 aeEventLoop,线程内创建若干 connection(socket),并为每个 socket 句柄注册事件(aeCreateFileEvent),包括:AE_READABLE,AE_WRITABLE
关键代码
flags = AE_READABLE | AE_WRITABLE;
aeCreateFileEvent(loop, fd, flags, socket_connected, c);
每个线程注册定时器(aeCreateTimeEvent),每 100ms 执行一次统计请求和响应结果
关键代码
aeCreateTimeEvent(loop, RECORD_INTERVAL_MS, record_rate, thread, NULL);
第二章可跳转:WRK 源码详解 (第二章:处理连接)