怎么用lua语言开发一个kong插件

这篇文章主要讲解了“怎么用lua语言开发一个kong插件”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用lua语言开发一个kong插件”吧!

站在用户的角度思考问题,与客户深入沟通,找到西乡塘网站设计与西乡塘网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都网站制作、成都做网站、企业官网、英文网站、手机端网站、网站推广、域名申请、网络空间、企业邮箱。业务覆盖西乡塘地区。

需求:
 插件1: 把一个请求的 header、request、response 这些数据传输到后台,通过http接口、或者mq。
 插件2: 根据 header 以及 request的信息,判断用户的权限,无权访问或者访问被限制,则直接网关层拦截返回response,不去调用后端服务。
lua版本:5.1
kong的版本:2.1.4
kong的架构图:
怎么用lua语言开发一个kong插件
    从Kong的架构图中,可以看到Nginx和OpenResty的存在。OpenResty是以 Nginx 为核心的 Web 开发平台,内部包含lua-nginx-module,集成了大量精良的 Lua 库,开发人员可以使用 Lua 脚本调动各类C和Lua 模块。OpenResty目标是让Web服务直接跑在 Nginx 服务内部,利用 Nginx 的非阻塞I/O模型实现高性能响应。而Kong 是OpenResty的一个应用程序。
kong的插件开发基础知识
 从基础知识可以看出,我们的要开发插件主要是重写kong提供的一些基础方法,这些基础方法对应了网络请求的生命周期的不同阶段,实际上对应了OpenResty 的不同执行阶段。所以在不同的生命周期,我们能拿到的数据是不同的,在不同的生命周期,有些函数和方法是不能使用的。
 如下报错表示你的API放错了生命周期:

function cannot be called in access phase (only in: header_filter, body_filter, log)

比如:Handler:access(请求被代理到上游服务之前执行)阶段调用获取response的信息 kong.response.get_header()

API disabled in the context of log_by_lua*

比如:你在生命周期里直接调用http.new()去创建网络请求。在NGINX的执行阶段使用某些函数,会影响客户端的响应时长。
 所以可以通过一个非常强大的方法 ngx.timer.at 在请求的生命周期中处理一些高延迟的业务逻辑。定时调用是在后台运行,并且他们的执行不会增加任何客户端的响应时长。

local timer_at = ngx.timer.at
local ok, err = timer_at(0, send_payload, conf, cjson.encode(json_str))
if not ok then
    kong.log.err("failed to create timer: ", err)
end
---timer_at(0, send_payload, conf, cjson.encode(json_str)) 0表示零延迟,send_payload表示要调用的方法,后面的参数表示send_payload该方法需要的入参。

以上解决了一些插件编写的基本规则层面的问题。

那么生命周期的不同阶段如何共享数据呢?

比如:在 handler:log()阶段获取请求的reponse结果,在该阶段可以获取到

json_str['header'] = cjson_encode(kong.request.get_headers())
 json_str['request'] = cjson_encode(basic_serializer.serialize(ngx))
但是response是不能直接过去到的。所以我们可以在body_filter阶段获取到response 然后通过kong.ctx.shared or kong.ctx.plugin

kong.ctx.shared

一个 table 结构的数据,它用于在给定请求的多个插件之间共享数据,由于它只与请求的上下文相关,所有无法从 Lua 模块的顶级块访问此表,只能在请求段中访问,对应插件的 rewriteaccessheader_filterbody_filterlog 接口
所有插件都可以看到单个插件在此 table 中插入的值命名时必须谨慎,因为命名冲突会导致数据被覆盖。

kong.ctx.plugin

一个 table 结构的数据,与 kong.ctx.shared 不同,此 table 不在插件之间共享,相反,它仅对当前插件实例可见,也就是说,如果配置了多个限流插件实例(在不同的服务上),每个实例对于每个请求都有自己的 table
由于它自带命名空间,所以它比 kong.ctx.shared 更安全,因为它避免了潜在的命名冲突,这可能导致多个插件在不知不觉中覆盖了彼此的数据

扩展部分:

在开发过程中,如果你像我一样不太了解OpenResty的运行原理,那么可能会产生这样的疑问:
 在高并发的情况下,会出现类似多线程的问题吗?不同的请求在同一个插件下数据获取会出错吗?
 解释:
   Nginx采用多进程模型,单Master进程—多Worker进程(一般跟CPU的核数相同)由Master处理外部信号、配置文件的读取及Worker的初始化,Worker进程采用单线程、非阻塞的事件模型(Event Loop,事件循环)来实现端口的监听及客户端请求的处理和响应,同时Worker还要处理来自Master的信号。由于Worker使用单线程处理各种事件,所以一定要保证主循环是非阻塞的,否则会大大降低Worker的响应能力。
每个请求都有一个协程进行处理。

协程类似一种多线程,与多线程的区别有:

  1. 协程并非os线程,所以创建、切换开销比线程相对要小。

  2. 协程与线程一样有自己的栈、局部变量等,但是协程的栈是在用户进程空间模拟的,所以创建、切换开销很小。

  3. 多线程程序是多个线程并发执行,也就是说在一瞬间有多个控制流在执行。而协程强调的是一种多个协程间协作的关系,只有当一个协程主动放弃执行权,另一个协程才能获得执行权,所以在某一瞬间,多个协程间只有一个在运行。

  4. 由于多个协程时只有一个在运行,所以对于临界区的访问不需要加锁,而多线程的情况则必须加锁。

  5. 多线程程序由于有多个控制流,所以程序的行为不可控,而多个协程的执行是由开发者定义的所以是可控的。
    Nginx的每个Worker进程都是在epoll或kqueue这样的事件模型之上,封装成协程,每个请求都有一个协程进行处理。这正好与Lua内建协程的模型是一致的,所以即使ngx_lua需要执行Lua,相对C有一定的开销,但依然能保证高并发能力。

openresty/lua-nginx-module(官方介绍)
Kong的日志记录(log)自定义插件
Kong插件开发工具包
OpenResty原理和缓存的实现
nginx+lua的基本原理概念介绍


 

感谢各位的阅读,以上就是“怎么用lua语言开发一个kong插件”的内容了,经过本文的学习后,相信大家对怎么用lua语言开发一个kong插件这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!


本文题目:怎么用lua语言开发一个kong插件
文章地址:http://scyanting.com/article/igopho.html