V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
CandyMi
V2EX  ›  Lua

core_framework - 基于 libev 的轻量级 lua 网络开发框架

  •  
  •   CandyMi · 2019-03-27 21:08:38 +08:00 · 6957 次点击
    这是一个创建于 2072 天前的主题,其中的信息可能已经有所发展或是发生改变。

    —— 大道至简, 返璞归真.

    前言

    在发表这篇博文的前夕, 还有一些小伙伴在提问一些以下相关的问题:

    1. 性能怎么样?

    2. 是否容易上手?

    3. 开发目标在哪?

    4. 如何反馈问题?

    5. 对比行业内的 lua 开源项目有何优势?

    等等, 以上问题会在本文中一一介绍.


    CF 的起因

    首先来聊聊情怀这个东西! 相信每一个行业内的从业者都或多或少有过一个梦, 这个梦叫做: "我到时候要开发一个 XXX"!其实作者当初也是一样.

    每当半夜(凌晨)在加班、看文档、调试的时候, 总会搜索到一些几年前或十几年前的框架或入门 demo。例如: tinyhttp, 链接的源码是一些同学 fork 的镜像站。

    每次看到这些内容或多或少都会激起心中那一丝丝快熄灭的热情, 也许这就是最后对技术的渴望?

    就是在动手创建项目之前还反复问过自己是否要做? 能坚持下去么?也许被喷都是一种奢望?

    在心里一一回答了这些问题后, 在 2018 年末创建了本项目.

    说句实话! 一个网络开发框架最难的不是实现某个功能, 而是从零开始一步一步添砖加瓦的造轮子!

    作为一个网络开发框架, 最重要的两个功能肯定是需要的! 定时器库、事件驱动库. 如何抉择?选项有 2 个: libev / libuv .

    libev 成熟稳定、轻量级、unix like 支持、容易嵌入;
    
    libuv 比 libev 更加优秀,增加了许多功能(线程池、信号、同步、锁等等),封装更加完善, 并且增加了 windows 支持;
    

    从 cf 框架开发之初选型来看, libuv 绝对是目前最优解. 但是作者偏偏选择了 libev. 也从此开始, 艰辛的底层开发之路就此展开.

    首先, 作者不让使用者 C/C++进行实际业务开发! 这样做会让使用者有较高的开发成本与学习成本, 而选择一门较好的脚本语言就显得尤为重要.

    作者对Lua还算是稍微熟悉一点, 所以就选了 Lua 作为业务脚本语言。至于 Lua 语言的优势这里就不说了, 网上大把文章夸它的.

    现在既然脚本语言已经选定, 那么就开始写代码吧! Let's Lua.


    CF 的编写之路

    1. 网络层

    首先, 我们来看一段 C 封装给 Lua 调用的 API 代码:

    LUAMOD_API int
    luaopen_tcp(lua_State *L){
    	luaL_checkversion(L);
    	/* 添加 SSL 支持 */
        SSL_library_init();
        SSL_load_error_strings();
        // CRYPTO_set_mem_functions(xmalloc, xrealloc, xfree);
        // OpenSSL_add_ssl_algorithms();
    	/* 添加 SSL 支持 */
    	luaL_newmetatable(L, "__TCP__");
    	lua_pushstring (L, "__index");
    	lua_pushvalue(L, -2);
    	lua_rawset(L, -3);
        lua_pushliteral(L, "__mode");
        lua_pushliteral(L, "kv");
        lua_rawset(L, -3);
    	luaL_Reg tcp_libs[] = {
    		{"read", tcp_read},
    		{"write", tcp_write},
    		{"ssl_read", tcp_sslread},
    		{"ssl_write", tcp_sslwrite},
    		{"stop", tcp_stop},
    		{"start", tcp_start},
    		{"close", tcp_close},
    		{"listen", tcp_listen},
    		{"connect", tcp_connect},
    		{"ssl_connect", tcp_sslconnect},
    		{"new", tcp_new},
    		{"new_ssl", ssl_new},
    		{"free_ssl", ssl_free},
    		{"new_server_fd", new_server_fd},
    		{"new_client_fd", new_client_fd},
    		{NULL, NULL}
    	};
    	luaL_setfuncs(L, tcp_libs, 0);
    	luaL_newlib(L, tcp_libs);
    	return 1;
    }
    

    以上是 TCP 实现的 C 代码的片段, 有兴趣阅读源码的小伙伴请点击这里;

    众所周知 Lua 没有原生的 Socket. 那么就需要框架编写者自己抽象底层逻辑重新实现一套 API.

    简单的封装 Lua C 库谁都会, 而且也算不上是什么难事. 但是我们的目的是将底层同步阻塞 Socket hook 为非阻塞, 这时候难点就来了!

    大家都知道 libev 是基于 react 模型的事件驱动网络库, 所有注册事件后的业务逻辑都是以回调的形式触发. 那不就变成 node-lua 代码了吗?(笑)

    这时候, 作者想了个点子来解决这个问题! 执行流程如下:

    1. 每次需要做一些同步操作的时候, 就调用 C API 注册回调事件.
    1. 为当前注册的所有事件创建一个 Lua 协程保存上下文并让出当前协程执行权.
    1. 等到注册事件被触发后, 调用 C API 恢复协程继续执行.

    简单来说就是将 C 层次的异步回调逻辑封装为 Lua 层的同步非阻塞, 保证不因为 IO 问题阻塞线程.

    下面提供一段 socket 同步非阻塞的伪代码, 经供参考:

    function TCP:recv(bytes)
        local current_co = co_self()
        self.read_co = read_ev(function()
        -- do action
        -- stop timer_ev
        -- wakeup(current_co) 恢复执行权
        end)
       self.timer_co =  self.timer_ev(function()
        -- do action
        -- stop read_ev
        -- wakeup(current_co) 恢复执行权
        end)
        tcp_start(io, EV_READ, self.read_co)
        timer_start(timer, 3 秒超时, self.timer_co)
        return co_yield() -- 让出执行权
    end
    

    一个 Lua 版的 Socket EV_READ 伪代码大致的处理流程如上, 想看实际处理逻辑请看这里

    同理, Socket write/connect/listen 等等 API 直接照抄就行(UDP 也大同小异). (其实这里有个小插曲就是 SSL SOCKET 的坑, 但是由于篇幅问题就不说了.)

    细心的小伙伴可能发现代码同时注册了 Socket 与 Timer 事件, Socket 非阻塞操作不能解决 read 与 connect 超时的问题. 所以 cf 框架干脆就封装彻底一点.

    至此, Socket 算是已经算是基本 hook 与封装完成了. 接下来就可以开始写应用层协议了.

    2. 应用层协议

    现在 Socket 终于能正常使用了, 那么面临的新问题就又来了。

    libev 没有自带异步 dns

    dns 都还需要使用者自己封装, 这个坑真是填的无比难受! 好在网络上有前辈实现了 Lua 版的异步 dns, 作者稍微看明白之后就借用了过来封装内部使用.

    这样 cf 也算是有了深度定制的异步 dns库了吧!(虽然并不完善, 但是足够使用)

    一个网络库是否流行, 基本上就得看生态. 那么协议层的轮子又得造起来:

    1. httpdhttpc
    2. mail
    3. mysql
    4. redis
    5. mqtt
    6. websocket

    其中一些协议为各位前辈那边借过来适配后定制的, 简单的协议则是直接花 1-2 小时直接手写出来的。

    3. 封装与易用性

    为了不让 API 那么封闭与提升 cf 的可用性, 作者决定将 mysql 与 redis 进行初步封装.

    封装包括大家常用的功能, 连接池、面向对象操作、无需手动管理 session 生命周期等等. 简化编程思想包袱来提升开发效率.

    至于内部 Socket 更是让框架来解决释放问题确保文件描述数量限制的情况下也是可以正常使用. (其实是不喜欢依赖 gc 被动 close fd 与 free 内存)


    CF 是啥?

    如果你耐心看完了第一部分介绍, 那么你就应该对 cf 有了一个大概的了解.

    cf 全称为: CoreFramework, 是一个基于 libev 的 Lua 网络开发框架. 在其内部实现了多种网络协议与第三方库用来帮助使用者进行项目原型的快速开发.

    cf 在 httpd 使用上尊崇前、后端分离的解决方案, 仅实现了基本的 view 路由并且不支持 rest 风格的 API 路由. 虽然这样可能会引来宇多人的诟病.

    cf 的 httpd 内嵌 websocket 支持, 方便使用者在复用端口的同时也可以享受长连接编写的乐趣.

    更多的介绍, 请大家项目地址的Wiki


    CF 能做什么?

    • 基于容器技术的微服务场景(swarm/kubernetes); —— 推荐

    • 游戏服务器的前端代理层; —— 推荐

    • 内存 /CPU 资源较为紧缺的云服务器; —— 推荐

    • 对性能要求较高的无状态集群; —— 推荐

    • 海量长连接(websocket)Agent 集群; —— 推荐


    CF 使用到的技术栈?

    传输层: TCP/UDP

    会话层: SSL Client 支持

    协议层: dns/webocket/http/mqtt/redis/mysql/smtp

    工具库: Timer/TASK

    第三方库: Libev、openssl/libressl、lua-5.3、jemalloc/tcmalloc(可选)


    CF 如何安装?

    cf 目前支持绝大部分 Unix like 操作系统, 作者是在 Mac 上进行开发, 所以 Mac 支持是必须的.

    cf 测试的 Linux 为 Centos, 所以基本上基于 Linux 内核的操作系统编译后的运行也没什么问题(export 增加 /usr/local/lib)

    同时,作者还贴心的为大家做了一个简单 Dockerfile. 文件在项目根目录下, 大家下载直接使用即可。

    当然, 如果你不想制作 Dockerfile,也可以使用 Docker 命令直接拉去作者制作好放在 docker hub 的镜像. candymi/cfweb

    使用详情与使用方法请参考Docker 安装编译安装


    CF 如何运行呢?

    测试运行

    bash#: ./cfadmin

    后台运行

    bash#: ./cfadmin

    退出

    killall cfadmin

    ctrl + c


    文档在哪?

    作者为大家贴心的写了一篇详细到不能再详细的文档, 以此来获取大家的点赞与关注.

    作者还为喜欢阅读源码的同学准备了充足的中文注释与英文注释, 结合起来方便大家快速了解 CF 工作方式(中 /英注释结合易于理解一些专属词汇).


    回答之前的问题:

    Q. 性能怎么样?

    A. 性能还不错, 但是具体数值请自行测试.

    Q. 是否容易上手?

    A. 学习 lua 一小时入门 -> cf 一小时入门

    Q. 开这个项目的初衷是什么?

    A. 其实在前面已经回答过了.

    Q. 开发目标在哪?

    A. Wiki 里有TODO

    Q. 如何反馈问题?

    A. Wiki 里有Q & A

    Q. 对比行业内的 lua 开源项目有何优势?

    A. CF 对比其它 lua 开发项目更深入改变用户使用习惯! 简化框架上手难度, 将框架都黑盒子透明化. 无需学习复杂的设计模式与理念.

    Q. CF 的开发理念是什么?

    A. CF 项目的目标不是竞争, 而是明白明白简单为美. 当你习惯了它, 也许你就会上瘾.


    使用示例

    精彩截图

    部署面板

    状态面板

    pod 日志

    希望

    也许你正在使用其它开发框架, 但是这不妨碍你对 cf 的督促.

    也许你正在试用它, 这不妨碍你与作者沟通你的想法.

    也许你正在吐槽它的缺点,请来issue尽情吐槽.

    文档与地址

    项目文档

    项目地址

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3629 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 04:30 · PVG 12:30 · LAX 20:30 · JFK 23:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.