Eventloop 具有高 ksoftirqd 负载; nginx 不会,但会执行相同的系统调用。为什么?
Eventloop has high ksoftirqd load; nginx does not but does same system-calls. Why?
我写了一些具有 epoll-eventloop 的代码,接受新连接并伪装成一个 http 服务器。
发布的代码是绝对最少的......我删除了所有内容(包括所有错误检查)以使其尽可能简短和切题:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <unistd.h>
int main () {
int servFd = socket (AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_IP);
int value = 1;
setsockopt (servFd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof (value));
struct sockaddr_in servAddr;
memset (&servAddr, 0, sizeof (servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = 0;
servAddr.sin_port = htons (8081);
bind (servFd, (struct sockaddr*)&servAddr, sizeof (servAddr));
listen (servFd, 511);
int efd = epoll_create1 (EPOLL_CLOEXEC);
struct epoll_event epollEvt;
epollEvt.events = EPOLLIN | EPOLLRDHUP;
epollEvt.data.u32 = servFd;
epoll_ctl (efd, EPOLL_CTL_ADD, servFd, &epollEvt);
for (;;) {
struct epoll_event pollEvent[512];
int eventCount = epoll_wait (efd, pollEvent, 512, -1);
for (int i = 0; i < eventCount; ++i) {
struct epoll_event* curEvent = &pollEvent[i];
if (curEvent->data.u32 == servFd) {
int clientFd = accept4 (servFd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
struct epoll_event epollEvt;
epollEvt.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
epollEvt.data.u32 = clientFd;
epoll_ctl (efd, EPOLL_CTL_ADD, clientFd, &epollEvt);
continue;
}
int clientFd = curEvent->data.u32;
char recvBuffer[2048];
recvfrom (clientFd, recvBuffer, 2048, 0, NULL, NULL);
char sndMsg[] = "HTTP/1.1 200 OK\r\nServer: nginx/1.12.2\r\nDate: Tue, 10 Apr 2018 17:41:57 GMT\r\nContent-Type: text/plain\r\nContent-Length: 0\r\nConnection: close\r\n\r\n";
size_t sndMsgLength = sizeof (sndMsg) - 1;
struct iovec sndBuffer;
sndBuffer.iov_base = sndMsg;
sndBuffer.iov_len = sndMsgLength;
writev (clientFd, &sndBuffer, 1);
close (clientFd);
}
}
return 0;
}
localhost:~# gcc -Wall -O2 test.c -o test
localhost:~# gcc --version
gcc (Alpine 6.4.0) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
我对这段代码做了一些负载测试,并将它与 nginx 进行了比较,看看我是否做错了什么或者是否有需要改进的地方。我希望这段代码是最快的实现,因为每个其他 "real" 网络服务器都必须在 userspace 中做更多的事情。但是仍然......在使用多个负载生成器线程时,nginx 在每秒请求数方面以某种方式击败了它。 (请注意,我将 nginx 配置为仅使用一个 worker 来处理每个请求)
//ab running 1 worker from local machine
localhost:~# ab -n 100000 -c 1 http://10.0.0.111:8081/index.html
Requests per second: 13228.07 [#/sec] (mean) //[to nginx]
Requests per second: 15300.35 [#/sec] (mean) //[to testcode]
//ab running 4 worker from local machine
localhost:~# ab -n 100000 -c 4 http://10.0.0.111:8081/index.html
Requests per second: 30902.63 [#/sec] (mean) //[to nginx]
Requests per second: 24734.76 [#/sec] (mean) //[to testcode]
第一个测试有预期的结果...测试代码速度更快,因为它除了生成硬编码响应外什么都不做。但是为什么 nginx 在多线程设置中更快呢?怎么可能?
我能想到的唯一解释是 kernel-space 中有些不同,nginx 使用了一些 sockopts(比如 TCP_FASTOPEN 或 TCP_DEFER_ACCEPT)或者其他一些系统调用做它的事。这就是为什么我做了一些 strace 并使我的代码做与 nginx 完全相同的事情(从内核角度来看)--> 你可以看到下面附加的 strace。仍然......它更快,我不明白为什么。
//ab running 50 worker from remote machine
localhost:~# ab -n 100000 -c 50 http://10.0.0.111:8081/index.html
Requests per second: 27507.60 [#/sec] (mean) //[to nginx]
Requests per second: 24208.51 [#/sec] (mean) //[to testcode]
这个测试转换有完全相同的结果,但我注意到 CPU-用法有些不同。
- 我的测试代码运行在大约 60% CPU-load 并且 ksoftirqd/0 运行在大约 80%
- nginx 以大约 99% CPU-load 运行而 ksoftirqd/0 仅以 30%
运行
在这两种情况下,- ksoftirqd/0 在本地主机设置中没有明显的 CPU-负载
nginx的sTrace:
localhost:~# strace -tt -f /usr/sbin/nginx
//Removed loading of libraries to stay under the 30k char body limit for this question
13:28:20.426369 open("/etc/localtime", O_RDONLY|O_NONBLOCK|O_CLOEXEC) = 3
13:28:20.426549 fstat(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
13:28:20.426723 mmap(NULL, 127, PROT_READ, MAP_SHARED, 3, 0) = 0x74ae1cf8c000
13:28:20.426847 close(3) = 0
13:28:20.427023 getpid() = 2186
13:28:20.427164 open("/var/lib/nginx/logs/error.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 3
13:28:20.427341 brk(0xd104603e000) = 0xd104603e000
13:28:20.427503 open("/etc/ssl/openssl.cnf", O_RDONLY) = 4
13:28:20.427680 brk(0xd104603f000) = 0xd104603f000
13:28:20.427819 readv(4, [{iov_base="", iov_len=0}, {iov_base="[ req ]\n#default_bits\t\t= 2048\n#d"..., iov_len=1024}], 2) = 745
13:28:20.428089 brk(0xd1046040000) = 0xd1046040000
13:28:20.428243 readv(4, [{iov_base="", iov_len=0}, {iov_base="", iov_len=1024}], 2) = 0
13:28:20.428476 close(4) = 0
13:28:20.428718 brk(0xd1046041000) = 0xd1046041000
13:28:20.428880 brk(0xd1046042000) = 0xd1046042000
13:28:20.429179 brk(0xd1046043000) = 0xd1046043000
13:28:20.429319 brk(0xd1046044000) = 0xd1046044000
13:28:20.429552 brk(0xd1046045000) = 0xd1046045000
13:28:20.429775 brk(0xd1046046000) = 0xd1046046000
13:28:20.429935 brk(0xd1046047000) = 0xd1046047000
13:28:20.430220 brk(0xd1046048000) = 0xd1046048000
13:28:20.430391 brk(0xd1046049000) = 0xd1046049000
13:28:20.430515 brk(0xd104604b000) = 0xd104604b000
13:28:20.430796 brk(0xd104604c000) = 0xd104604c000
13:28:20.431042 brk(0xd104604d000) = 0xd104604d000
13:28:20.431238 brk(0xd104604e000) = 0xd104604e000
13:28:20.431396 brk(0xd104604f000) = 0xd104604f000
13:28:20.431581 brk(0xd1046050000) = 0xd1046050000
13:28:20.431820 brk(0xd1046051000) = 0xd1046051000
13:28:20.432112 brk(0xd1046054000) = 0xd1046054000
13:28:20.432374 brk(0xd1046055000) = 0xd1046055000
13:28:20.432509 brk(0xd1046056000) = 0xd1046056000
13:28:20.432666 brk(0xd1046057000) = 0xd1046057000
13:28:20.432836 brk(0xd1046058000) = 0xd1046058000
13:28:20.433004 brk(0xd1046059000) = 0xd1046059000
13:28:20.433203 brk(0xd104605a000) = 0xd104605a000
13:28:20.433400 brk(0xd104605b000) = 0xd104605b000
13:28:20.433610 brk(0xd104605c000) = 0xd104605c000
13:28:20.433740 brk(0xd104605d000) = 0xd104605d000
13:28:20.433895 brk(0xd104605e000) = 0xd104605e000
13:28:20.434020 brk(0xd104605f000) = 0xd104605f000
13:28:20.434240 brk(0xd1046060000) = 0xd1046060000
13:28:20.434419 brk(0xd1046061000) = 0xd1046061000
13:28:20.434622 uname({sysname="Linux", nodename="localhost", ...}) = 0
13:28:20.434801 sched_getaffinity(0, 128, [0, 1, 2, 3, 4, 5]) = 32
13:28:20.435077 prlimit64(0, RLIMIT_NOFILE, NULL, {rlim_cur=1024, rlim_max=4*1024}) = 0
13:28:20.435260 brk(0xd1046066000) = 0xd1046066000
13:28:20.435424 uname({sysname="Linux", nodename="localhost", ...}) = 0
13:28:20.435578 brk(0xd104606b000) = 0xd104606b000
13:28:20.435700 open("/etc/nginx/nginx.conf", O_RDONLY) = 4
13:28:20.435912 fstat(4, {st_mode=S_IFREG|0644, st_size=2781, ...}) = 0
13:28:20.436115 pread64(4, "\n\n\nuser nginx;\npcre_jit on;\n#tim"..., 2781, 0) = 2781
13:28:20.436284 geteuid() = 0
13:28:20.436440 open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 5
13:28:20.436596 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.436725 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.436857 readv(5, [{iov_base="", iov_len=0}, {iov_base="root:x:0:0:root:/root:/bin/ash\nb"..., iov_len=1024}], 2) = 1024
13:28:20.437047 readv(5, [{iov_base="", iov_len=0}, {iov_base="sbin/nologin\nntp:x:123:123:NTP:/"..., iov_len=1024}], 2) = 397
13:28:20.437235 lseek(5, -43, SEEK_CUR) = 1378
13:28:20.437353 close(5) = 0
13:28:20.437520 open("/etc/group", O_RDONLY|O_CLOEXEC) = 5
13:28:20.437684 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.437800 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.437933 readv(5, [{iov_base="", iov_len=0}, {iov_base="root:x:0:root\nbin:x:1:root,bin,d"..., iov_len=1024}], 2) = 776
13:28:20.438097 close(5) = 0
13:28:20.438240 epoll_create1(0) = 5
13:28:20.438429 close(5) = 0
13:28:20.438681 brk(0xd1046070000) = 0xd1046070000
13:28:20.438842 brk(0xd1046072000) = 0xd1046072000
13:28:20.439053 brk(0xd1046074000) = 0xd1046074000
13:28:20.439175 brk(0xd1046076000) = 0xd1046076000
13:28:20.439418 brk(0xd104607b000) = 0xd104607b000
13:28:20.439655 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1ce8b000
13:28:20.439886 brk(0xd1046080000) = 0xd1046080000
13:28:20.440020 brk(0xd1046085000) = 0xd1046085000
13:28:20.440225 open("/etc/nginx/mime.types", O_RDONLY) = 5
13:28:20.440380 fstat(5, {st_mode=S_IFREG|0644, st_size=3957, ...}) = 0
13:28:20.440523 pread64(5, "\ntypes {\n text/html "..., 3957, 0) = 3957
13:28:20.440725 close(5) = 0
13:28:20.440977 brk(0xd104608a000) = 0xd104608a000
13:28:20.441297 brk(0xd104608c000) = 0xd104608c000
13:28:20.441453 close(4) = 0
13:28:20.441587 mkdir("/var/tmp/nginx/client_body", 0700) = -1 EEXIST (File exists)
13:28:20.441814 stat("/var/tmp/nginx/client_body", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.442022 mkdir("/var/tmp/nginx/proxy", 0700) = -1 EEXIST (File exists)
13:28:20.442149 stat("/var/tmp/nginx/proxy", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.442257 mkdir("/var/tmp/nginx/fastcgi", 0700) = -1 EEXIST (File exists)
13:28:20.442407 stat("/var/tmp/nginx/fastcgi", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.442568 mkdir("/var/tmp/nginx/uwsgi", 0700) = -1 EEXIST (File exists)
13:28:20.442732 stat("/var/tmp/nginx/uwsgi", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.442945 mkdir("/var/tmp/nginx/scgi", 0700) = -1 EEXIST (File exists)
13:28:20.443051 stat("/var/tmp/nginx/scgi", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.443229 open("/var/log/nginx/access.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 4
13:28:20.443417 fcntl(4, F_SETFD, FD_CLOEXEC) = 0
13:28:20.443586 open("/var/log/nginx/error.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 5
13:28:20.443750 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.443889 open("/var/lib/nginx/logs/error.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 6
13:28:20.444040 fcntl(6, F_SETFD, FD_CLOEXEC) = 0
13:28:20.444197 mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0x74ae1c0a0000
13:28:20.444382 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 7
13:28:20.444515 setsockopt(7, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
13:28:20.444680 ioctl(7, FIONBIO, [1]) = 0
13:28:20.444808 bind(7, {sa_family=AF_INET, sin_port=htons(8081), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
13:28:20.445015 listen(7, 511) = 0
13:28:20.445140 listen(7, 511) = 0
13:28:20.445326 mmap(NULL, 65536, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1ce7b000
13:28:20.445493 prlimit64(0, RLIMIT_NOFILE, NULL, {rlim_cur=1024, rlim_max=4*1024}) = 0
13:28:20.445671 mmap(NULL, 1280, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0x74ae1ce7a000
13:28:20.445817 rt_sigprocmask(SIG_UNBLOCK, [RT_1 RT_2], NULL, 8) = 0
13:28:20.445977 rt_sigaction(SIGHUP, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446097 rt_sigaction(SIGUSR1, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446247 rt_sigaction(SIGWINCH, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446438 rt_sigaction(SIGTERM, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446635 rt_sigaction(SIGQUIT, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446886 rt_sigaction(SIGUSR2, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447093 rt_sigaction(SIGALRM, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447236 rt_sigaction(SIGINT, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447446 rt_sigaction(SIGIO, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447767 rt_sigaction(SIGCHLD, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447888 rt_sigaction(SIGSYS, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.448094 rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.448253 rt_sigprocmask(SIG_BLOCK, ~[], [], 8) = 0
13:28:20.448396 fork(strace: Process 2187 attached
) = 2187
[pid 2187] 13:28:20.448594 gettid( <unfinished ...>
[pid 2186] 13:28:20.448643 rt_sigprocmask(SIG_SETMASK, [], <unfinished ...>
[pid 2187] 13:28:20.448671 <... gettid resumed> ) = 2187
[pid 2186] 13:28:20.448700 <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 2187] 13:28:20.448765 rt_sigprocmask(SIG_SETMASK, [], <unfinished ...>
[pid 2186] 13:28:20.448792 exit_group(0 <unfinished ...>
[pid 2187] 13:28:20.448812 <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 2186] 13:28:20.448836 <... exit_group resumed>) = ?
[pid 2187] 13:28:20.448854 getpid() = 2187
[pid 2187] 13:28:20.448951 setsid( <unfinished ...>
[pid 2186] 13:28:20.449046 +++ exited with 0 +++
13:28:20.449055 <... setsid resumed> ) = 2187
13:28:20.449107 umask(000) = 022
13:28:20.449212 open("/dev/null", O_RDWR) = 8
13:28:20.449309 dup2(8, 0) = 0
13:28:20.449455 dup2(8, 1) = 1
13:28:20.449573 close(8) = 0
13:28:20.449692 open("/run/nginx/nginx.pid", O_RDWR|O_CREAT|O_TRUNC, 0644) = 8
13:28:20.449848 pwrite64(8, "2187\n", 5, 0) = 5
13:28:20.449978 close(8) = 0
13:28:20.450111 dup2(6, 2) = 2
13:28:20.450218 close(3) = 0
13:28:20.450376 rt_sigprocmask(SIG_BLOCK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], NULL, 8) = 0
13:28:20.450499 socketpair(AF_UNIX, SOCK_STREAM, 0, [3, 8]) = 0
13:28:20.450603 ioctl(3, FIONBIO, [1]) = 0
13:28:20.450696 ioctl(8, FIONBIO, [1]) = 0
13:28:20.450830 ioctl(3, FIOASYNC, [1]) = 0
13:28:20.450964 fcntl(3, F_SETOWN, 2187) = 0
13:28:20.451079 fcntl(3, F_SETFD, FD_CLOEXEC) = 0
13:28:20.451148 fcntl(8, F_SETFD, FD_CLOEXEC) = 0
13:28:20.451244 rt_sigprocmask(SIG_BLOCK, ~[], [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], 8) = 0
13:28:20.451379 fork(strace: Process 2188 attached
<unfinished ...>
[pid 2188] 13:28:20.451596 gettid( <unfinished ...>
[pid 2187] 13:28:20.451615 <... fork resumed> ) = 2188
[pid 2187] 13:28:20.451727 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], <unfinished ...>
[pid 2188] 13:28:20.451754 <... gettid resumed> ) = 2188
[pid 2187] 13:28:20.451774 <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 2188] 13:28:20.451942 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], <unfinished ...>
[pid 2187] 13:28:20.451969 rt_sigsuspend([], 8 <unfinished ...>
[pid 2188] 13:28:20.451985 <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 2188] 13:28:20.452053 getpid() = 2188
[pid 2188] 13:28:20.452330 rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], 8) = 0
[pid 2188] 13:28:20.452621 rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
[pid 2188] 13:28:20.452893 prlimit64(0, RLIMIT_NOFILE, {rlim_cur=8*1024, rlim_max=8*1024}, NULL) = 0
[pid 2188] 13:28:20.453075 futex(0x74ae1cf95064, FUTEX_WAKE_PRIVATE, 2147483647) = 0
[pid 2188] 13:28:20.453279 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], NULL, 8) = 0
[pid 2188] 13:28:20.453487 geteuid() = 0
[pid 2188] 13:28:20.453667 rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], 8) = 0
[pid 2188] 13:28:20.453861 rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
[pid 2188] 13:28:20.454091 setgid(103) = 0
[pid 2188] 13:28:20.454335 futex(0x74ae1cf95064, FUTEX_WAKE_PRIVATE, 2147483647) = 0
[pid 2188] 13:28:20.454583 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], NULL, 8) = 0
[pid 2188] 13:28:20.454822 socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 9
[pid 2188] 13:28:20.455183 connect(9, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 24) = -1 ENOENT (No such file or directory)
[pid 2188] 13:28:20.455537 close(9) = 0
[pid 2188] 13:28:20.455800 open("/etc/group", O_RDONLY|O_CLOEXEC) = 9
[pid 2188] 13:28:20.456030 fcntl(9, F_SETFD, FD_CLOEXEC) = 0
[pid 2188] 13:28:20.456331 fcntl(9, F_SETFD, FD_CLOEXEC) = 0
[pid 2188] 13:28:20.456544 readv(9, [{iov_base="", iov_len=0}, {iov_base="root:x:0:root\nbin:x:1:root,bin,d"..., iov_len=1024}], 2) = 776
[pid 2188] 13:28:20.456799 readv(9, [{iov_base="", iov_len=0}, {iov_base="", iov_len=1024}], 2) = 0
[pid 2188] 13:28:20.456956 close(9) = 0
[pid 2188] 13:28:20.457134 setgroups(3, [103, 82, 103]) = 0
[pid 2188] 13:28:20.457365 rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], 8) = 0
[pid 2188] 13:28:20.457534 rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
[pid 2188] 13:28:20.457818 setuid(102) = 0
[pid 2188] 13:28:20.457990 futex(0x74ae1cf95064, FUTEX_WAKE_PRIVATE, 2147483647) = 0
[pid 2188] 13:28:20.458159 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], NULL, 8) = 0
[pid 2188] 13:28:20.458378 prctl(PR_SET_DUMPABLE, SUID_DUMP_USER) = 0
[pid 2188] 13:28:20.458598 chdir("/var/www") = 0
[pid 2188] 13:28:20.458868 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[pid 2188] 13:28:20.459703 epoll_create1(0) = 9
[pid 2188] 13:28:20.459994 eventfd2(0, 0) = 10
[pid 2188] 13:28:20.460340 epoll_ctl(9, EPOLL_CTL_ADD, 10, {EPOLLIN|EPOLLET, {u32=1109208384, u64=14363479846208}}) = 0
[pid 2188] 13:28:20.460600 eventfd2(0, 0) = 11
[pid 2188] 13:28:20.460878 ioctl(11, FIONBIO, [1]) = 0
[pid 2188] 13:28:20.461043 io_setup(32, [0x74ae1ce79000]) = 0
[pid 2188] 13:28:20.461389 epoll_ctl(9, EPOLL_CTL_ADD, 11, {EPOLLIN|EPOLLET, {u32=1109208032, u64=14363479845856}}) = 0
[pid 2188] 13:28:20.461729 socketpair(AF_UNIX, SOCK_STREAM, 0, [12, 13]) = 0
[pid 2188] 13:28:20.462043 epoll_ctl(9, EPOLL_CTL_ADD, 12, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=1109208032, u64=14363479845856}}) = 0
[pid 2188] 13:28:20.462255 close(13) = 0
[pid 2188] 13:28:20.462608 epoll_pwait(9, [{EPOLLIN|EPOLLHUP|EPOLLRDHUP, {u32=1109208032, u64=14363479845856}}], 1, 5000, NULL, 8) = 1
[pid 2188] 13:28:20.462969 close(12) = 0
[pid 2188] 13:28:20.463325 mmap(NULL, 987136, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1bfaf000
[pid 2188] 13:28:20.463517 mmap(NULL, 397312, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1ce18000
[pid 2188] 13:28:20.464039 mmap(NULL, 397312, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1cdb7000
[pid 2188] 13:28:20.466039 epoll_ctl(9, EPOLL_CTL_ADD, 7, {EPOLLIN|EPOLLRDHUP, {u32=469430304, u64=128291142561824}}) = 0
[pid 2188] 13:28:20.466432 close(3) = 0
[pid 2188] 13:28:20.466763 epoll_ctl(9, EPOLL_CTL_ADD, 8, {EPOLLIN|EPOLLRDHUP, {u32=469430544, u64=128291142562064}}) = 0
//Eventloop starts here
[pid 2188] 13:28:20.467046 epoll_pwait(9, [{EPOLLIN, {u32=469430304, u64=128291142561824}}], 512, -1, NULL, 8) = 1
[pid 2188] 13:28:34.390021 accept4(7, {sa_family=AF_INET, sin_port=htons(54280), sin_addr=inet_addr("10.0.0.15")}, [112->16], SOCK_NONBLOCK) = 3
[pid 2188] 13:28:34.390110 epoll_ctl(9, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=469430784, u64=128291142562304}}) = 0
[pid 2188] 13:28:34.390188 epoll_pwait(9, [{EPOLLIN, {u32=469430784, u64=128291142562304}}], 512, 30000, NULL, 8) = 1
[pid 2188] 13:28:34.390245 recvfrom(3, "GET /index.html HTTP/1.0\r\nHost: "..., 2048, 0, NULL, NULL) = 93
[pid 2188] 13:28:34.390462 writev(3, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1"..., iov_len=142}], 1) = 142
[pid 2188] 13:28:34.390602 close(3) = 0
测试代码的跟踪:
localhost:/~# strace -tt -f ./test
18:07:49.511351 execve("./test", ["./test"], 0x735df8f6c0a0 /* 16 vars */) = 0
18:07:49.514382 arch_prctl(ARCH_SET_FS, 0x71a7644fdb88) = 0
18:07:49.515405 set_tid_address(0x71a7644fdbc0) = 2325
18:07:49.515983 mprotect(0x71a7644fa000, 4096, PROT_READ) = 0
18:07:49.516742 mprotect(0x322e536d000, 4096, PROT_READ) = 0
18:07:49.517329 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
18:07:49.518692 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
18:07:49.519955 bind(3, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
18:07:49.521092 listen(3, 511) = 0
18:07:49.521764 epoll_create1(EPOLL_CLOEXEC) = 4
18:07:49.522239 epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLRDHUP, {u32=3, u64=3}}) = 0
18:07:49.523392 epoll_pwait(4, [{EPOLLIN, {u32=3, u64=3}}], 512, -1, NULL, 8) = 1
18:07:52.616270 accept4(3, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK) = 5
18:07:52.617149 epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=5, u64=5}}) = 0
18:07:52.618188 epoll_pwait(4, [{EPOLLIN, {u32=5, u64=5}}], 512, -1, NULL, 8) = 1
18:07:52.619472 recvfrom(5, "GET /index.html HTTP/1.0\r\nHost: "..., 2048, 0, NULL, NULL) = 93
18:07:52.620474 writev(5, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1.12"..., iov_len=142}], 1) = 142
18:07:52.622846 close(5) = 0
编辑:
我做了更多的跟踪......来自远程主机的 400000 个请求......仍然不知道为什么会发生这种情况:
localhost:/~# strace -c -f /usr/sbin/nginx
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
47.11 0.040309 0 400000 writev
44.55 0.038115 0 400021 close
3.11 0.002658 0 400002 accept4
1.80 0.001538 0 400002 recvfrom
1.74 0.001486 0 400007 epoll_ctl
1.69 0.001450 0 400008 epoll_pwait
localhost:/~# strace -c -f ./test
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
47.90 0.042760 0 400002 writev
44.27 0.039518 0 400002 close
3.13 0.002793 0 400002 accept4
1.80 0.001610 0 400002 recvfrom
1.57 0.001400 0 400005 epoll_pwait
1.33 0.001183 0 400003 epoll_ctl
编辑:
正如评论部分所建议的那样,我再次测试了内存对齐...
localhost:~# strace -e raw=recvfrom,writev ./test
recvfrom(0x5, 0x7c7364ae2ee0, 0x800, 0, 0, 0) = 0x5d
writev(0x5, 0x7c7364ae1650, 0x1) = 0x69
localhost:~# strace -f -e raw=recvfrom,writev /usr/sbin/nginx
[pid 2381] recvfrom(0x3, 0x2344ebbd6a0, 0x800, 0, 0, 0) = 0x5d
[pid 2381] writev(0x3, 0x7df116c39f90, 0x1) = 0x86
编辑:
根据要求配置 nginx:
user nginx;
worker_processes 1;
working_directory /var/www;
events {
accept_mutex off;
worker_connections 4096;
}
http {
include /etc/nginx/mime.types;
server {
listen 8081;
server_name "10.0.0.110";
return 200;
}
}
简短回答:
有时更快意味着更慢。
长答案:
在单请求设置中(一次一个请求)epoll_wait
总是阻塞并强制上下文切换。客户端(在本例中为 ab
)必须接收并处理响应 + 在服务器再次唤醒之前发送下一个请求,并且 epoll_wait
return 挂起套接字。服务器生成响应的速度不会改变此行为,因为客户端总是在发送下一个请求之前等待服务器响应。
在多请求设置中,epoll_wait
是否强制上下文切换取决于服务器的性能。如果服务器应用程序速度较慢,则下一个请求已经在等待的可能性更高;在这种情况下,不需要上下文切换,因为 epoll_wait
可以立即 return。上下文切换很昂贵,并且可能需要比下一个请求到达浪费时间更长的时间。
当我通过将超时设置为零来消除 epoll_wait
进行上下文切换的机会时,我意识到了这一点。即使没有待处理的请求,这也会立即强制 epoll_wait
到 return(因此它从不等待,因此没有强制上下文切换)。在这种情况下,即使在多请求设置中,测试应用程序方式也优于 nginx。
我进一步证实了我的理论:
- 从 nginx 中删除工作(禁用访问日志)使其变慢
- 向测试应用程序(自旋循环)添加工作,使其更快
在多请求设置中。
为了这个答案,我重新进行了所有测量。所有测试都是在更新后的 ubuntu-box 上进行的 运行,具有 8 个内核(因此超过 5 个),同时在这台机器上使用服务器和客户端 运行。测试应用程序未更改。
- gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0
- nginx 版本:nginx/1.14.0 (Ubuntu)
我写了一个小脚本来得出下面的 request/second 数字,它运行 ab
60.000 个请求 100 次选择最快的结果。
maxRequests=0
for ((i = 0; i < 100; ++i)); do
requests=$(ab -n 60000 -c (1 or 4) http://127.0.0.1:8081/index.html 2>&1 | grep "Requests per second" | cut -d" " -f7)
requests=${requests%.*}
maxRequests=$(( maxRequests > requests ? maxRequests : requests ))
done
echo ${maxRequests}
这里再次使用与问题中相同设置的基值。
Requests per second: 13507 (test-application, 1c)
Requests per second: 27648 (test-application, 4c)
Requests per second: 11755 (nginx, 1c)
Requests per second: 31446 (nginx, 4c)
为了使 nginx 更快(因此使用 4c 更慢)我禁用了访问日志。
Requests per second: 12028 (nginx, 1c, no access-log)
Requests per second: 28976 (nginx, 4c, no access-log)
如果测试应用程序通过将 epool_wait
- 时间设置为零而永不休眠,则结果如下。
有趣的是 1c 设置的差异显示了在新请求到达时唤醒测试应用程序的成本。
Requests per second: 20079 (test-application, 1c, spinning)
Requests per second: 34522 (test-application, 4c, spinning)
对于这些最后的测量,我向测试应用程序添加了一些工作,人为地使其变慢以增加防止上下文切换的机会。我将下面的代码添加到内部 for 循环的末尾(在 close
之后)并改变 j
的初始值以获得不同的结果
uint8_t j = 50;
while (--j != 0) {
uint8_t i = 0;
while (--i != 0)
asm("");
}
Requests per second: 12910 (test-application, 1c, j=50)
Requests per second: 12126 (test-application, 1c, j=100)
Requests per second: 11634 (test-application, 1c, j=150)
Requests per second: 11020 (test-application, 1c, j=200)
Requests per second: 10235 (test-application, 1c, j=250)
Requests per second: 27447 (test-application, 4c, j=25)
Requests per second: 29464 (test-application, 4c, j=50)
Requests per second: 31334 (test-application, 4c, j=75)
Requests per second: 32079 (test-application, 4c, j=100)
Requests per second: 33510 (test-application, 4c, j=125)
Requests per second: 34241 (test-application, 4c, j=150)
Requests per second: 34189 (test-application, 4c, j=175)
Requests per second: 33855 (test-application, 4c, j=200)
Requests per second: 33328 (test-application, 4c, j=250)
我写了一些具有 epoll-eventloop 的代码,接受新连接并伪装成一个 http 服务器。 发布的代码是绝对最少的......我删除了所有内容(包括所有错误检查)以使其尽可能简短和切题:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <unistd.h>
int main () {
int servFd = socket (AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_IP);
int value = 1;
setsockopt (servFd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof (value));
struct sockaddr_in servAddr;
memset (&servAddr, 0, sizeof (servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = 0;
servAddr.sin_port = htons (8081);
bind (servFd, (struct sockaddr*)&servAddr, sizeof (servAddr));
listen (servFd, 511);
int efd = epoll_create1 (EPOLL_CLOEXEC);
struct epoll_event epollEvt;
epollEvt.events = EPOLLIN | EPOLLRDHUP;
epollEvt.data.u32 = servFd;
epoll_ctl (efd, EPOLL_CTL_ADD, servFd, &epollEvt);
for (;;) {
struct epoll_event pollEvent[512];
int eventCount = epoll_wait (efd, pollEvent, 512, -1);
for (int i = 0; i < eventCount; ++i) {
struct epoll_event* curEvent = &pollEvent[i];
if (curEvent->data.u32 == servFd) {
int clientFd = accept4 (servFd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
struct epoll_event epollEvt;
epollEvt.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
epollEvt.data.u32 = clientFd;
epoll_ctl (efd, EPOLL_CTL_ADD, clientFd, &epollEvt);
continue;
}
int clientFd = curEvent->data.u32;
char recvBuffer[2048];
recvfrom (clientFd, recvBuffer, 2048, 0, NULL, NULL);
char sndMsg[] = "HTTP/1.1 200 OK\r\nServer: nginx/1.12.2\r\nDate: Tue, 10 Apr 2018 17:41:57 GMT\r\nContent-Type: text/plain\r\nContent-Length: 0\r\nConnection: close\r\n\r\n";
size_t sndMsgLength = sizeof (sndMsg) - 1;
struct iovec sndBuffer;
sndBuffer.iov_base = sndMsg;
sndBuffer.iov_len = sndMsgLength;
writev (clientFd, &sndBuffer, 1);
close (clientFd);
}
}
return 0;
}
localhost:~# gcc -Wall -O2 test.c -o test
localhost:~# gcc --version
gcc (Alpine 6.4.0) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
我对这段代码做了一些负载测试,并将它与 nginx 进行了比较,看看我是否做错了什么或者是否有需要改进的地方。我希望这段代码是最快的实现,因为每个其他 "real" 网络服务器都必须在 userspace 中做更多的事情。但是仍然......在使用多个负载生成器线程时,nginx 在每秒请求数方面以某种方式击败了它。 (请注意,我将 nginx 配置为仅使用一个 worker 来处理每个请求)
//ab running 1 worker from local machine
localhost:~# ab -n 100000 -c 1 http://10.0.0.111:8081/index.html
Requests per second: 13228.07 [#/sec] (mean) //[to nginx]
Requests per second: 15300.35 [#/sec] (mean) //[to testcode]
//ab running 4 worker from local machine
localhost:~# ab -n 100000 -c 4 http://10.0.0.111:8081/index.html
Requests per second: 30902.63 [#/sec] (mean) //[to nginx]
Requests per second: 24734.76 [#/sec] (mean) //[to testcode]
第一个测试有预期的结果...测试代码速度更快,因为它除了生成硬编码响应外什么都不做。但是为什么 nginx 在多线程设置中更快呢?怎么可能?
我能想到的唯一解释是 kernel-space 中有些不同,nginx 使用了一些 sockopts(比如 TCP_FASTOPEN 或 TCP_DEFER_ACCEPT)或者其他一些系统调用做它的事。这就是为什么我做了一些 strace 并使我的代码做与 nginx 完全相同的事情(从内核角度来看)--> 你可以看到下面附加的 strace。仍然......它更快,我不明白为什么。
//ab running 50 worker from remote machine
localhost:~# ab -n 100000 -c 50 http://10.0.0.111:8081/index.html
Requests per second: 27507.60 [#/sec] (mean) //[to nginx]
Requests per second: 24208.51 [#/sec] (mean) //[to testcode]
这个测试转换有完全相同的结果,但我注意到 CPU-用法有些不同。
- 我的测试代码运行在大约 60% CPU-load 并且 ksoftirqd/0 运行在大约 80%
- nginx 以大约 99% CPU-load 运行而 ksoftirqd/0 仅以 30% 运行 在这两种情况下,
- ksoftirqd/0 在本地主机设置中没有明显的 CPU-负载
nginx的sTrace:
localhost:~# strace -tt -f /usr/sbin/nginx
//Removed loading of libraries to stay under the 30k char body limit for this question
13:28:20.426369 open("/etc/localtime", O_RDONLY|O_NONBLOCK|O_CLOEXEC) = 3
13:28:20.426549 fstat(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
13:28:20.426723 mmap(NULL, 127, PROT_READ, MAP_SHARED, 3, 0) = 0x74ae1cf8c000
13:28:20.426847 close(3) = 0
13:28:20.427023 getpid() = 2186
13:28:20.427164 open("/var/lib/nginx/logs/error.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 3
13:28:20.427341 brk(0xd104603e000) = 0xd104603e000
13:28:20.427503 open("/etc/ssl/openssl.cnf", O_RDONLY) = 4
13:28:20.427680 brk(0xd104603f000) = 0xd104603f000
13:28:20.427819 readv(4, [{iov_base="", iov_len=0}, {iov_base="[ req ]\n#default_bits\t\t= 2048\n#d"..., iov_len=1024}], 2) = 745
13:28:20.428089 brk(0xd1046040000) = 0xd1046040000
13:28:20.428243 readv(4, [{iov_base="", iov_len=0}, {iov_base="", iov_len=1024}], 2) = 0
13:28:20.428476 close(4) = 0
13:28:20.428718 brk(0xd1046041000) = 0xd1046041000
13:28:20.428880 brk(0xd1046042000) = 0xd1046042000
13:28:20.429179 brk(0xd1046043000) = 0xd1046043000
13:28:20.429319 brk(0xd1046044000) = 0xd1046044000
13:28:20.429552 brk(0xd1046045000) = 0xd1046045000
13:28:20.429775 brk(0xd1046046000) = 0xd1046046000
13:28:20.429935 brk(0xd1046047000) = 0xd1046047000
13:28:20.430220 brk(0xd1046048000) = 0xd1046048000
13:28:20.430391 brk(0xd1046049000) = 0xd1046049000
13:28:20.430515 brk(0xd104604b000) = 0xd104604b000
13:28:20.430796 brk(0xd104604c000) = 0xd104604c000
13:28:20.431042 brk(0xd104604d000) = 0xd104604d000
13:28:20.431238 brk(0xd104604e000) = 0xd104604e000
13:28:20.431396 brk(0xd104604f000) = 0xd104604f000
13:28:20.431581 brk(0xd1046050000) = 0xd1046050000
13:28:20.431820 brk(0xd1046051000) = 0xd1046051000
13:28:20.432112 brk(0xd1046054000) = 0xd1046054000
13:28:20.432374 brk(0xd1046055000) = 0xd1046055000
13:28:20.432509 brk(0xd1046056000) = 0xd1046056000
13:28:20.432666 brk(0xd1046057000) = 0xd1046057000
13:28:20.432836 brk(0xd1046058000) = 0xd1046058000
13:28:20.433004 brk(0xd1046059000) = 0xd1046059000
13:28:20.433203 brk(0xd104605a000) = 0xd104605a000
13:28:20.433400 brk(0xd104605b000) = 0xd104605b000
13:28:20.433610 brk(0xd104605c000) = 0xd104605c000
13:28:20.433740 brk(0xd104605d000) = 0xd104605d000
13:28:20.433895 brk(0xd104605e000) = 0xd104605e000
13:28:20.434020 brk(0xd104605f000) = 0xd104605f000
13:28:20.434240 brk(0xd1046060000) = 0xd1046060000
13:28:20.434419 brk(0xd1046061000) = 0xd1046061000
13:28:20.434622 uname({sysname="Linux", nodename="localhost", ...}) = 0
13:28:20.434801 sched_getaffinity(0, 128, [0, 1, 2, 3, 4, 5]) = 32
13:28:20.435077 prlimit64(0, RLIMIT_NOFILE, NULL, {rlim_cur=1024, rlim_max=4*1024}) = 0
13:28:20.435260 brk(0xd1046066000) = 0xd1046066000
13:28:20.435424 uname({sysname="Linux", nodename="localhost", ...}) = 0
13:28:20.435578 brk(0xd104606b000) = 0xd104606b000
13:28:20.435700 open("/etc/nginx/nginx.conf", O_RDONLY) = 4
13:28:20.435912 fstat(4, {st_mode=S_IFREG|0644, st_size=2781, ...}) = 0
13:28:20.436115 pread64(4, "\n\n\nuser nginx;\npcre_jit on;\n#tim"..., 2781, 0) = 2781
13:28:20.436284 geteuid() = 0
13:28:20.436440 open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 5
13:28:20.436596 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.436725 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.436857 readv(5, [{iov_base="", iov_len=0}, {iov_base="root:x:0:0:root:/root:/bin/ash\nb"..., iov_len=1024}], 2) = 1024
13:28:20.437047 readv(5, [{iov_base="", iov_len=0}, {iov_base="sbin/nologin\nntp:x:123:123:NTP:/"..., iov_len=1024}], 2) = 397
13:28:20.437235 lseek(5, -43, SEEK_CUR) = 1378
13:28:20.437353 close(5) = 0
13:28:20.437520 open("/etc/group", O_RDONLY|O_CLOEXEC) = 5
13:28:20.437684 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.437800 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.437933 readv(5, [{iov_base="", iov_len=0}, {iov_base="root:x:0:root\nbin:x:1:root,bin,d"..., iov_len=1024}], 2) = 776
13:28:20.438097 close(5) = 0
13:28:20.438240 epoll_create1(0) = 5
13:28:20.438429 close(5) = 0
13:28:20.438681 brk(0xd1046070000) = 0xd1046070000
13:28:20.438842 brk(0xd1046072000) = 0xd1046072000
13:28:20.439053 brk(0xd1046074000) = 0xd1046074000
13:28:20.439175 brk(0xd1046076000) = 0xd1046076000
13:28:20.439418 brk(0xd104607b000) = 0xd104607b000
13:28:20.439655 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1ce8b000
13:28:20.439886 brk(0xd1046080000) = 0xd1046080000
13:28:20.440020 brk(0xd1046085000) = 0xd1046085000
13:28:20.440225 open("/etc/nginx/mime.types", O_RDONLY) = 5
13:28:20.440380 fstat(5, {st_mode=S_IFREG|0644, st_size=3957, ...}) = 0
13:28:20.440523 pread64(5, "\ntypes {\n text/html "..., 3957, 0) = 3957
13:28:20.440725 close(5) = 0
13:28:20.440977 brk(0xd104608a000) = 0xd104608a000
13:28:20.441297 brk(0xd104608c000) = 0xd104608c000
13:28:20.441453 close(4) = 0
13:28:20.441587 mkdir("/var/tmp/nginx/client_body", 0700) = -1 EEXIST (File exists)
13:28:20.441814 stat("/var/tmp/nginx/client_body", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.442022 mkdir("/var/tmp/nginx/proxy", 0700) = -1 EEXIST (File exists)
13:28:20.442149 stat("/var/tmp/nginx/proxy", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.442257 mkdir("/var/tmp/nginx/fastcgi", 0700) = -1 EEXIST (File exists)
13:28:20.442407 stat("/var/tmp/nginx/fastcgi", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.442568 mkdir("/var/tmp/nginx/uwsgi", 0700) = -1 EEXIST (File exists)
13:28:20.442732 stat("/var/tmp/nginx/uwsgi", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.442945 mkdir("/var/tmp/nginx/scgi", 0700) = -1 EEXIST (File exists)
13:28:20.443051 stat("/var/tmp/nginx/scgi", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13:28:20.443229 open("/var/log/nginx/access.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 4
13:28:20.443417 fcntl(4, F_SETFD, FD_CLOEXEC) = 0
13:28:20.443586 open("/var/log/nginx/error.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 5
13:28:20.443750 fcntl(5, F_SETFD, FD_CLOEXEC) = 0
13:28:20.443889 open("/var/lib/nginx/logs/error.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = 6
13:28:20.444040 fcntl(6, F_SETFD, FD_CLOEXEC) = 0
13:28:20.444197 mmap(NULL, 2097152, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0x74ae1c0a0000
13:28:20.444382 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 7
13:28:20.444515 setsockopt(7, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
13:28:20.444680 ioctl(7, FIONBIO, [1]) = 0
13:28:20.444808 bind(7, {sa_family=AF_INET, sin_port=htons(8081), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
13:28:20.445015 listen(7, 511) = 0
13:28:20.445140 listen(7, 511) = 0
13:28:20.445326 mmap(NULL, 65536, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1ce7b000
13:28:20.445493 prlimit64(0, RLIMIT_NOFILE, NULL, {rlim_cur=1024, rlim_max=4*1024}) = 0
13:28:20.445671 mmap(NULL, 1280, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0x74ae1ce7a000
13:28:20.445817 rt_sigprocmask(SIG_UNBLOCK, [RT_1 RT_2], NULL, 8) = 0
13:28:20.445977 rt_sigaction(SIGHUP, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446097 rt_sigaction(SIGUSR1, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446247 rt_sigaction(SIGWINCH, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446438 rt_sigaction(SIGTERM, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446635 rt_sigaction(SIGQUIT, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.446886 rt_sigaction(SIGUSR2, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447093 rt_sigaction(SIGALRM, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447236 rt_sigaction(SIGINT, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447446 rt_sigaction(SIGIO, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447767 rt_sigaction(SIGCHLD, {sa_handler=0xd1041f1f3fc, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.447888 rt_sigaction(SIGSYS, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.448094 rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x74ae1cd4a6cf}, NULL, 8) = 0
13:28:20.448253 rt_sigprocmask(SIG_BLOCK, ~[], [], 8) = 0
13:28:20.448396 fork(strace: Process 2187 attached
) = 2187
[pid 2187] 13:28:20.448594 gettid( <unfinished ...>
[pid 2186] 13:28:20.448643 rt_sigprocmask(SIG_SETMASK, [], <unfinished ...>
[pid 2187] 13:28:20.448671 <... gettid resumed> ) = 2187
[pid 2186] 13:28:20.448700 <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 2187] 13:28:20.448765 rt_sigprocmask(SIG_SETMASK, [], <unfinished ...>
[pid 2186] 13:28:20.448792 exit_group(0 <unfinished ...>
[pid 2187] 13:28:20.448812 <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 2186] 13:28:20.448836 <... exit_group resumed>) = ?
[pid 2187] 13:28:20.448854 getpid() = 2187
[pid 2187] 13:28:20.448951 setsid( <unfinished ...>
[pid 2186] 13:28:20.449046 +++ exited with 0 +++
13:28:20.449055 <... setsid resumed> ) = 2187
13:28:20.449107 umask(000) = 022
13:28:20.449212 open("/dev/null", O_RDWR) = 8
13:28:20.449309 dup2(8, 0) = 0
13:28:20.449455 dup2(8, 1) = 1
13:28:20.449573 close(8) = 0
13:28:20.449692 open("/run/nginx/nginx.pid", O_RDWR|O_CREAT|O_TRUNC, 0644) = 8
13:28:20.449848 pwrite64(8, "2187\n", 5, 0) = 5
13:28:20.449978 close(8) = 0
13:28:20.450111 dup2(6, 2) = 2
13:28:20.450218 close(3) = 0
13:28:20.450376 rt_sigprocmask(SIG_BLOCK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], NULL, 8) = 0
13:28:20.450499 socketpair(AF_UNIX, SOCK_STREAM, 0, [3, 8]) = 0
13:28:20.450603 ioctl(3, FIONBIO, [1]) = 0
13:28:20.450696 ioctl(8, FIONBIO, [1]) = 0
13:28:20.450830 ioctl(3, FIOASYNC, [1]) = 0
13:28:20.450964 fcntl(3, F_SETOWN, 2187) = 0
13:28:20.451079 fcntl(3, F_SETFD, FD_CLOEXEC) = 0
13:28:20.451148 fcntl(8, F_SETFD, FD_CLOEXEC) = 0
13:28:20.451244 rt_sigprocmask(SIG_BLOCK, ~[], [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], 8) = 0
13:28:20.451379 fork(strace: Process 2188 attached
<unfinished ...>
[pid 2188] 13:28:20.451596 gettid( <unfinished ...>
[pid 2187] 13:28:20.451615 <... fork resumed> ) = 2188
[pid 2187] 13:28:20.451727 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], <unfinished ...>
[pid 2188] 13:28:20.451754 <... gettid resumed> ) = 2188
[pid 2187] 13:28:20.451774 <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 2188] 13:28:20.451942 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], <unfinished ...>
[pid 2187] 13:28:20.451969 rt_sigsuspend([], 8 <unfinished ...>
[pid 2188] 13:28:20.451985 <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 2188] 13:28:20.452053 getpid() = 2188
[pid 2188] 13:28:20.452330 rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], 8) = 0
[pid 2188] 13:28:20.452621 rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
[pid 2188] 13:28:20.452893 prlimit64(0, RLIMIT_NOFILE, {rlim_cur=8*1024, rlim_max=8*1024}, NULL) = 0
[pid 2188] 13:28:20.453075 futex(0x74ae1cf95064, FUTEX_WAKE_PRIVATE, 2147483647) = 0
[pid 2188] 13:28:20.453279 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], NULL, 8) = 0
[pid 2188] 13:28:20.453487 geteuid() = 0
[pid 2188] 13:28:20.453667 rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], 8) = 0
[pid 2188] 13:28:20.453861 rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
[pid 2188] 13:28:20.454091 setgid(103) = 0
[pid 2188] 13:28:20.454335 futex(0x74ae1cf95064, FUTEX_WAKE_PRIVATE, 2147483647) = 0
[pid 2188] 13:28:20.454583 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], NULL, 8) = 0
[pid 2188] 13:28:20.454822 socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 9
[pid 2188] 13:28:20.455183 connect(9, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 24) = -1 ENOENT (No such file or directory)
[pid 2188] 13:28:20.455537 close(9) = 0
[pid 2188] 13:28:20.455800 open("/etc/group", O_RDONLY|O_CLOEXEC) = 9
[pid 2188] 13:28:20.456030 fcntl(9, F_SETFD, FD_CLOEXEC) = 0
[pid 2188] 13:28:20.456331 fcntl(9, F_SETFD, FD_CLOEXEC) = 0
[pid 2188] 13:28:20.456544 readv(9, [{iov_base="", iov_len=0}, {iov_base="root:x:0:root\nbin:x:1:root,bin,d"..., iov_len=1024}], 2) = 776
[pid 2188] 13:28:20.456799 readv(9, [{iov_base="", iov_len=0}, {iov_base="", iov_len=1024}], 2) = 0
[pid 2188] 13:28:20.456956 close(9) = 0
[pid 2188] 13:28:20.457134 setgroups(3, [103, 82, 103]) = 0
[pid 2188] 13:28:20.457365 rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1 RT_2], [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], 8) = 0
[pid 2188] 13:28:20.457534 rt_sigprocmask(SIG_BLOCK, ~[], NULL, 8) = 0
[pid 2188] 13:28:20.457818 setuid(102) = 0
[pid 2188] 13:28:20.457990 futex(0x74ae1cf95064, FUTEX_WAKE_PRIVATE, 2147483647) = 0
[pid 2188] 13:28:20.458159 rt_sigprocmask(SIG_SETMASK, [HUP INT QUIT USR1 USR2 ALRM TERM CHLD WINCH IO], NULL, 8) = 0
[pid 2188] 13:28:20.458378 prctl(PR_SET_DUMPABLE, SUID_DUMP_USER) = 0
[pid 2188] 13:28:20.458598 chdir("/var/www") = 0
[pid 2188] 13:28:20.458868 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[pid 2188] 13:28:20.459703 epoll_create1(0) = 9
[pid 2188] 13:28:20.459994 eventfd2(0, 0) = 10
[pid 2188] 13:28:20.460340 epoll_ctl(9, EPOLL_CTL_ADD, 10, {EPOLLIN|EPOLLET, {u32=1109208384, u64=14363479846208}}) = 0
[pid 2188] 13:28:20.460600 eventfd2(0, 0) = 11
[pid 2188] 13:28:20.460878 ioctl(11, FIONBIO, [1]) = 0
[pid 2188] 13:28:20.461043 io_setup(32, [0x74ae1ce79000]) = 0
[pid 2188] 13:28:20.461389 epoll_ctl(9, EPOLL_CTL_ADD, 11, {EPOLLIN|EPOLLET, {u32=1109208032, u64=14363479845856}}) = 0
[pid 2188] 13:28:20.461729 socketpair(AF_UNIX, SOCK_STREAM, 0, [12, 13]) = 0
[pid 2188] 13:28:20.462043 epoll_ctl(9, EPOLL_CTL_ADD, 12, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=1109208032, u64=14363479845856}}) = 0
[pid 2188] 13:28:20.462255 close(13) = 0
[pid 2188] 13:28:20.462608 epoll_pwait(9, [{EPOLLIN|EPOLLHUP|EPOLLRDHUP, {u32=1109208032, u64=14363479845856}}], 1, 5000, NULL, 8) = 1
[pid 2188] 13:28:20.462969 close(12) = 0
[pid 2188] 13:28:20.463325 mmap(NULL, 987136, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1bfaf000
[pid 2188] 13:28:20.463517 mmap(NULL, 397312, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1ce18000
[pid 2188] 13:28:20.464039 mmap(NULL, 397312, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x74ae1cdb7000
[pid 2188] 13:28:20.466039 epoll_ctl(9, EPOLL_CTL_ADD, 7, {EPOLLIN|EPOLLRDHUP, {u32=469430304, u64=128291142561824}}) = 0
[pid 2188] 13:28:20.466432 close(3) = 0
[pid 2188] 13:28:20.466763 epoll_ctl(9, EPOLL_CTL_ADD, 8, {EPOLLIN|EPOLLRDHUP, {u32=469430544, u64=128291142562064}}) = 0
//Eventloop starts here
[pid 2188] 13:28:20.467046 epoll_pwait(9, [{EPOLLIN, {u32=469430304, u64=128291142561824}}], 512, -1, NULL, 8) = 1
[pid 2188] 13:28:34.390021 accept4(7, {sa_family=AF_INET, sin_port=htons(54280), sin_addr=inet_addr("10.0.0.15")}, [112->16], SOCK_NONBLOCK) = 3
[pid 2188] 13:28:34.390110 epoll_ctl(9, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=469430784, u64=128291142562304}}) = 0
[pid 2188] 13:28:34.390188 epoll_pwait(9, [{EPOLLIN, {u32=469430784, u64=128291142562304}}], 512, 30000, NULL, 8) = 1
[pid 2188] 13:28:34.390245 recvfrom(3, "GET /index.html HTTP/1.0\r\nHost: "..., 2048, 0, NULL, NULL) = 93
[pid 2188] 13:28:34.390462 writev(3, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1"..., iov_len=142}], 1) = 142
[pid 2188] 13:28:34.390602 close(3) = 0
测试代码的跟踪:
localhost:/~# strace -tt -f ./test
18:07:49.511351 execve("./test", ["./test"], 0x735df8f6c0a0 /* 16 vars */) = 0
18:07:49.514382 arch_prctl(ARCH_SET_FS, 0x71a7644fdb88) = 0
18:07:49.515405 set_tid_address(0x71a7644fdbc0) = 2325
18:07:49.515983 mprotect(0x71a7644fa000, 4096, PROT_READ) = 0
18:07:49.516742 mprotect(0x322e536d000, 4096, PROT_READ) = 0
18:07:49.517329 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
18:07:49.518692 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
18:07:49.519955 bind(3, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
18:07:49.521092 listen(3, 511) = 0
18:07:49.521764 epoll_create1(EPOLL_CLOEXEC) = 4
18:07:49.522239 epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLRDHUP, {u32=3, u64=3}}) = 0
18:07:49.523392 epoll_pwait(4, [{EPOLLIN, {u32=3, u64=3}}], 512, -1, NULL, 8) = 1
18:07:52.616270 accept4(3, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK) = 5
18:07:52.617149 epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=5, u64=5}}) = 0
18:07:52.618188 epoll_pwait(4, [{EPOLLIN, {u32=5, u64=5}}], 512, -1, NULL, 8) = 1
18:07:52.619472 recvfrom(5, "GET /index.html HTTP/1.0\r\nHost: "..., 2048, 0, NULL, NULL) = 93
18:07:52.620474 writev(5, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1.12"..., iov_len=142}], 1) = 142
18:07:52.622846 close(5) = 0
编辑:
我做了更多的跟踪......来自远程主机的 400000 个请求......仍然不知道为什么会发生这种情况:
localhost:/~# strace -c -f /usr/sbin/nginx
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
47.11 0.040309 0 400000 writev
44.55 0.038115 0 400021 close
3.11 0.002658 0 400002 accept4
1.80 0.001538 0 400002 recvfrom
1.74 0.001486 0 400007 epoll_ctl
1.69 0.001450 0 400008 epoll_pwait
localhost:/~# strace -c -f ./test
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
47.90 0.042760 0 400002 writev
44.27 0.039518 0 400002 close
3.13 0.002793 0 400002 accept4
1.80 0.001610 0 400002 recvfrom
1.57 0.001400 0 400005 epoll_pwait
1.33 0.001183 0 400003 epoll_ctl
编辑:
正如评论部分所建议的那样,我再次测试了内存对齐...
localhost:~# strace -e raw=recvfrom,writev ./test
recvfrom(0x5, 0x7c7364ae2ee0, 0x800, 0, 0, 0) = 0x5d
writev(0x5, 0x7c7364ae1650, 0x1) = 0x69
localhost:~# strace -f -e raw=recvfrom,writev /usr/sbin/nginx
[pid 2381] recvfrom(0x3, 0x2344ebbd6a0, 0x800, 0, 0, 0) = 0x5d
[pid 2381] writev(0x3, 0x7df116c39f90, 0x1) = 0x86
编辑:
根据要求配置 nginx:
user nginx;
worker_processes 1;
working_directory /var/www;
events {
accept_mutex off;
worker_connections 4096;
}
http {
include /etc/nginx/mime.types;
server {
listen 8081;
server_name "10.0.0.110";
return 200;
}
}
简短回答:
有时更快意味着更慢。
长答案:
在单请求设置中(一次一个请求)epoll_wait
总是阻塞并强制上下文切换。客户端(在本例中为 ab
)必须接收并处理响应 + 在服务器再次唤醒之前发送下一个请求,并且 epoll_wait
return 挂起套接字。服务器生成响应的速度不会改变此行为,因为客户端总是在发送下一个请求之前等待服务器响应。
在多请求设置中,epoll_wait
是否强制上下文切换取决于服务器的性能。如果服务器应用程序速度较慢,则下一个请求已经在等待的可能性更高;在这种情况下,不需要上下文切换,因为 epoll_wait
可以立即 return。上下文切换很昂贵,并且可能需要比下一个请求到达浪费时间更长的时间。
当我通过将超时设置为零来消除 epoll_wait
进行上下文切换的机会时,我意识到了这一点。即使没有待处理的请求,这也会立即强制 epoll_wait
到 return(因此它从不等待,因此没有强制上下文切换)。在这种情况下,即使在多请求设置中,测试应用程序方式也优于 nginx。
我进一步证实了我的理论:
- 从 nginx 中删除工作(禁用访问日志)使其变慢
- 向测试应用程序(自旋循环)添加工作,使其更快
在多请求设置中。
为了这个答案,我重新进行了所有测量。所有测试都是在更新后的 ubuntu-box 上进行的 运行,具有 8 个内核(因此超过 5 个),同时在这台机器上使用服务器和客户端 运行。测试应用程序未更改。
- gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0
- nginx 版本:nginx/1.14.0 (Ubuntu)
我写了一个小脚本来得出下面的 request/second 数字,它运行 ab
60.000 个请求 100 次选择最快的结果。
maxRequests=0
for ((i = 0; i < 100; ++i)); do
requests=$(ab -n 60000 -c (1 or 4) http://127.0.0.1:8081/index.html 2>&1 | grep "Requests per second" | cut -d" " -f7)
requests=${requests%.*}
maxRequests=$(( maxRequests > requests ? maxRequests : requests ))
done
echo ${maxRequests}
这里再次使用与问题中相同设置的基值。
Requests per second: 13507 (test-application, 1c)
Requests per second: 27648 (test-application, 4c)
Requests per second: 11755 (nginx, 1c)
Requests per second: 31446 (nginx, 4c)
为了使 nginx 更快(因此使用 4c 更慢)我禁用了访问日志。
Requests per second: 12028 (nginx, 1c, no access-log)
Requests per second: 28976 (nginx, 4c, no access-log)
如果测试应用程序通过将 epool_wait
- 时间设置为零而永不休眠,则结果如下。
有趣的是 1c 设置的差异显示了在新请求到达时唤醒测试应用程序的成本。
Requests per second: 20079 (test-application, 1c, spinning)
Requests per second: 34522 (test-application, 4c, spinning)
对于这些最后的测量,我向测试应用程序添加了一些工作,人为地使其变慢以增加防止上下文切换的机会。我将下面的代码添加到内部 for 循环的末尾(在 close
之后)并改变 j
的初始值以获得不同的结果
uint8_t j = 50;
while (--j != 0) {
uint8_t i = 0;
while (--i != 0)
asm("");
}
Requests per second: 12910 (test-application, 1c, j=50)
Requests per second: 12126 (test-application, 1c, j=100)
Requests per second: 11634 (test-application, 1c, j=150)
Requests per second: 11020 (test-application, 1c, j=200)
Requests per second: 10235 (test-application, 1c, j=250)
Requests per second: 27447 (test-application, 4c, j=25)
Requests per second: 29464 (test-application, 4c, j=50)
Requests per second: 31334 (test-application, 4c, j=75)
Requests per second: 32079 (test-application, 4c, j=100)
Requests per second: 33510 (test-application, 4c, j=125)
Requests per second: 34241 (test-application, 4c, j=150)
Requests per second: 34189 (test-application, 4c, j=175)
Requests per second: 33855 (test-application, 4c, j=200)
Requests per second: 33328 (test-application, 4c, j=250)