vlambda博客
学习文章列表

聊一聊和Nacos 2.0.0对接那些事

前言

nacos 2.0.0 已经发布了 alpha1, alpha2 和 beta 三个版本了,部分测试报告也已经出来了。

  • Nacos2.0.0-ALPHA2 服务发现性能测试报告
  • Nacos 2.0.0-ALPHA2 配置性能测试报告

还是比较值得期待的。

前段时间也一直在完善 nacos-sdk-csharp 这个项目。

主要就是对接 Nacos 2.0.0 这一块,也考虑到之前主要是针对Open API封装,同时参考JAVA的SDK进行功能叠加。

这一次就索性全部重新来过了,也对齐 JAVA SDK 提供的方法。

这其中最为重要的应该是底层协议由 HTTP 换成 gRPC,也是长轮询到长连接的一个跨越。

现在就和大家简单梳理一下老黄在对接中认为要注意的地方。

这里以 nacos 2.0.0 beta 版本为准,后续版本可能会有变化。

端口

nacos 的默认端口是 8848,也是之前 HTTP 协议对接时的请求端口,那么我们是不是通过 8848 这个端口进行 gRPC 的交互呢?

答案是否定的!

nacos 里面做了一个约定,把 gRPC 的服务端口设置成 nacos 启动的端口加 1000。

也就是说,nacos 的端口是 8848 的话,那么 gRPC 服务端口就是 9848

所以这里是第一个注意的点。

proto 文件

下面是 nacos 提供的 proto 文件,这个是SDK和Server交互的基础。

syntax = "proto3";

import "google/protobuf/any.proto";
import "google/protobuf/timestamp.proto";

option java_multiple_files = true;
option java_package = "com.alibaba.nacos.api.grpc.auto";

message Metadata {
string type = 3;
map<string, string> headers = 7;
}

message Payload {
Metadata metadata = 2;
google.protobuf.Any body = 3;
}

service RequestStream {
// build a streamRequest
rpc requestStream (Payload) returns (stream Payload) {
}
}

service Request {
// Sends a commonRequest
rpc request (Payload) returns (Payload) {
}
}

service BiRequestStream {
// Sends a commonRequest
rpc requestBiStream (stream Payload) returns (stream Payload) {
}
}

这里有 3 个 service,其中 RequestStream 这个在实际对接中是没有使用到的。所以只介绍其他两个。

Request 这个是通用请求,发布配置,注册服务之类的请求都是通过这个方法来交互的。

BiRequestStream 这个是双向流,主要是用来注册连接,和一些监听回调。

Nacos 1.x 里面, 配置的监听回调是基于长轮询机制,服务的监听回调是基于udp机制。

再来看看 service 的参数和响应。

Payload 的设计是有两个部分, 一个是自定义类型的 metadata, 一个是 Any 类型的 body

metadata 里面有一个 type 字段,这个字段代表的是客户端和服务端交互的 RPC 语义。好比说,我要发布配置,就是通过这个 type 告诉服务端,当前请求是要做什么。

body 这个在交互时需要做一下转换,拿到一个 object 对象,序列化成一个 JSON 字符串,最后在转化成 Any 类型的 value。

下面是一个简单的示例:

var body = new Google.Protobuf.WellKnownTypes.Any
{
    // convert the request paramter to a json string, as the body
    Value = Google.Protobuf.ByteString.CopyFromUtf8(request.ToJsonString())
};

这里有一个要注意的地方,在生成 C# 代码后,会因为参数名和方法名一样造成编译不过,所以这里要修改一下生成代码的参数名。

对接

知道了服务端的端口, proto 文件也有了,接下来就可以和服务端对接了。

想要和服务端对接上,成功获取到正确的数据,其实还有不少内容的。

下面老黄拆成 3 个小节来说。

建立连接

Step 1:

与 gRPC 服务端进行交互,首先就是要创建一个 Channel ,这里用的是 Insecure 的方式,不需要提供额外的证书信息。

Step 2:

创建 Request 请求客户端,并发起 ServerCheckRequest 请求,检查服务是否可用,不可用就直接关闭这个 Channel 了。

Step 3:

创建 BiRequestStream 请求客户端,注册处理服务端推送的相关操作,主要是配置和服务的变更。

注册完成后,还要发送 ConnectionSetupRequest 请求和 server 端建立真正意义上的连接。

这一步至关重要,因为这一步过后,服务端会把这个连接维护到客户端的连接管理里面,后续的请求会通过这个来判断是不是合法的请求。可以理解成拿到了大门的钥匙。

这一步完成之后,就可以通过 Request 发送请求了。

请求与响应

这里的请求,指的是通过 Request 发起的。

前面有提到,body 参数这一块,是对一个 JSON 字符串进行转化后的值。

这个 JSON 字符串大概成下面这样。

{
    "headers": {
        "h1""v1",
        "h2""v2"
    },
    "requestId""xxxx",
    "biz-prop-1""value-1",
    "biz-prop-2""value-2",
    "biz-prop-n""value-n",
}

其中, headers 和 requestId 这两个是通用参数,每个接口都应该带上,其他的就是各个接口需要什么就加什么。

响应的话会有正常和异常。

正常的话,返回的 type 是和请求的 type 相对应的。

好比 ConfigPublishRequest 就会对应 ConfigPublishResponse。

如果服务端处理异常了,就会返 ErrorResponse

这里的异常可以分为两类。

  1. 请求没有注册
{"resultCode":500,"errorCode":301,"message":"Connection is unregistered.","success":false

出现这种情况后,客户端这边是要重新和服务端进行连接,不然所有的请求都会是这个返回。

可能的原因有:

  • 在请求之前没有提前在双向流里面发起建立连接的请求。
  • 客户端与服务端断开过连接
  1. 请求处理失败

这个一般就是服务端处理出现了异常。

重新连接

如果响应告诉客户端请求没有注册,这个时候要及时触发重新连接,这样才不会让业务受到影响。

到这里其实对接相关的内容基本差不多了,剩下的就是对接具体的请求和其他操作了。

也附上一张老黄之前画的粗糙的图。

写在最后

老黄参与的 nacos-sdk-csharp 目前已经基本适配好了 nacos 2.0.0 beta 版本,但是还有许多细节需要慢慢的调整和改进。

希望有感兴趣的大佬一起参与到这个项目来。