nginx tcp lua module

941 views
Skip to first unread message

Simon

unread,
Nov 15, 2012, 2:13:17 AM11/15/12
to openresty
https://github.com/bigplum/nginx-tcp-lua-module

移植了很多ngx-lua模块的代码,接口和api基本上原封不动抄过来,lua-resty-redis模块可以直接运行。

简单写了一个redis-proxy测试了下性能,单进程处理能力总体上约比redis降低了60%左右,不过nginx强在有多进程,做redis
sharding还是没问题。想来做mysql-proxy应该也没问题。

移植过程还是挺happy的,很多代码拷贝过来改改就能用,哈哈

smallfish

unread,
Nov 15, 2012, 2:18:55 AM11/15/12
to open...@googlegroups.com
赞。之前和 agentzh 也聊过 tcp 实现的东西,这样的话可以在 nginx 层面不管是 tcp 还是 http 都可以做很多事情。
--


2012/11/15 Simon <big...@gmail.com>

ldmiao

unread,
Nov 15, 2012, 2:45:12 AM11/15/12
to open...@googlegroups.com
赞!一直在关注 nginx lua tcp 的实现。

看到你提到移植了很多ngx-lua的代码,这个项目(nginx-tcp-lua-module)会 和 春哥的 lua-nginx-module 在代码级别上保持同步更新吗?
会有 lua-nginx-module 类似的测试用例来保证质量吗?

抱歉,可能问题有点多,但确实是我很关心的。

Simon

unread,
Nov 15, 2012, 5:29:55 AM11/15/12
to openresty
同步更新比较困难,但是后面会逐渐合入lua-nginx-module的thread等新特性,慢慢更新代码到最新版本

测试用例目前移植了一部分测试主要功能,lua-nginx-module的用例太多了。。。我在考虑写个工具批量把测试用例转换过来

Demiao Lin

unread,
Nov 15, 2012, 5:52:03 AM11/15/12
to open...@googlegroups.com
多谢回复!

我会持续关注的。


2012/11/15 Simon <big...@gmail.com>

agentzh

unread,
Dec 1, 2012, 3:10:04 PM12/1/12
to open...@googlegroups.com
Hello!

2012/11/14 Simon:


> https://github.com/bigplum/nginx-tcp-lua-module
>
> 移植了很多ngx-lua模块的代码,接口和api基本上原封不动抄过来,lua-resty-redis模块可以直接运行。
>
> 简单写了一个redis-proxy测试了下性能,单进程处理能力总体上约比redis降低了60%左右,不过nginx强在有多进程,做redis
> sharding还是没问题。想来做mysql-proxy应该也没问题。
>

哈哈!没想到你这么快就搞定原型实现了!热烈祝贺!

> 移植过程还是挺happy的,很多代码拷贝过来改改就能用,哈哈
>

呵呵,真好 :)

后面我找时间看看能否把你的工作融合回 ngx_http_lua_module,希望二者之间能复用尽可能多的代码,以避免同时维护两份非常相近的代码之苦,呵呵。

Thanks!
-agentzh

Simon

unread,
Dec 3, 2012, 8:14:27 AM12/3/12
to open...@googlegroups.com
确实有很多代码重复,与request无关的代码可以直接移植,与request相关的代码比较麻烦。可以考虑把请求无关的代码独立成小模块,这样tcp也可以作为一个模块,和http共用一些基础设施。貌似春哥之前考虑过拆分ngx-lua模块的吧?

这两天在考虑收敛连接的问题,无论是upstream keepalive还是cosocket,每个请求都会对应一个后端连接,所以碰到海量push的情况,即使协议上支持,ngx用于后端连接的端口也会不够用。前面有个帖子讨论过,一时找不到了。收敛连接还有个好处就是适合用于做数据库代理。

想了两个方案,感觉都不是太好:
1. 另外起进程用于和后端服务器通信,通过share mem在lua之间传递数据
2. 在worker启动的时候运行一个lua,用于连接后端服务器;在这个lua和请求处理的lua之间,通过两个队列,完成生产者和消费者的处理模型。

在 2012年12月2日星期日UTC+8上午4时10分04秒,agentzh写道:

agentzh

unread,
Dec 3, 2012, 2:45:38 PM12/3/12
to open...@googlegroups.com
Hello!

