- Socket 编程发展
- OpenResty 简介
- Lua 入门
- Nginx
- 子查询
- 不同阶段共享变量
- 防止 SQL 注入
- 如何发起新 HTTP 请求
- 访问有授权验证的 Redis
- select+set_keepalive 组合操作引起的数据读写错误
- redis 接口的二次封装(简化建连、拆连等细节)
- redis 接口的二次封装(发布订阅)
- pipeline 压缩请求数量
- script 压缩复杂请求
- 动态生成的 lua-resty-redis 模块方法
- LuaCjsonLibrary
- json解析的异常捕获
- 稀疏数组
- 空table编码为array还是object
- PostgresNginxModule
- 调用方式简介
- 不支持事务
- 超时
- 健康监测
- SQL注入
- LuaNginxModule
- 执行阶段概念
- 正确的记录日志
- 热装载代码
- 阻塞操作
- 缓存
- sleep
- 定时任务
- 禁止某些终端访问
- 请求返回后继续执行
- 调试
- 请求中断后的处理
- 我的 lua 代码需要调优么
- 变量的共享范围
- 动态限速
- shared.dict 非队列性质
- 正确使用长链接
- 如何引用第三方 resty 库
- 典型应用场景
- 怎样理解 cosocket
- 如何安全启动唯一实例的 timer
- 如何正确的解析域名
- LuaRestyDNSLibrary
- 使用动态 DNS 来完成 HTTP 请求
- LuaRestyLock
- 缓存失效风暴
- HTTPS 时代
- 动态加载证书和 OCSP stapling
- TLS session resumption
- 测试
- Web 服务
- 火焰图
- 如何定位问题
- module 是邪恶的
- FFI
- 什么是 JIT
阻塞操作
OpenResty 的诞生,一直对外宣传是同步非阻塞(100% non-blocking)的。基于事件通知的 Nginx 给我们带来了足够强悍的高并发支持,但是也对我们的编码有特殊要求。这个特殊要求就是我们的代码,也必须是非阻塞的。如果你的服务端编程生涯一开始就是从异步框架开始的,恭喜你了。但如果你的编程生涯是从同步框架过来的,而且又是刚刚开始深入了解异步框架,那你就要小心了。
Nginx 为了减少系统上下文切换,它的 worker 是用单进程单线程设计的,事实证明这种做法运行效率很高。Nginx 要么是在等待网络讯号,要么就是在处理业务(请求数据解析、过滤、内容应答等),没有任何额外资源消耗。
常见语言代表异步框架
- Golang:使用协程技术实现
- Python:gevent 基于协程的 Python 网络库
- Rust:用的少,只知道语言完备支持异步框架
- OpenResty:基于 Nginx,使用事件通知机制
- Java:Netty,使用网络事件通知机制
异步编程的噩梦
异步编程,如果从零开始,难度是非常大的。一个完整的请求,由于网络传输的非连续性,这个请求要被多次挂起、恢复、运行,一旦网络有新数据到达,都需要立刻唤醒恢复原始请求处于运行状态。开发人员不仅仅要考虑异步 API 接口本身的使用规范,还要考虑业务请求的完整处理,稍有不慎,全盘皆输。
最最重要的噩梦是,我们好不容易搞定异步框架和业务请求完整性,但是却在我们的业务请求上使用了阻塞函数。一开始没有任何感知,只有做压力测试的时候才发现我们的并发量上不去,各种卡顿,甚至开始怀疑人生:异步世界也就这样。
OpenResty 中的阻塞函数
官方有明确说明,OpenResty 的官方 API 绝对 100% non-blocking,所以我们只能在她的外面寻找了。我这里大致归纳总结了一下,包含下面几种情况:
- 高 CPU 的调用(压缩、解压缩、加解密等)
- 高磁盘的调用(所有文件操作)
- 非 OpenResty 提供的网络操作(luasocket 等)
- 系统命令行调用(os.execute 等)
这些都应该是我们尽量要避免的。理想丰满,现实骨感,谁能保证我们的应用中不使用这些类型的 API?没人保证,我们能做的就是把他们的调用数量、频率降低再降低,如果还是不能满足我们需要,那么就考虑把他们封装成独立服务,对外提供 TCP/HTTP 级别的接口调用,这样我们的 OpenResty 就可以同时享受异步编程的好处又能达到我们的目的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论