Nginx与阻塞操作
借用"OpenResty最佳实践"的话
https://moonbingbing.gitbooks.io/openresty-best-practices/ngx_lua/block_io.html
Nginx 为了减少系统上下文切换,它的 worker 是用单进程单线程设计的,事实证明这种做法运行效率很高。
Nginx 要么是在等待网络讯号,要么就是在处理业务(请求数据解析、过滤、内容应答等),没有任何额外资源消耗。
举个栗子
最近在做app的数据上报后台服务,当前有这样一个需求,客户端想上传一些文件(日志文件、订单回执等)。
后台服务用的是OpenResty,使用了它的upload模块(好像是春哥写的),客户端使用http协议post方法上传文件。
其中比较蛋疼的一个问题如下:
我想把客户端上传的文件,按照用户id,上传时间存入到每个用户独立的文件夹中。
比如A用户的id是123456789,那我收到client上传的文件后,写入 /data/upload/123456789/20170909/ 文件夹下面。
那就得去创建这个文件夹,最初我是在lua脚本中调用 os.excute("mkdir -p /data/upload/123456789/20170909")
后来想想,这样做不是不行,当然可以实现功能。
但是应该这样做吗?肯定不应该这样做的。
前面说了 Nginx 是单进程、单线程设计,像文件上传这种写磁盘(相比业务逻辑运算)非常慢的操作,如果让Nginx去做,业务处理能力就会大打折扣。
类似的,磁盘操作/阻塞式网络操作/系统调用等,都是比较慢的,尽量想想其他好的方案去代替Nginx直接做会阻塞的操作。
当前有两个想法:
- 把文件上传服务,单独抽离出来,不要跟业务逻辑服务放在一起
- OpenResty收到客户端上传的文件之后,转发给文件上传服务器,让文件上传服务器去做磁盘操作。
心得
所以不要使用OpenResty去做一些可能会阻塞的操作,比如下面的一些操作
- 高CPU的调用(压缩、解压缩、加解密)
- 高磁盘的调用(所有的文件操作)
- 非OpenResty提供的网络操作(luasocket等)
- 系统命令行调用(os.excute等)