MOSN(Modular Open Smart Network)-08-MOSN 扩展机制解析
前言
大家好,我是老马。
sofastack 其实出来很久了,第一次应该是在 2022 年左右开始关注,但是一直没有深入研究。
最近想学习一下 SOFA 对于生态的设计和思考。
sofaboot 系列
SOFAStack-00-sofa 技术栈概览
MOSN(Modular Open Smart Network)-00-简单聊一聊
MOSN(Modular Open Smart Network)-01-是一款主要使用 Go 语言开发的云原生网络代理平台
MOSN(Modular Open Smart Network)-02-核心概念
MOSN(Modular Open Smart Network)-03-流量劫持
MOSN(Modular Open Smart Network)-04-TLS 安全链路
MOSN(Modular Open Smart Network)-05-MOSN 平滑升级原理解析
MOSN(Modular Open Smart Network)-06-MOSN 多协议机制解析
MOSN(Modular Open Smart Network)-07-Sidecar 模式
MOSN(Modular Open Smart Network)-08-MOSN 扩展机制解析
云原生网络代理 MOSN 扩展机制解析。
大家好,我是今天的讲师永鹏,来自蚂蚁集团,目前主要负责 MOSN 的开发,也是 MOSN 的Committer。
今天我为大家分享的是云原生网络代理 MOSN 的扩展机制,希望通过这次分享以后,能让大家了解 MOSN 的可编程扩展能力,可以基于 MOSN 的扩展能力,按照自己实际的业务需求进行二次开发。
前言
今天我们将从以下几个方面,对 MOSN 的扩展机制进行介绍:
- MOSN 扩展能力和扩展机制的详细介绍;
- 结合示例对 MOSN 的 Filter 扩展机制与插件扩展机制进行详细介绍;
- MOSN 后续扩展能力规划与展望;
欢迎大家有兴趣一起共建 MOSN。在本次演讲中涉及到的示例就在我们的 Github 的 examples/codes/mosn-extensions
目录下,大家有兴趣的也可以下载下来运行一下,关于这些示例我们还做了一些小活动,也希望大家可以踊跃参与。
MOSN:https://github.com/mosn/mosn
MOSN 简介
MOSN 作为云原生的网络代理,旨在为服务提供多协议、模块化、智能化、安全的代理能力。在实际生产使用中,不同的厂商会有不同的使用场景,通用的网络代理能力面对具体的业务场景会显得有些不足,通常都需要进行二次开发以满足业务需求。MOSN 在核心框架中,提供了一系列的扩展机制和扩展点,就是为了满足需要基于业务进行二次开发的场景,同时 MOSN 提供的部分通用逻辑也是基于扩展机制和扩展点的实现。
比如通过 MOSN “内置实现”的透明劫持的能力,就是通过 MOSN Filter 机制实现。而要实现消息的代理,则可以通过类似的扩展实现。在通用代理的情况下,可以通过 Filter 机制实现业务的认证鉴权,也可以实现定制的负载均衡逻辑;除了转发流程可以扩展实现以外,MOSN 还可以扩展日志的实现,用于对标已有的日志系统,也可以扩展 XDS 实现定制的配置更新;根据不同的业务场景还会有很多具体的扩展情况,就不在此展开了,有兴趣的可以关注 MOSN 社区正在建设的源代码分析系列文章与文档。
MOSN 作为一款网络代理,在转发链路上的网络层、协议层、转发层,在非转发链路上的配置、日志、Admin API 等都提供了扩展能力,对于协议扩展的部分,有兴趣的可以看一下上期直播讲的 MOSN 多协议机制解析,我们今天将重点介绍一下转发层的 Stream Filter 扩展机制与 MOSN 的插件机制。
Stream Filter 机制
在实际业务场景中,在转发请求之前或者回写响应之前,都可能需要对请求/响应做一些处理,如判断是否需要进行转发的认证/鉴权,是否需要限流,又或者需要对请求/响应做一些具有业务语义的记录,需要对协议进行转换等。这些场景都与具体的业务高度耦合,是一个典型的需要进行二次开发的情况。MOSN 的 Stream Filter 机制就是为了满足这样的扩展场景所设计的,它也成为目前 MOSN 扩展中使用频率最高的扩展点。
在目前的内置 MOSN 实现中,Stream Filter 机制暂时与内置的 network filter: proxy 是绑定的,后面我们也考虑将这部分能力进行抽象,让其他 network filter 也可以复用这部分能力。
关于 Stream Filter,今天会为大家讲解两个部分的内容:
- 一个 Stream Filter 包含哪些部分以及在 MOSN 中是如何工作的;
- 通过一个 Demo 演示来加深对 Stream Filter 的实现与应用;
一个完整的 Stream Filter
一个完整的 StreamFilter,包含三个部分的内容:
- 一个 StreamFilter 对象,存在于每一个请求/响应当中,在 MOSN 收到请求的时候发挥作用,我们称为 ReceiverFilter,在 MOSN 收到响应时发挥作用,我们称为 SenderFilter。一个 StreamFilter 可以是其中任意一种,也可以是两种都是;
- 一个 StreamFilterFactory 对象,用于 MOSN 在每次收到请求时,生成 StreamFilter 对象。在 Listener 配置解析时,一个 StreamFilter 的配置会生成一个其对于的 StreamFilterFactory。同一个 StreamFilter 在不同的 Listener 下可能对应不同的 StreamFilterFactory,但是也有的特殊情况下,StreamFilterFactory 可能需要实现为单例;
- 一个 CreateStreamFilterFactory 方法,配置解析时生成 StreamFilterFactory 就是调用它;
Stream Filter 在 MOSN 中是如何工作的
接下来,我们看下 Stream Filter 在 MOSN 中是如何工作的。
当 MOSN 经过协议解析,收到一个完整的请求时,会创建一个 Stream。此时收到请求的 Listener 中每存在 StreamFilterFactory,就会生成一个 StreamFilter 对象,随后进入到 proxy 流程。
进入 proxy 流程以后,如果存在 ReceiverFilter,那么就会执行对应的逻辑,ReceiverFilter 包括两个阶段,“路由前”和“路由后”,在每个 Filter 处理完成以后,会返回一个状态,如果是 Stop 则会中止后续尚未执行的 ReceiverFilter,通常情况下,返回 Stop 状态的 Filter 都会回写一个响应。如果是 Continue 则会执行下一个 ReceiverFilter,直到本阶段的 ReceiverFilter 都执行完成或中止;路由前阶段的 ReceiverFIlter 执行完成后,就会执行路由后阶段,其逻辑和路由前一致。如果是正常转发,那么随后 MOSN 会收到一个响应或者发现其他异常直接回写一个响应,此时就会进入到 SenderFilter 的流程中,完成 SenderFilter 的处理。SenderFilter 处理完成以后,MOSN 会写响应给 Client,并且完成最后的收尾工作,收尾工作包括一些数据的回收、日志的记录,以及 StreamFilter 的“销毁”(调用 OnDestroy)。
Stream Filter Demo
对 StreamFilter 有了一个基本的认识以后,我们来看一个实际的 Demo 代码来看下如何实现一个 StreamFilter 并且让它在 MOSN 中发挥作用。
按照刚才我们的介绍,一个 Stream FIlter 要包含三部分:Filter、Factory、CreateFactory。
- 首先我们实现一个 Filter,其逻辑是模拟一个鉴权的 Filter:只有请求的 Header 中包含所配置的 Key-Value 时,MOSN 才会对请求做继续转发,否则直接返回 403 错误;
- 然后我们实现一个 Factory,它负责生成我们实现的 Filter,并且说明 Filter 应该发挥作用的阶段(在请求阶段、路由匹配之前);
- 最后我们定义了一个生成 DemoFactory 的函数 CreateDemoFactory,并且通过 init 将其“注册”,注册完成以后,MOSN 配置解析就可以识别这个 StreamFilter;
完成实现以后,我们就可以通过具体的配置来实现对应的功能了。在示例的配置中,配置 StreamFilter 为我们刚才实现的 Filter,只转发 Header 中包含 user:admin 的请求。示例配置中监听的端口是 2046,转发的后端 server 端口是 8080。在演示之前,我已经完成了 8080 server 的启动,这个 server 会对收到的任意请求返回 200 。我们来看一下 MOSN 转发情况。Demo 操作可以在文末直播的视频回顾中查看。
MOSN Plugin 机制
下面我们来了解一下 MOSN 的 Plugin 机制。
刚才我们对 Stream Filter 有了一个了解,MOSN 中其余的扩展实现也是类似的方法,思路就是编码实现 MOSN 扩展点所需要的接口然后利用 MOSN 的框架运行扩展的实现。
但是这里会发现一个问题,就是有时候我们需要的扩展能力已经有现成可用的实现了,那么我们是否可以做简单的改造就让 MOSN 可以获取对应的能力,哪怕目前可用的实现不是 Go 语言的实现,比如现成的限流能力的实现、注入能力的实现等;又或者对于某些特定的能力,它需要有更严格的控制,更高的标准,比如安全相关的能力。
类似这样的场景,我们引入了 MOSN 的 Plugin 机制,它支持我们可以对 MOSN 需要的能力进行独立开发或者我们对现有的程序进行适当的改造以后,就可以将它们引入到 MOSN 当中来。
MOSN 的 Plugin 机制包含了两部分内容,一是 MOSN 自定义的 Plugin 框架,它支持通过在 MOSN 中实现 agent 与一个独立的进程进行交互来完成 MOSN 扩展能力的实现。二是基于 Golang 的 Plugin 框架,通过动态库(SO)加载的方式,实现 MOSN 的扩展。其中动态库加载的方式目前还存在一些局限性,还处于 beta 阶段。
我们先来看一下多进程 Plugin 框架。
多进程 Plugin 框架
MOSN 的 Plugin 框架是 MOSN 封装的一个可以让 MOSN 通过 gRPC 和独立进程进行交互的方式,它包含两部分:
- 独立的进程通过 MOSN Plugin 框架管理,作为 MOSN 的子进程;MOSN 的 Plugin 框架可以管理它们,如启动、关闭等;
- 通过在 MOSN 中实现的 agent,使用 gRPC 的方式和子进程进行交互,gRPC 可以是基于 tcp 的,也可以是基于 domain socket 的;
基于这个框架,我们只需要开发或者进行一些改造,让程序满足 MOSN 框架的规范,就可以作为 MOSN 多进程插件的一部分。
首先我们需要提供一个 gRPC 的服务,并且满足 MOSN 框架下的 proto 定义。当 gRPC server 启动完成以后,向标准输出(stdout)输出一段约定的字符串,作为 MOSN 和子进程之间的握手协议。MOSN 中的对应 agent 会通过握手协议完成与子进程之间的连接建立。握手协议的字符串包含5个字段,每个字段之间用"|“分割,其中带$符号的是根据实际进程情况需要填写的值,其余的是当前约定的固定字段。network 支持 tcp/unix,代表通过 tcp 方式还是 unix domain socket 的方式进行通信,addr 表示 gRPC server 监听的地址。
MOSN 提供了 go 语言的子进程 server 封装,在 go 语言场景下,作为子进程的程序只需要实现一个 MOSN 框架下的 plugin.Service 接口,并且通过 plugin.Serve 方法启动即可。
通过 Plugin 框架,让 MOSN 做到在扩展功能实现的时候,支持隔离性、支持异构语言扩展能力、支持模块化,以及具备进程管理的能力。
对于 MOSN 通过多进程方式完成扩展,今天准备了两个示例和大家进行分享。一个是基于 MOSN 的 TLS 扩展,模拟了通过一个安全等级比较高的证书管理程序来获取 TLS 配置证书、私钥等敏感信息的能力;第二个是将之前演示的 Stream Filter 修改为了“子进程”,模拟“如何将现成的能力”引入 MOSN。