事情的起因是这样的,我希望用skynet做webserver来承载大量的web请求,并把请求发送到后端或者从后端取数据。 后端的瓶颈不是问题,不管是memcached,或者redis,或者kafka。 这是一个轻cpu运算,重吞吐量的应用场景。
于是我测试了skynet作为http echo server的能力, echo server比较简单
一个service 监听连接,并把请求发送给broker处理
for i= 1, broker_n do
broker[i] = assert(skynet.newservice("broker"))
end
local address = skynet.getenv "listen"
skynet.error("Listening "..address)
local id = assert(socket.listen(address))
local balance = 1
socket.start(id , function(id, addr)
skynet.send(broker[balance], "lua", id, addr)
balance = balance + 1
if balance > #broker then
balance = 1
end
end)
broker处理http请求,返回ok
local function handle_socket(id)
local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(id), 8192)
if code then
if url == "/echo" then
response(id, 200, "ok")
end
。。。。
通过局域网的另一台机器,对这个服务进行ab压力测试
ab -n 100000 -c 2000 -r
http://ip:8888/echo &
无论是调整ab进程数量,或者connection数量, 请求数量大约在2w左右每秒 达到瓶颈
26896 root 20 0 341m 103m 1188 R 87.1 0.2 0:07.90 skynet
26905 root 20 0 341m 103m 1188 S 13.2 0.2 0:01.11 skynet
26908 root 20 0 341m 103m 1188 S 13.2 0.2 0:01.16 skynet
26898 root 20 0 341m 103m 1188 R 12.9 0.2 0:01.24 skynet
26912 root 20 0 341m 103m 1188 S 12.9 0.2 0:01.20 skynet
26900 root 20 0 341m 103m 1188 S 12.6 0.2 0:01.24 skynet
26906 root 20 0 341m 103m 1188 S 12.3 0.2 0:01.02 skynet
26909 root 20 0 341m 103m 1188 S 12.3 0.2 0:01.02 skynet
26910 root 20 0 341m 103m 1188 S 12.3 0.2 0:01.03 skynet
26907 root 20 0 341m 103m 1188 S 11.9 0.2 0:01.17 skynet
26911 root 20 0 341m 103m 1188 S 11.6 0.2 0:00.99 skynet
26899 root 20 0 341m 103m 1188 S 11.3 0.2 0:01.12 skynet
26897 root 20 0 341m 103m 1188 S 10.6 0.2 0:01.05 skynet
26904 root 20 0 341m 103m 1188 S 10.6 0.2 0:00.97 skynet
26901 root 20 0 341m 103m 1188 S 10.3 0.2 0:00.95 skynet
26902 root 20 0 341m 103m 1188 S 9.9 0.2 0:00.94 skynet
26903 root 20 0 341m 103m 1188 R 8.9 0.2 0:00.92 skynet
通过在thread_socket 线程函数里 打印出tid( gettid()) 可以确认第一个占用cpu接近90%的线程是thread_socket
这时候替换服务器为swoole,同样的echo server,每秒大约能处理4w请求, 多的没有测试。
swoole
的做法是:它有多个Reactor线程来真正处理TCP连接,收发数据。swoole的主线程在Accept新的连接后,会将这个连接分配给一个固定的
Reactor线程,并由这个线程负责监听此socket。在socket可读时读取数据,并进行协议解析,将请求投递到Worker进程。在
socket可写时将数据发送给TCP客户端。
分配的计算方式是fd % serv->reactor_num
那么问题来了,作为一个skynet粉希望用skynet做更多的事情,
如果skynet也采用这种方法,比如启动多个thread_socket, accept到新的连接后,通过message queue,把fd传递给某个thread_socket, 这样是否会提升skynet的适用场景,或者有无其他比较好的方案。