我试图把比约恩位于 Nginx 后面,可轻松实现负载平衡和缓解 DoS/DDoS 攻击。
令我沮丧的是,我不仅发现它像芯片一样掉线(占总连接数的 20% 到 50% 之间),而且当不落后于它时,它似乎实际上更快。
这是在具有 6GB RAM 和双核 2Ghz CPU 的机器上进行的测试。
我的应用程序是这样的:
import bjoern,redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
val = r.get('test:7')
def hello_world(environ, start_response):
status = '200 OK'
res = val
response_headers = [
('Content-type','text/plain'),
('Content-Length',str(len(res)))]
start_response(status, response_headers)
return [res]
# despite the name this is not a hello world as you can see
bjoern.run(hello_world, 'unix:/tmp/bjoern.sock')
Nginx 配置:
user www-data;
worker_processes 2;
worker_rlimit_nofile 52000; # worker_connections * 2
pid /run/nginx.pid;
events {
multi_accept on;
worker_connections 18000;
use epoll;
}
http {
charset utf-8;
client_body_timeout 65;
client_header_timeout 65;
client_max_body_size 10m;
default_type application/octet-stream;
keepalive_timeout 20;
reset_timedout_connection on;
send_timeout 65;
server_tokens off;
sendfile on;
server_names_hash_bucket_size 64;
tcp_nodelay off;
tcp_nopush on;
error_log /var/log/nginx/error.log;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
和虚拟主机:
upstream backend {
server unix:/tmp/bjoern.sock;
}
server {
listen 80;
server_name _;
error_log /var/log/nginx/error.log;
location / {
proxy_buffering off;
proxy_redirect off;
proxy_pass http://backend;
}
}
我得到的 Bjoern 通过 unix socket 对 Nginx 进行基准测试如下:
Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software: nginx
Server Hostname: 127.0.0.1
Server Port: 80
Document Path: /
Document Length: 148 bytes
Concurrency Level: 1000
Time taken for tests: 0.983 seconds
Complete requests: 10000
Failed requests: 3
(Connect: 0, Receive: 0, Length: 3, Exceptions: 0)
Non-2xx responses: 3
Total transferred: 3000078 bytes
HTML transferred: 1480054 bytes
Requests per second: 10170.24 [#/sec] (mean)
Time per request: 98.326 [ms] (mean)
Time per request: 0.098 [ms] (mean, across all concurrent requests)
Transfer rate: 2979.64 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 15 4.8 15 35
Processing: 11 28 19.2 19 223
Waiting: 7 24 20.4 16 218
Total: 16 43 20.0 35 225
Percentage of the requests served within a certain time (ms)
50% 35
66% 38
75% 40
80% 40
90% 79
95% 97
98% 109
99% 115
100% 225 (longest request)
每秒 10k 个请求,这次失败的请求较少,但仍然......
当 Bjoern 直接受到打击时,基准测试结果如下:
更改bjoern.run(hello_world, 'unix:/tmp/bjoern.sock')
为bjoern.run(hello_world, "127.0.0.1", 8000)
Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software:
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /
Document Length: 148 bytes
Concurrency Level: 100
Time taken for tests: 0.193 seconds
Complete requests: 10000
Failed requests: 0
Keep-Alive requests: 10000
Total transferred: 2380000 bytes
HTML transferred: 1480000 bytes
Requests per second: 51904.64 [#/sec] (mean)
Time per request: 1.927 [ms] (mean)
Time per request: 0.019 [ms] (mean, across all concurrent requests)
Transfer rate: 12063.77 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.3 0 4
Processing: 1 2 0.4 2 5
Waiting: 0 2 0.4 2 5
Total: 1 2 0.5 2 5
Percentage of the requests served within a certain time (ms)
50% 2
66% 2
75% 2
80% 2
90% 2
95% 3
98% 4
99% 4
100% 5 (longest request)
每秒 50k 个请求,在这种情况下甚至没有失败的请求。
我已经广泛调整了系统变量,例如索迈斯康等等,如果不是这样,我认为无论如何我不会单独与 Bjoern 收到那么多请求。
Bjoern 怎么可能比 Nginx 快这么多呢?
我真的很担心无法使用 Nginx 并从第一行概述的内容中受益,希望您能帮助我找到罪魁祸首。
简短而简洁的问题是:如何在不损失性能的情况下将 Bjoern 代理到 Nginx?我是否应该继续使用 Bjoern 并以其他方式实现负载平衡和 DoS/DDoS 攻击缓解?
答案1
我认为下面的文章给出了答案。
https://news.ycombinator.com/item?id=2036661
例如,让我们考虑一下这个思维实验:有人在这里提到 Mongrel2 每秒获得 4000 个请求。让我们将名称“Mongrel2”替换为“服务器 A”,因为这个思维实验不仅限于 Mongrel2,而是所有服务器。我假设他在笔记本电脑上对 hello world 应用程序进行基准测试。假设服务器 B“仅”获得 2000 个请求/秒。现在人们可能会(错误地)得出以下结论:
服务器B慢很多。
在高流量的生产环境中,应该使用服务器 A 而不是服务器 B。
现在将服务器 A 置于 HAProxy 后面。HAproxy 被称为高性能 HTTP 代理服务器,开销极小。对此设置进行基准测试,并观察请求/秒下降到大约 2000-3000(在典型的双核笔记本电脑上进行基准测试时)。
刚刚发生了什么?服务器 B 似乎非常慢。但实际情况是,服务器 A 和服务器 B 都非常快,即使进行最少量的额外工作也会对 req/sec 数产生重大影响。在这种情况下,额外的上下文切换和对内核的 read()/write() 调用的开销已经足以使 req/sec 数下降一半。任何相当复杂的 Web 应用程序逻辑都会使该数字下降很多,以至于不同服务器之间的性能差异变得可以忽略不计。