OpenResty从入门到实战
温铭
OpenResty软件基金会主席,《OpenResty 最佳实践》作者
立即订阅
4332 人已学习
课程目录
已完结 52 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | OpenResty,为你打开高性能开发的大门
免费
入门篇 (14讲)
01 | 初探OpenResty的三大特性
02 | 如何写出你的“hello world”?
03 | 揪出隐藏在背后的那些子项目
04 | 如何管理第三方包?从包管理工具luarocks和opm说起
05 | [视频]opm项目导读
06 | OpenResty 中用到的 NGINX 知识
07 | 带你快速上手 Lua
08 | LuaJIT分支和标准Lua有什么不同?
09 | 为什么 lua-resty-core 性能更高一些?
10 | JIT编译器的死穴:为什么要避免使用 NYI ?
11 | 剖析Lua唯一的数据结构table和metatable特性
12 | 高手秘诀:识别Lua的独有概念和坑
13 | [视频]实战:基于FFI实现的lua-resty-lrucache
14 | 答疑(一):Lua 规则和 NGINX 配置文件产生冲突怎么办?
API篇 (11讲)
15 | OpenResty 和别的开发平台有什么不同?
16 | 秒杀大多数开发问题的两个利器:文档和测试案例
17 | 为什么能成为更好的Web服务器?动态处理请求和响应是关键
18 | worker间的通信法宝:最重要的数据结构之shared dict
19 | OpenResty 的核心和精髓:cosocket
20 | 超越 Web 服务器:特权进程和定时任务
21 | 带你玩转时间、正则表达式等常用API
22 | [视频]从一个安全漏洞说起,探寻API性能和安全的平衡
23 | [视频]导读lua-resty-requests:优秀的lua-resty-*是如何编写的?
24 | 实战:处理四层流量,实现Memcached Server
25 | 答疑(二):特权进程的权限到底是什么?
测试篇 (5讲)
26 | 代码贡献者的拦路虎:test::nginx 简介
27 | test::nginx 包罗万象的测试方法
28 | test::nginx 还可以这样用?
29 | 最容易失准的性能测试?你需要压测工具界的“悍马”wrk
30 | 答疑(三)如何搭建测试的网络结构?
性能优化篇 (16讲)
31 | 性能下降10倍的真凶:阻塞函数
32 | 让人又恨又爱的字符串操作
33 | 性能提升10倍的秘诀:必须用好 table
34 | 特别放送:OpenResty编码指南
35 | [视频]实际项目中的性能优化:ingress-nginx中的几个PR解读
36 | 盘点OpenResty的各种调试手段
37 | systemtap-toolkit和stapxx:如何用数据搞定“疑难杂症”?
38 | [视频]巧用wrk和火焰图,科学定位性能瓶颈
39 | 高性能的关键:shared dict 缓存和 lru 缓存
40 | 缓存与风暴并存,谁说缓存风暴不可避免?
41 | lua-resty-* 封装,让你远离多级缓存之痛
42 | 如何应对突发流量:漏桶和令牌桶的概念
43 | 灵活实现动态限流限速,其实没有那么难
44 | OpenResty 的杀手锏:动态
45 | 不得不提的能力外延:OpenResty常用的第三方库
46 | 答疑(四):共享字典的缓存是必须的吗?
API网关篇 (4讲)
47 | 微服务API网关搭建三步曲(一)
48 | 微服务API网关搭建三步曲(二)
49 | 微服务API网关搭建三步曲(三)
50 | 答疑(五):如何在工作中引入 OpenResty?
结束语 (1讲)
结束语 | 行百里者半九十
OpenResty从入门到实战
登录|注册

19 | OpenResty 的核心和精髓:cosocket

温铭 2019-07-08
你好,我是温铭,今天我们来学习下 OpenResty 中的核心技术:cosocket。
其实在前面的课程中,我们就已经多次提到过它了,cosocket 是各种 lua-resty-* 非阻塞库的基础,没有 cosocket,开发者就无法用 Lua 来快速连接各种外部的网络服务。
在早期的 OpenResty 版本中,如果你想要去与 Redis、memcached 这些服务交互的话,需要使用 redis2-nginx-moduleredis-nginx-modulememc-nginx-module这些 C 模块. 这些模块至今仍然在 OpenResty 的发行包中。
不过,cosocket 功能加入以后,它们都已经被 lua-resty-redislua-resty-memcached 替代,基本上没人再去使用 C 模块连接外部服务了。

什么是 cosocket?

