hanxi / blog

涵曦的博客
https://blog.hanxi.cc
56 stars 5 forks source link

高性能路由 libr3 库的 lua 封装 #49

Open hanxi opened 3 years ago

hanxi commented 3 years ago

最近在折腾 lua 语言的 web 服务器框架,需要实现路由模块。

以前使用过这个 APItools/router 做路由,是一个比较简单的实现,这里 hanxi/skynet-demo 可以看到使用示例。

参考了 lor 框架的路由实现,它的路由模块使用的是一个纯 lua 实现的 trie 树,看上去挺复杂的,不太好拆出一个独立的模块。

搜到了 libr3 这个库,看描述性能很高,且接口比较简单。并且 iresty/lua-resty-libr3 也对它做了封装,说明质量很定是没啥问题的。已经有人写好了为什么不用呢?

首先我计划的 web 框架是基于 skynet 的,使用的是 lua 不是 luajit,虽然 lua 也有 ffi 库可以使用,我还是想用 lua 的原生方式来封装一下。另一个原因是我用不到 host 和 remote_addr 这两个参数,这两个参数对于 API 网关开发肯定是有用的,但是对于 web 应用开发是用不上的。

参考了 iresty 的封装代码,实现的方式也打算使用 iresty 的方式,一个 so 文件,一个 lua 文件。 so 文件提供基础接口, lua 文件实现主要的路由逻辑。

逻辑全部写在 C 语言里,使用一个 so 也是能做到的,逻辑也不多。但是如果要像 iresty 那样实现 path 的缓存功能,在 C 里实现的话代码就不简洁了。

这个方案纠结了许久,使用一个 so 的话,方便使用者,只需要拷贝一个 so 文件就可以使用, 使用 so + lua 的方式又可以做到代码简洁。最后还是选用了代码简洁的方式,因为使用者使用起来也不麻烦,只需要把 so 和 lua 放到对应的搜索路径即可。

先设计好使用接口:

  1. 创建树 M:create(cap)
  2. 插入节点 M:insert(path, method, data)
  3. 编译 M:compile()
  4. 查找节点 M:match(path, method)

销毁树放到元表的 __gc 里面。

data 不直接存入 libr3 的树里,像 iresty 一样,只存入索引即可。

不像 iresty 一样提供 dispatch 接口直接调用注入的 callback,而是提供 find 接口,方便使用者根据自己的需要是执行 callback,还是使用数据去干别的事情。这个可以参考 gin 框架的代码,也是提供查询数据的接口的。另外我将要实现的 web 框架也借鉴了 gin 的思路。

目前这个库还只实现了 C 库部分,代码已开放 hanxi/lua-r3 ,感兴趣的可以提前看看。

对 skynet 感兴趣的话,可以学习下这门课程:《Skynet 游戏服务器开发实战》,课程地址: https://www.lanqiao.cn/courses/2770 ,九折优惠邀请码: 2CZ2UA5u

使用 skynet 开发的 web 框架也见过几个,没有遇到合心意的。提前预告下,我写的 web 框架参考了 lor , gin ,webpy 等框架的实现,面世还没那么快,还在慢慢打磨。有时候遇到一个方案的抉择要推敲很久。


2021-02-03 更新

https://github.com/hanxi/lua-r3 已实现 Lua 封装部分。