2012/12/3 Simon:
> 确实有很多代码重复,与request无关的代码可以直接移植,与request相关的代码比较麻烦。

是的。

> 可以考虑把请求无关的代码独立成小模块,这样tcp也可以作为一个模块,和http共用一些基础设施。貌似春哥之前考虑过拆分ngx-lua模块的吧?
>

拆分可以解决一部分问题,比如 ngx.re.*, ngx.shared.*, ngx.md5, ngx.time
之类的很容易拆分出来。ngx_lua 的拆分或许会发生在 ngx_lua 2.0 版本中 :) 但是 coroutine.*,
ngx.thread, ngx.flush, ngx.sleep 等和调度器紧密集成的特性目前还不太好拆分出来;我需要再多想想 :)

> 这两天在考虑收敛连接的问题,无论是upstream
> keepalive还是cosocket,每个请求都会对应一个后端连接,所以碰到海量push的情况,即使协议上支持,ngx用于后端连接的端口也会不够用。前面有个帖子讨论过,一时找不到了。收敛连接还有个好处就是适合用于做数据库代理。
>
> 想了两个方案,感觉都不是太好:
> 1. 另外起进程用于和后端服务器通信,通过share mem在lua之间传递数据
> 2. 在worker启动的时候运行一个lua,用于连接后端服务器;在这个lua和请求处理的lua之间,通过两个队列,完成生产者和消费者的处理模型。
>

你说的是这个主题吗?

https://groups.google.com/group/openresty/browse_thread/thread/fd07882f42d08203/20f023da04fbcc38

我觉得你的两个方案中第二个方案效率应当更高一些,实现上也容易很多。

由于我感觉这种技术的具体实现强烈依赖于特定的后端通讯协议;我不太清楚是否有很好的抽象方法可以将之实现为 Lua 级别上比较通用的框架或 API.

Best regards,
-agentzh

Simon

unread,
Dec 3, 2012, 9:18:05 PM12/3/12
to open...@googlegroups.com
是这个主题,确实依赖协议,需求比较独特

 

pengqi

unread,
Dec 3, 2012, 11:31:25 PM12/3/12
to openresty
Hi,

最近我在做一个与后端通讯的模块也需要这种技术,cosocket现有的方式实现不了,还只能用c模块来做。
这种需求貌似还是挺多的,后端服务器如果只能提供有限的连接资源,而前端有大量的客户机时,实现单连接同时并发多请求的功能就显得非常重要了。
一般这种协议会提供一个id来标识一个session,一个session用来处理一个请求(一发一回),同一连接上可以同时并发多个session。cosocket最好能抽象出连接及session的概念,并提供一个get_session_id的钩子,用户可以设置这个钩子用于从自定义协议中解析id,ngx_lua得到此id之后,可以得到相应的session,session里面保存相应的请求数据,这样就可以resume对应的请求。


是这个主题,确实依赖协议,需求比较独特

 
--



--
Jinglong
Software Engineer
Server Platforms Team at Taobao

agentzh

unread,
Dec 4, 2012, 2:14:23 PM12/4/12
to open...@googlegroups.com
Hello!

2012/12/3 pengqi:


>
> 最近我在做一个与后端通讯的模块也需要这种技术,cosocket现有的方式实现不了,还只能用c模块来做。
> 这种需求貌似还是挺多的,后端服务器如果只能提供有限的连接资源,而前端有大量的客户机时,实现单连接同时并发多请求的功能就显得非常重要了。

同意。这个特性值得加入 ngx_lua cosocket 中 :)

> 一般这种协议会提供一个id来标识一个session,一个session用来处理一个请求(一发一回),同一连接上可以同时并发多个session。

你能列举出有哪些比较典型的开源服务使用了这种连接多路复用技术?或许我们可以先针对这些服务尝试设计对应的 lua-resty-* 客户端及其需要的 API.

> cosocket最好能抽象出连接及session的概念,并提供一个get_session_id的钩子,用户可以设置这个钩子用于从自定义协议中解析id,ngx_lua得到此id之后,可以得到相应的session,session里面保存相应的请求数据,这样就可以resume对应的请求。
>