那究竟什么是 cosocket 呢?事实上,cosocket 是 OpenResty 中的专有名词,是把协程和网络套接字的英文拼在一起形成的,即 cosocket = coroutine + socket。所以,你可以把 cosocket 翻译为“协程套接字”。
cosocket 不仅需要 Lua 协程特性的支持,也需要 Nginx 中非常重要的事件机制的支持,这两者结合在一起,最终实现了非阻塞网络 I/O。另外,cosocket 支持 TCP、UDP 和 Unix Domain Socket。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《OpenResty从入门到实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(8)

  • 回家
    问题一:将表格利用cjson进行序列化之后发送
    问题二:通过设置定时器,在不能使用cosocket的阶段使用

    作者回复: 第二个答案是对的。第一个确实是可以的,但并非最好的方案,send 函数不仅支持字符串,还支持 table,这也是隐藏的优化点。

    2019-07-08
    1
    1
  • wusiration
    问题一:将table通过cjson序列化,但是看到老师有说send函数支持table,查阅api文档有说The input argument data can either be a Lua string or a (nested) Lua table holding string fragments.In case of table arguments, this method will copy all the string elements piece by piece to the underlying Nginx socket send buffers, which is usually optimal than doing string concatenation operations on the Lua land.
    问题二:通过shared dict进行数据传递

    作者回复: 接收 table 而非字符串,是 OpenResty Lua API 的一个重要的优化点。
    通过shared dict进行数据传递,这个我不是很明白,这个是如何绕过限制的呢?

    2019-07-13
    1
  • 小超人
    有个真实需求:
    client --密文--> Openresty解密 --明文--> server
    client <--密文-- Openresty加密 <--明文-- server
    1. 这是TCP应用,send/recv不一定是一对儿,比如有个大请求,client需要send 10次以后再收;
    2. Openresty知道client发过来的密文格式,带total_len,可以正常receive(total_len)就可以了;
    3. 【问题】Openresty不知道业务数据格式,在receive上游服务器时,遇到两个问题:
    *3.1* 不知道什么时候receive,如1.描述,Openresty将明文转发至server时,server不一定有返回数据;
    *3.2*如果来了数据,不知道该收多少,因为不知道业务数据的格式。
    【我现在的做法是】
    1. Openresty receive server那一侧,设置了一个buf_len,和一个较小的超时,比如200ms;
    2. Openresty每转发一次数据到server,都尝试receive一下server,如果超时,不报错不返回;如果receive到数据了,就加密返回后再循环receive,直到无数据(超时);
    这样虽然解决了问题,但是性能太差了,在openresty---server那一侧,至少要receive超时一次,才能知道收完数据了。
    【请问】有更好的解决办法吗?

    作者回复: 我理解了你的问题,尝试回答下,不一定准确:
    1. client 会传上来 total_len,那么 OpenResty 就能计算出来第几次 send 是最后一次。在最后一次 client send 的数据解密并转发给上游 server 后,开始 receive server。是否可以解决呢?
    2. 这个有有些尴尬了,即使OpenResty 不关心数据格式,至少也要知道数据长度或者结束符,这两个的其中一个。不然无法知道何时结束。

    2019-07-13
    2
  • helloworld
    老师:
    [error] 16239#16239: *5 attempt to send data on a closed socket: u:0000000000000000, c:0000000000000000
    客户端每次post数据过来,lua都可以正确的将数据写入redis,但是error.log日志中总是报这个错误。
    老师,我没用到redis连接池,我这个应用场景是每隔一段时间post请求往redis写数据,所以没必要使用连接池。关于redis的语句只有下面这些:
    local redis = require "resty.redis"
    local red = redis:new()
    red:set_timemout(2000) -- 2 sec
    local ip = "127.0.0.1"
    local port = 6379
    local ok, err = red:connect(ip, port)
    if not ok then
        ...
    end
    ok, err = red:hset(data_time, client, json_encode(data))
    if not ok then
        ...
    end

    作者回复: 建议在 redis:new() 的时候判断下是否成功。
    另外附上 OpenResty 作者给这个错误的排查意见:https://github.com/openresty/lua-resty-redis/issues/27#issuecomment-28166754,自然是更加权威的。

    2019-07-12
    1
  • helloworld
    [error] 16239#16239: *5 attempt to send data on a closed socket: u:0000000000000000, c:0000000000000000
    客户端每次post数据过来,lua都可以正确的将数据写入redis,但是error.log日志中总是报这个错误,求解。

    作者回复: 是否使用了redis 的连接池?猜测连接池里面有不正常的连接,但是被复用了。可以确认下放进连接池之前,代码中是否判断了连接是否正常?

    2019-07-08
  • helloworld
    老师,是不是不论在哪个阶段运行ngx.say('hello'),都会在执行完本阶段剩余代码后直接响应给客户端,不会继续执行其他阶段了。我测试是这样的。

    作者回复: 并不是,你可以看下它的执行阶段的顺序图:https://github.com/moonbingbing/openresty-best-practices/blob/master/images/openresty_phases.png,你可以做这个测试,在 content 里面 ngx.say,然后在 log 或者 body filter 阶段打印下日志试试。

    2019-07-08
    1
  • 回家
    文中利用cosocket将TCP请求发送到www.baidu.com的例子,我运行了一下包含头域Host:www.baidu.com和不包含该头域的请求,抓包来看,也确实是一个包含Host头域,一个不包含,两个请求都能得到百度的200应答。有一个问题是,我在本地使用proxy,然后转upstream时,如果不指定请求头域为请求到的域名的话,就不能得到正确的应答。这里是我写的关于这个问题的博客链接:https://blog.csdn.net/u013139008/article/details/94732537 介绍这个问题。老师,你知道这里必须要指定头域是www.baidu.com的原因吗?

    作者回复:
    一般来说,一个 ip 上可能会运行多个网站,所以会通过 server name 来做区分,比如 Nginx 中的 server 这个指令。如果没有设置
     proxy_set_header Host "www.baidu.com";
    的话,在路由的时候就可能会找不到 server。

    2019-07-08
    1
  • helloworld
    👍
    2019-07-08
收起评论
8
返回
顶部