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直接做会阻塞的操作。

当前有两个想法:

  1. 把文件上传服务,单独抽离出来,不要跟业务逻辑服务放在一起
  2. OpenResty收到客户端上传的文件之后,转发给文件上传服务器,让文件上传服务器去做磁盘操作。

心得

所以不要使用OpenResty去做一些可能会阻塞的操作,比如下面的一些操作

  1. 高CPU的调用(压缩、解压缩、加解密)
  2. 高磁盘的调用(所有的文件操作)
  3. 非OpenResty提供的网络操作(luasocket等)
  4. 系统命令行调用(os.excute等)