我可以想象这种类型的协议一般会定义更上层的 packet 的概念,颇有些在 TCP 协议之上再实现一个自定义的 UDP 协议的感觉 :)

但显然我们需要足够多的真实世界里的协议实例来进行有效的模型抽象 :)

Best regards,
-agentzh

pengqi

unread,
Dec 5, 2012, 1:39:49 AM12/5/12
to openresty
hi,


在 2012年12月5日 上午3:14,agentzh <age...@gmail.com>写道:
Hello!

2012/12/3 pengqi:
>
> 最近我在做一个与后端通讯的模块也需要这种技术,cosocket现有的方式实现不了,还只能用c模块来做。
> 这种需求貌似还是挺多的,后端服务器如果只能提供有限的连接资源,而前端有大量的客户机时,实现单连接同时并发多请求的功能就显得非常重要了。

同意。这个特性值得加入 ngx_lua cosocket 中 :)

> 一般这种协议会提供一个id来标识一个session,一个session用来处理一个请求(一发一回),同一连接上可以同时并发多个session。

你能列举出有哪些比较典型的开源服务使用了这种连接多路复用技术?或许我们可以先针对这些服务尝试设计对应的 lua-resty-* 客户端及其需要的 API.

淘宝内部很多服务都用了这种技术,比如hsf,tair(基于tbnet协议实现单连接多路复用,内部很多服务都使用tbnet作为网络库),tair是开源的但是我们内部已经做了nginx c版本的客户端。
最好能够再抽象出类似nginx upstream的负载均衡层,很多分布式服务都是configure server + 多个data server,从cf server获取data server地址列表,负载均衡层可以对多个ip来做轮询或者hash。

tbnet:

tair:
 
> cosocket最好能抽象出连接及session的概念,并提供一个get_session_id的钩子,用户可以设置这个钩子用于从自定义协议中解析id,ngx_lua得到此id之后,可以得到相应的session,session里面保存相应的请求数据,这样就可以resume对应的请求。
>

我可以想象这种类型的协议一般会定义更上层的 packet 的概念,颇有些在 TCP 协议之上再实现一个自定义的 UDP 协议的感觉 :)

但显然我们需要足够多的真实世界里的协议实例来进行有效的模型抽象 :)

Best regards,
-agentzh

agentzh

unread,
Dec 5, 2012, 2:54:13 PM12/5/12
to open...@googlegroups.com
Hello!

2012/12/4 pengqi:


>
> 淘宝内部很多服务都用了这种技术,比如hsf,tair(基于tbnet协议实现单连接多路复用,内部很多服务都使用tbnet作为网络库),tair是开源的但是我们内部已经做了nginx
> c版本的客户端。
> 最好能够再抽象出类似nginx upstream的负载均衡层,很多分布式服务都是configure server + 多个data server,从cf
> server获取data server地址列表,负载均衡层可以对多个ip来做轮询或者hash。
>
> tbnet:
> http://code.taobao.org/p/tb-common-utils/src/trunk/tbnet/
>
> tair:
> http://tair.taobao.org/
>

tbnet 使用的线路协议可以作为一个参考实例,不过我们显然还需要更多的实例来进行恰当的抽象,否则容易就变成针对 tbnet
的专有机制了,呵呵。这里的错误处理和资源管理等方面的细节都需要仔细的设计和实现。

至于可复用的负载均衡机制,我在邮件列表的另一个 thread 里提到过,这适合做成独立的纯 Lua 库,而不是内建在 ngx_lua 核心中。

Best regards,
-agentzh

Simon

unread,
May 23, 2013, 11:10:30 PM5/23/13
to openresty
可能你的编译器不支持typedef重复定义,我这里是可以的。

你可以把这两个文件的typedef都移到ngx_tcp.h

On 5月23日, 下午9时35分, zju.missha...@gmail.com wrote:
> Hi,菜鸟请教一下,这个nginx-tcp-lua-module包在make的时候出错,提示:
> In file included from ../nginx-tcp-lua-module//src/ngx_tcp_session.c:6:
> ../nginx-tcp-lua-module//src/ngx_tcp_lua_common.h:70: error: redefinition of typedef ‘ngx_tcp_cleanup_pt’
> ../nginx-tcp-lua-module//src/ngx_tcp_session.h:48: note: previous declaration of ‘ngx_tcp_cleanup_pt’ was here
> make[1]: *** [objs/addon/src/ngx_tcp_session.o] Error 1
>
> 指的是typedef的redefine,我分别看了ngx_tcp_lua_common.h:70,ngx_tcp_session.h:48,都有一行代码:typedef void (*ngx_tcp_cleanup_pt)(void *data);既然定义是相同的,应该不会报错,请问这是什么问题?谢谢哈!

