先看一个最简单的超高性能 hello world http 服务器:
require "socket"
s = TCPServer.new '127.0.0.1', 3000
s.listen 10000
loop do
io = s.accept
content = 'hello world'
io << "HTTP/1.1 200 OK
Content-Type: text/html; utf-8
Connection: close
Content-Length: #{content.size}
#{content}"
io.close
end
我的机器上占用内存十多兆,ab 测下大约 10000 request/s, 和 C 写的差别不大,完爆各种 goroutine STM async***... c10k 解决了!... 那到底是什么东西拖慢了服务器的响应呢?
五花八门的应用服务器做的事情,说白了就是用来解析请求 header 的... rack 提供了这么多工具这么多层,说白了就是用来组装响应 header 的...
如果加上 ruby 写的 http 请求解析,直接就掉到 1000 req/s 的层次去了。所以这部分还是倾向于用 C 去做。这里有两个选择,一个是 thin / mongrel 用的基于状态机的 http parser, 另一个是 eventmachine / nodejs 用的基于事件的 http parser, 不管选哪个,都能比较好的改良性能,还能保持 5000 request/s 左右。
一般模板也有 50000/s 以上的渲染速度,对组装 response 的影响不大...
外部调用延迟都比较大,为了不让服务器被单请求阻塞,需要一个 multiplexing 方案,我们这些一辈子都碰不上 c10k 问题的屌丝,多线程甚至一个 fork 就够了...
改良版 hello world 服务器,unicorn 架构 ...
require "socket"
s = TCPServer.new '127.0.0.1', 3000
s.listen 10000
6.times do
fork {
loop do
io = s.accept
content = 'hello world'
io << "HTTP/1.1 200 OK
Content-Type: text/html; utf-8
Connection: close
Content-Length: #{content.size}
#{content}"
io.close
end
}
end
Process.waitall
10 几年前 aio_ 系列的函数一度被推崇,但现在大家都在踩 aio, 推 epoll / kqueue 了... 但是 kqueue 不能 share 给子进程,epoll 每次只取出 1 个事件,都有它们自己的问题,事件框架包装后又都显得比较慢...
另外顺带提下 prefork eventmachine 进程的简单解决方案: https://gist.github.com/rkh/1102809
rails dispatch 很慢,解决方案就是页面静态化和 etag rails helper 很慢,解决方案就是页面片段缓存 active record 很慢,解决方案就是对象缓存 devise 很慢,解决方案就是不用 devise ...
毕竟加点缓存有 20 req/s 就已经能撑起巨大流量的应用了...
igvita 刚整的 slides, 比这个帖子有价值多了... http://www.igvita.com/slides/2013/fluent-perfcourse.pdf
还有这本新书,趁免费赶紧看呀! http://chimera.labs.oreilly.com/books/1230000000545/index.html
sysctl net.ipv4.tcp_window_scaling
.sysctl net.ipv4.tcp_slow_start_after_idle
ss --options --extended --memory --processes --inf