加载中...

阻塞操作


阻塞操作

Openresty的诞生,一直对外宣传是非阻塞(100% noblock)的。基于事件通知的Nginx给我们带来了足够强悍的高并发支持,但是也对我们的编码有特殊要求。这个特殊要求就是我们的代码,也必须是非阻塞的。如果你的服务端编程生涯一开始就是从异步框架开始的,恭喜你了。但如果你的编程生涯是从同步框架过来的,而且又是刚刚开始深入了解异步框架,那你就要小心了。

Nginx为了减少系统上下文切换,它的worker是用单进程单线程设计的,事实证明这种做法运行效率很高。Nginx要么是在等待网络讯号,要么就是在处理业务(请求数据解析、过滤、内容应答等),没有任何额外资源消耗。

常见语言代表异步框架

  • Golang :使用协程技术实现
  • Python :gevent基于协程的Python网络库
  • Rust :用的少,只知道语言完备支持异步框架
  • Openresty:基于Nginx,使用事件通知机制
  • Java :Netty,使用网络事件通知机制

异步编程的噩梦

异步编程,如果从零开始,难度是非常大的。一个完整的请求,由于网络传输的非连续性,这个请求要被多次挂起、恢复、运行,一旦网络有新数据到达,都需要立刻唤醒恢复原始请求处于运行状态。开发人员不仅仅要考虑异步api接口本身的使用规范,还要考虑业务会话的完整处理,稍有不慎,全盘皆输。

最最重要的噩梦是,我们好不容易搞定异步框架和业务会话完整性,但是却在我们的业务会话上使用了阻塞函数。一开始没有任何感知,只有做压力测试的时候才发现我们的并发量上不去,各种卡曼顿,甚至开始怀疑人生:异步世界也就这样。

Openresty中的阻塞函数

官方有明确说明,Openresty的官方API绝对100% noblock,所以我们只能在她的外面寻找了。我这里大致归纳总结了一下,包含下面几种情况:

  • 高CPU的调用(压缩、解压缩、加解密等)
  • 高磁盘的调用(所有文件操作)
  • 非Openresty提供的网络操作(luasocket等)
  • 系统命令行调用(os.execute等)

这些都应该是我们尽量要避免的。理想丰满,现实骨感,谁能保证我们的应用中不使用这些类型的API?没人保证,我们能做的就是把他们的调用数量、频率降低再降低,如果还是不能满足我们需要,那么就考虑把他们封装成独立服务,对外提供TCP/HTTP级别的接口调用,这样我们的Openresty就可以同时享受异步编程的好处又能达到我们的目的。


还没有评论.