Han Li

unread,
May 24, 2013, 4:55:54 AM5/24/13
to open...@googlegroups.com
    把定义移过去就好了,谢谢!
    另外请教一下,比如我有几个Server,想使用nginx_tcp_lua_module实现代理这几个Server,能够负载均衡,并且Server list是可能增删的。请问我要怎么做?
    看到你的代码里面有redis的demo,但是只是nginx代理了一个demo。所以想请教您大概是什么流程,或者有没有demo,谢谢!

Simon

unread,
May 24, 2013, 9:05:34 PM5/24/13
to openresty
你需要对客户端的请求进行处理,可以简单的将请求hash取模,映射到对应的服务器,或者用一致性hash的算法。

如果需要检测server异常,可以在连接后端server的时候进行检测,并且删除异常的server.

lua初学者

unread,
May 27, 2013, 3:19:31 AM5/27/13
to open...@googlegroups.com
很好用的东西,能不能 同时实现udp啊,我现在是用c++接受udp在tcp转给ngx-tcp-lua

在 2012年11月15日星期四UTC+8下午3时13分18秒,Simon写道:

Han Li

unread,
May 27, 2013, 9:11:49 AM5/27/13
to open...@googlegroups.com

很感谢!最近在忙别的,明天按照你的方法尝试。但菜鸟还是问一下,你的意思是否是说,给每个后台Server开一个ngx socket,保存成数组,每个Client来的时候映射到一个Server。也就是简单地将你的连redis的demo复制,只是ngx socket的数目变成多个。刚接触ngx+lua,对于开发也是green hand。望指教,谢谢!

Simon

unread,
May 27, 2013, 9:08:51 PM5/27/13
to openresty
不用给后台server开socket,只需要保存ip到list中,每个client来的时候从list中取一个ip进行connect。

Simon

unread,
May 27, 2013, 9:09:44 PM5/27/13
to openresty
udp暂时没时间弄了,有时间了移植起来应该也很快

lua初学者

unread,
May 27, 2013, 10:29:02 PM5/27/13
to open...@googlegroups.com
很期待~

在 2013年5月28日星期二UTC+8上午9时09分44秒,Simon写道:

hebutc...@gmail.com

unread,
Jun 19, 2014, 6:00:21 AM6/19/14
to open...@googlegroups.com
在 2012年11月15日星期四UTC+8下午3时13分18秒,Simon写道:
Simon,你好。

最近在使用这个模块,我想问,tcp{}能与http{}共用全局变量么?或者http{}可以包含tcp{}么?如果能,我感觉会更方便点。

我的应用场景如下:
1、nginx接收来自浏览器端的请求(HTTP{})
2、nginx根据请求向后台服务器(TCP socket访问)询问
3、整合后台服务器回复,然后回给浏览器

遇到的问题是,tcp纯socket访问,tcp-lua-module有基本功能,但是没办法与http域共享全局变量和require()模块。

我的配置是这样的:摘自nginx.conf
tcp {
server {
listen 5555;
server_name localhost;
timeout 3s;

process_by_lua '
require("LuaXml")
local sock = ngx.req.socket()
while true do
sock:settimeout(3000)
local line, status = sock:receiveuntil("123456")
if not line then
ngx.say("failed to read a line: ", err)
return
end
local data, err, partial = line()
if not data then
ngx.say("-------------")
return
end

--parser xml data
...
end
';
}
}

http {
include mime.types;
#default_type application/octet-stream;
default_type text/plain;

...

init_by_lua ' g_pubtable = {} g_livetable = {} g_target = {} require("LuaXml") g_sort = require("table_sort")';

server {
listen 80;
server_name localhost;

#proxy pass to target server
location /query {
}
}
}

如何在tcp{}中访问到http{}定义的全局变量,如g_pubtable
Reply all
Reply to author
Forward
0 new messages