- 论坛徽章:
- 4
|
本帖最后由 linux_c_py_php 于 2013-03-14 12:04 编辑
这两天动手去做了一下嵌入lua的server(包括提供connect, read_util, write等lua api).
写完之后, 我突然意识到了实现上几个致命的硬伤, 希望得到指点.
先说说我的设计:
1, server采用select做事件循环.
2, server调用accept后, 为该connection创建一个lua_State, 创建一个userdata设置为global var, 以便后续暴露给lua使用.
3, server采用状态机维护连接状态, 其状态转移为:
before_request(过渡状态, 用于注册read event) -> wait_request -> before_response(过渡状态, 用于取消read event, 注册write event) -> wait_response(创建一个lua coroutine并启动, 定时轮询检测coroutine生死, 死后取消write event重新进入before_request)
在wait_request阶段解析到request, 则经过before_response设置write event后进入wait_response阶段.
在wait_response阶段, 第一次调用时会从该连接的lua_State创建一个coroutine并resume.
在此之后, 由于处于wait_request阶段并且注册了write event, 所以server框架会一直触发此连接的回调,
进入状态机的wait_request状态来lua_status()查看coroutine是否死亡, 一旦判定为死亡, 则说明本次lua执行结束,
则会清理掉这个coroutine, 通过进入before_request -> wait_request继续进入下一轮请求解析.
就这样的设计, 通过给lua执行时间加上timeout检测, cpu通常也不会因为write event的轮询而异常繁忙, 并且一切也能正常的工作.
这样设计, 应该是因为我受lighttpd/nginx的插件架构影响较深的原因.
但写完后, 我就觉得有几个地方我自己都觉得不爽:
①, 因为我提供了connect/read_util/write等lua api, 如果是我此种设计, 想做到长连接connect会很不自然很没结构, 因为我的coroutine不是常驻的.
所以我意识到一个常驻的coroutine设计多么重要:
1, accept后就为该连接启动一个coroutine, 在lua层面的代码变成了while get_req() end的循环取请求结构(可以让用户仅填callback, while我们替其隐藏在api里).
2, 在server端要做的就是当解析到req后, 根据lua层的api:get_req 是否已经yield(在yield前标记变量以便server层进行判定)决定是否有必要resume该coroutine.
②, 我之所以要一个connection创建一个lua_State, 想来唯一的原因就是想给每个coroutine暴露一个独立的全局变量, 为了这个目的创建那么多lua_State很破费.
能不能推荐一个官方一点的做法, 能够整个server只用一个lua_State, 并且能够保证在lua代码层面可以直接使用一个全局变量, 比如叫做: core, 而不需要做其他多余的操作.
我能想到的方法可能是:
1, 一个全局lua_State.
2, 在accept连接后, 为其创建一个table存储连接相关信息, 再创建一个userdata: core, 然后把core存在前面的table中.
3, load一份lua代码, 设置它的第1个环境(5.1里用lua_setenv, 5.2里是setupvalue第1个upvalue(_ENV)) 为前面那个table, 这样coroutine就会有不同的环境表了.
4, 创建一个常驻coroutine , 把这个coroutine记录在前面的table里(为了保持一个引用计数, 也为了可以在C层获取其lua_State), 然后coroutine reumse跑起.
5, 把table存在以fd为下标的全局索引table中.
这样之后, server可以从lua_State的全局索引table根据fd取到table, 拿出其中的userdata, 也可以拿出里面的coroutine的lua_State, 可以用来resume.
另外, 想清理一个fd对应的lua数据, 只要从全局索引table中清理掉该fd的数据即可, 因为可以一下子把userdata和coroutine的引用减少为0 , 可以垃圾回收了.
|
|