问题
后台是 云服务器 ECS + Nginx + PHP 。服务器配置比较低好像是2核4GB,后台提供接口,供前台Node.js和路由器插件(小米,极路由等)以及安卓客户端调用。
路由器插件端和安卓客户端的一个逻辑就是要请求后台获取 sn,再通过sn做其它操作。那么如果获取不到 sn 的时候,就会 10s 之后继续请求,这就是问题的根源。
产品刚刚上线,大约有两万台小米路由器设备于凌晨4点钟重启,不断地请求获取 sn 接口。后台就挂了, Nginx 502 bad gateway, PHP-FPM 进程数过多。
路由器插件在用户端,并不能做任何修改,只能是在后台优化使其能接受 20K 的 QPS。
为什么选择 OenResty
可以搭负载均衡,但是当前只是单个接口访问量特别高,单个服务器的性能并没有发挥到极致。
后来我就发现了 OpenResty ,可以用这个尝试下,然后我们先看下官网的描述。可以方便地搭建处理超高并发,看起来是我想要的。
OpenResty是一个基于与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
OpenResty 开发
OpenResty学习的话推荐一本小册子 OpenResty 最佳实践,讲的很好。
有以下要注意的几个点:
- Lua 的 数字都是 float 型,不能直接和字符串做比较。那么从 URL 接受的值要执行数字相关操作的话,就要先将其转为数字
local page = tonumber(arg['page'])
- Lua 中执行 sql 查询出来就是 table ,查询出来就是多条数据的形式。并且其下标都是从1开始的。
local id = 1000
res, err, errno, sqlstate = db:query(
string.format([[select name from user where id = %d ]], id)
)
if not res then
ngx.say("failed to connect: ", err, ": ", errno, " ", sqlstate)
return
else
name = res[1]['name']
ngx.say("name is ", name)
end
我最难受的是OenResty 中的调试只能是通过 Nginx 的 error.log,每次出了问题都要看日志。可能是我现在还不知道 OpenResty 如何开发才是最合适的,如果你有更好的方式一定要告诉我。
总结
如果是某些简单的业务,可以用 Lua 重写,可以极大提高性能,快来体验下吧。