-
Notifications
You must be signed in to change notification settings - Fork 173
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add pluggable component design chinese doc
- Loading branch information
Showing
5 changed files
with
87 additions
and
88 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Pluggable Component 设计文档 | ||
|
||
## 背景 | ||
|
||
当前 Layotto 的 component 都是实现在 Layotto 的工程里面的,这要求用户要想使用新的 component,必须使用 golang 语言开发,同时必须在 Layotto 工程中实现,然后统一编译。 | ||
对于多语言用户来说非常不友好,因此 Layotto 需要提供pluggable components 的能力,允许用户可以通过任何语言实现自己的component,Layotto 通过 grpc 协议和外部的 component 进行通信。 | ||
|
||
## 方案 | ||
|
||
- 基于 uds(unix domain socket)实现本地跨语言组件服务发现,降低通信开销。 | ||
- 基于 proto 实现组件跨语言实现能力。 | ||
|
||
## 数据流架构 | ||
|
||
![](../../../img/pluggable/layotto_datatflow.png) | ||
|
||
这是当前用户调用 sdk 开始的数据流向。虚线部分是与 pluggable component 主要参与的数据流。 | ||
|
||
### 组件发现 | ||
|
||
![](../../../img/pluggable/layotto.png) | ||
|
||
如上图所示,用户自定义组件启动 socket 服务,并将 socket 文件放到指定目录中。 layotto 启动时,会读取该目录中的所有 socket 文件(跳过文件夹),并建立 socket 连接。 | ||
|
||
目前,layotto 向 dapr 对齐,不负责用户组件的生命周期,服务期间若用户组件下线,不会进行重连,该组件服务无法使用。 | ||
后面根据社区使用情况,决定 layotto 是否需要支持进程管理模块,或是使用一个单独的服务来管理。 | ||
|
||
由于 windows 对于 uds 的支持还不是很完善,且 layotto 本身取消了对 windows 的兼容,所以新特性采用的 uds 发现模式未对 windows 系统做兼容。 | ||
|
||
## 组件注册 | ||
|
||
如上面的数据流架构图所示,用户注册的组件需要实现 pluggable proto 定义的 grpc 服务。 layotto 会根据 grpc 接口,实现 go interface 接口,这里 | ||
对应于数据流图中的 wrap component。wrap component 与 build-in component 对 layotto runtime 来说没有任何区别,对于用户来说也没有特殊的感知。 | ||
|
||
layotto 通过 grpc reflect 库,获取到用户提供服务实现了哪些组件,注册到全局的组件注册中心,供用户使用。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,62 @@ | ||
# pluggable component 使用文档 | ||
# Pluggable Component 使用文档 | ||
|
||
## 编写组件 | ||
该示例展示了如何通过 Layotto 提供的可插拔组件能力,用户实现并注册自己的组件。并通过 Layotto sdk 调用,来验证自己组件编写的正确性。 | ||
|
||
下面以 go 实现 hello 组件为例 | ||
## step1.编写并运行可插拔组件 | ||
|
||
在 `layotto/spec/proto/pluggable` 中找到对应组件的 proto 文件,生成对应实现语言的 grpc 文件。 | ||
接下来,运行已经编写好的代码 | ||
|
||
```shell | ||
cd demo/pluggable/hello | ||
go run . | ||
``` | ||
|
||
打印如下结果表示服务启动成功 | ||
```shell | ||
start grpc server | ||
``` | ||
|
||
若出现以下错误,代表 sock 文件已经存在,可能是上次启动服务时强制关闭导致的,使用 `rm /tmp/runtime/component-sockets/hello-grpc-demo.sock` 删除后重新启动即可。 | ||
```shell | ||
panic: listen unix /tmp/runtime/component-sockets/hello-grpc-demo.sock: bind: address already in use | ||
|
||
goroutine 1 [running]: | ||
main.main() | ||
/home/cyb/project/ospp/layotto/demo/pluggable/hello/main.go:49 +0x236 | ||
exit status 2 | ||
``` | ||
|
||
> 1. 以 go 实现 hello 组件为例,在 `layotto/spec/proto/pluggable` 中找到对应组件的 proto 文件,生成对应实现语言的 grpc 文件。 | ||
go 语言的 pb 文件已经生成并放在了 `spec/proto/pluggable/v1` 下,用户在使用时直接引用即可。 | ||
> 2. 组件除了需要实现 protobuf 文件中定义的接口外,还需要使用 socket 方式启动文件并将 sock 文件存放在 `/tmp/runtime/component-sockets` 默认路径下, | ||
也可以通过环境变量 `LAYOTTO_COMPONENTS_SOCKETS_FOLDER` 修改 sock 存储路径位置。 | ||
> 3. 除此之外,用户还需要注册 reflection 服务到 grpc server 中,用于 layotto 服务发现时获取该 grpc 服务具体实现接口的 spec。 具体代码可以参考 `demo/pluggable/hello/main.go` | ||
## step2. 启动 Layotto | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"github.com/golang/protobuf/ptypes/empty" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/reflection" | ||
pb "mosn.io/layotto/spec/proto/pluggable/v1/hello" | ||
"net" | ||
"os" | ||
) | ||
|
||
const ( | ||
AuthToken = "123456" // token 校验 | ||
TokenConfigKey = "token" | ||
SocketFilePath = "/tmp/runtime/component-sockets/hello-grpc-demo.sock" | ||
) | ||
|
||
type HelloService struct { | ||
pb.UnimplementedHelloServer | ||
hello string | ||
token string | ||
} | ||
|
||
func (h *HelloService) Init(ctx context.Context, config *pb.HelloConfig) (*empty.Empty, error) { | ||
h.hello = config.GetHelloString() | ||
h.token = config.Metadata[TokenConfigKey] | ||
if h.token != AuthToken { | ||
return nil, errors.New("auth failed") | ||
} | ||
|
||
return nil, nil | ||
} | ||
|
||
func (h *HelloService) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) { | ||
res := &pb.HelloResponse{ | ||
HelloString: h.hello, | ||
} | ||
return res, nil | ||
} | ||
|
||
func main() { | ||
listen, err := net.Listen("unix", SocketFilePath) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer os.RemoveAll(SocketFilePath) | ||
|
||
server := grpc.NewServer() | ||
srv := &HelloService{} | ||
pb.RegisterHelloServer(server, srv) | ||
reflection.Register(server) | ||
|
||
fmt.Println("start grpc server") | ||
if err := server.Serve(listen); err != nil && !errors.Is(err, net.ErrClosed) { | ||
fmt.Println(err) | ||
} | ||
} | ||
```shell | ||
cd cmd/layotto | ||
go build -o layotto . | ||
./layotto start -c ../../configs/config_hello_component.json | ||
``` | ||
|
||
1. 实现对应组件 proto 文件的 grpc 服务。 | ||
2. 启动 socket 服务,sock 文件需放置在 `/tmp/runtime/component-sockets` 下,也可以使用 `LAYOTTO_COMPONENTS_SOCKETS_FOLDER` 环境变量进行设置。 | ||
3. 注册 grpc 服务,除了注册 hello 服务外,还需要注册 reflection 服务。该服务用于 layotto 服务发现时,获取该 socket 服务具体实现了哪些 proto 文件定义的服务。 | ||
4. 启动服务 | ||
|
||
## 注册组件 | ||
|
||
填写配置文件,在对应组件下添加相关配置项,以上述的 hello 组件为例。 | ||
|
||
```json | ||
"grpc_config": { | ||
"hellos": { | ||
"helloworld": { | ||
"type": "hello-grpc-demo", | ||
"hello": "hello", | ||
"metadata": { | ||
"token": "123456" | ||
} | ||
} | ||
} | ||
} | ||
> 配置文件中填写组件的 type 为 `hello-grpc-demo`,由 socket 文件的前缀名决定。 配置项与注册普通 hello 组件一致。提供 metadata 项,便于用户设置自定义配置需求。 | ||
## step3. 组件校验 | ||
|
||
基于现有的组件测试代码,来测试用户实现的可插拔组件的正确性。 | ||
|
||
```shell | ||
cd demo/hello/common | ||
go run . -s helloworld | ||
``` | ||
|
||
组件的 type 为 `hello-grpc-demo`,由 socket 文件的前缀名决定。 | ||
程序输出以下结果表示可插拔组件注册运行成功 | ||
```shell | ||
runtime client initializing for: 127.0.0.1:34904 | ||
hello | ||
``` | ||
|
||
配置项与注册普通 hello 组件一致。提供 metadata 项,便于用户设置自定义配置需求。 | ||
## 了解 Layotto 可插拔组件的实现原理 | ||
|
||
如果您对实现原理感兴趣,或者想扩展一些功能,可以阅读[可插拔组件的设计文档](zh/design/pluggable/design.md) |