gRPC 推送模式(Nacos 2.0 新特性) 源码详解

Nacos 2.0 引入了基于 gRPC 的长连接通信模型,彻底重构了客户端与服务端的通信方式,取代了 1.x 版本中基于 HTTP 短连接 + 轮询 + HTTP Push 的模式。这一变革带来了 更低延迟、更高吞吐、更可靠的配置推送与服务发现能力

本文将从 源码角度 深入解析 Nacos 2.0 的 gRPC 推送模式,涵盖:

  • gRPC 长连接的建立
  • 客户端注册与连接管理
  • 服务端如何通过 Stream 推送配置变更
  • 客户端接收与响应
  • 心跳与连接保活
  • 故障恢复机制

一、gRPC 推送的核心优势(对比 Nacos 1.x)

特性Nacos 1.x(HTTP)Nacos 2.0(gRPC)
通信协议HTTP 短连接gRPC 长连接(基于 HTTP/2)
配置推送HTTP Push(不可靠)Stream 流式推送(可靠)
服务发现客户端轮询服务端主动通知
连接管理无状态有状态连接(Connection)
性能高延迟、高资源消耗低延迟、高并发、低开销

二、核心模块与源码包结构

com.alibaba.nacos.core.remote
├── grpc.GrpcConnection                  // gRPC 连接封装
├── grpc.GrpcServer                      // gRPC 服务端
├── grpc.BiRequestStreamObserver       // 双向流观察者
├── service.RemoteConnectionService    // 连接管理服务
└── controller.ConnectionController    // 连接状态查询接口

com.alibaba.nacos.naming.remote.grpc
├── NamingGrpcService                  // 服务发现 gRPC 服务
└── NamingPushService                  // 服务端推送实现

com.alibaba.nacos.config.remote.grpc
├── ConfigGrpcService                  // 配置中心 gRPC 服务
└── ConfigPushService                  // 配置推送实现

三、gRPC 长连接建立流程

1. 客户端启动:GrpcClient

// com.alibaba.nacos.common.remote.client.grpc.GrpcClient
public class GrpcClient extends Client {

    @Override
    public void connectToServer(ServerInfo serverInfo) {
        // 构建 gRPC Channel
        ManagedChannel channel = NettyChannelBuilder
            .forAddress(serverInfo.getIp(), serverInfo.getGrpcPort())
            .usePlaintext() // 默认不加密
            .keepAliveTime(30, TimeUnit.SECONDS)
            .build();

        // 创建双向流 Stub
        RemoteServiceGrpc.RemoteServiceStub stub = RemoteServiceGrpc.newStub(channel);

        // 建立流式连接
        StreamObserver<Request> requestObserver = stub.requestStreaming(new ResponseStreamObserver());
        
        // 发送客户端注册请求
        RegisterRequest registerRequest = new RegisterRequest();
        registerRequest.setClientID(clientId);
        registerRequest.setLabels(getLabels()); // 包含角色:config/naming
        requestObserver.onNext(registerRequest);
    }
}
  • 使用 NettyChannelBuilder 建立 gRPC 连接(默认端口 9848)。
  • 调用 requestStreaming 建立 双向流(Bidirectional Stream)
  • 发送 RegisterRequest 注册客户端身份。

2. 服务端接收连接:BiRequestStreamObserver

// com.alibaba.nacos/core/remote/grpc/BiRequestStreamObserver.java
public class BiRequestStreamObserver implements StreamObserver<Request> {

    private final GrpcConnection connection;

    @Override
    public void onNext(Request request) {
        if (request instanceof RegisterRequest) {
            handleRegister((RegisterRequest) request);
        } else {
            // 处理其他请求
            RequestHandler handler = requestHandlerRegistry.findHandler(request);
            handler.handle(request, connection);
        }
    }

    private void handleRegister(RegisterRequest request) {
        String clientId = request.getClientID();
        String role = request.getLabels().get("role"); // 如: ConfigRole, NamingRole

        // 创建连接对象
        connection = new GrpcConnection(channel, connectionId, request.getIp(), request.getLabels());

        // 注册到连接管理器
        remoteConnectionService.registerConnection(connection);

        // 根据角色初始化处理器
        if ("ConfigRole".equals(role)) {
            configGrpcService.addConnection(connection);
        } else if ("NamingRole".equals(role)) {
            namingGrpcService.addConnection(connection);
        }

        // 回复注册成功
        Response response = Response.newBuilder().setRequestId(request.getRequestId()).setErrorCode(0).build();
        connection.getResponseObserver().onNext(response);
    }
}
  • 服务端通过 BiRequestStreamObserver 监听客户端消息流。
  • 收到 RegisterRequest 后:
    • 创建 GrpcConnection 对象
    • 注册到 RemoteConnectionService
    • 按角色绑定到 ConfigGrpcServiceNamingGrpcService

四、配置变更推送:ConfigPushService

1. 配置发布触发推送

// com.alibaba.nacos/config/server/service/ConfigServletInner.java
public boolean publishConfig(...) {
    // ... 持久化配置

    // 触发 gRPC 推送
    NotifyCenter.publishEvent(new ConfigDataChangeEvent(...));
}

2. ConfigPushService 监听事件

// com.alibaba.nacos/config/remote/grpc/ConfigPushService.java
@EventListener
public void onConfigChange(ConfigDataChangeEvent event) {
    String dataId = event.getDataId();
    String group = event.getGroup();
    String tenant = event.getTenant();

    // 获取所有订阅该配置的客户端连接
    Set<Connection> connections = configConnectionManager.getConnections(dataId, group, tenant);

    for (Connection conn : connections) {
        // 构造推送消息
        ConfigChangeNotifyRequest notifyRequest = new ConfigChangeNotifyRequest();
        notifyRequest.setDataId(dataId);
        notifyRequest.setGroup(group);
        notifyRequest.setTenant(tenant);
        notifyRequest.setNotificationId(event.getNotificationId());

        // 通过 gRPC 连接推送
        conn.asyncRequest(notifyRequest, new RequestCallBack() {
            @Override
            public void onResponse(Response response) {
                Loggers.PUSH.info("Push ACK received from {}", conn.getMetaInfo());
            }

            @Override
            public void onFail(Throwable e) {
                // 推送失败,尝试重试或关闭连接
                retryManager.addRetryTask(new RetryTask(notifyRequest, conn));
            }
        });
    }
}
  • configConnectionManager 维护了 dataId+group → Connection 列表 的映射。
  • 使用 conn.asyncRequest() 通过 gRPC 流发送消息。
  • 支持 ACK 回调,实现可靠推送。

五、客户端接收推送

1. 客户端 ResponseStreamObserver 处理消息

// com.alibaba.nacos/common/remote/client/grpc/ResponseStreamObserver.java
public class ResponseStreamObserver implements StreamObserver<Response> {

    @Override
    public void onNext(Response response) {
        if (response instanceof ConfigChangeNotifyResponse) {
            ConfigChangeNotifyRequest request = (ConfigChangeNotifyRequest) response.getRequest();
            // 触发本地拉取最新配置
            ConfigService.notifyListenConfig(request.getDataId(), request.getGroup(), request.getTenant());
        }
    }
}
  • 客户端收到 ConfigChangeNotifyRequest
  • 调用 notifyListenConfig() 主动从服务端拉取最新配置。

六、连接管理与心跳机制

1. 心跳保活:ConnectionProbeService

// com.alibaba.nacos/core/remote/ConnectionProbeService.java
@PostConstruct
public void start() {
    GlobalExecutor.schedulePermit(this::probeAllConnections, 5, 5, TimeUnit.SECONDS);
}

private void probeAllConnections() {
    for (Connection conn : connectionManager.allConnections()) {
        if (conn.getLastActiveTime() < System.currentTimeMillis() - 30_000) {
            // 发送心跳探测
            conn.asyncRequest(new HealthCheckRequest(), resp -> {
                if (resp.getErrorCode() != 0) {
                    closeAndClean(conn);
                }
            });
        }
    }
}
  • 每 5 秒检查一次连接活跃性。
  • 超过 30 秒无通信,发送 HealthCheckRequest 探测。
  • 失败则关闭连接并清理订阅关系。

2. 连接断开处理

// BiRequestStreamObserver.onCompleted() / onError()
@Override
public void onError(Throwable t) {
    remoteConnectionService.unregisterConnection(connection);
    configConnectionManager.removeConnection(connection);
    namingConnectionManager.removeConnection(connection);
}
  • 网络异常或客户端关闭时,自动清理连接和订阅关系。

七、服务端主动推送 vs 客户端拉取

阶段方式
通知服务端 → 客户端:gRPC Stream 推送 ConfigChangeNotifyRequest
获取内容客户端 → 服务端:HTTP GET /nacos/v1/cs/configs 拉取完整配置
ACK 确认客户端 → 服务端:gRPC 返回 Response

✅ 这种“推拉结合”模式既保证了实时性,又避免了推送内容过大。


八、关键配置项

配置项默认值说明
nacos.server.grpc.port9848gRPC 服务端口
nacos.server.grpc.health.check.interval5s心跳检测间隔
nacos.remote.client.reconnect.delay2s客户端重连延迟
nacos.core.protocol.grpc.stream.max.inbound.message.size10MB最大消息大小

⚠️ Nacos 2.0 默认开启 gRPC,端口 98489849(TLS)必须开放。


九、源码调用链总结

客户端 GrpcClient.connect()
    → 发送 RegisterRequest
        → 服务端 BiRequestStreamObserver.onNext()
            → handleRegister()
                → 创建 GrpcConnection
                → 注册到 RemoteConnectionService
                    → ConfigGrpcService.addConnection()

配置发布
    → ConfigServletInner.publishConfig()
        → NotifyCenter.publishEvent(ConfigDataChangeEvent)
            → ConfigPushService.onConfigChange()
                → configConnectionManager.getConnections()
                    → conn.asyncRequest(ConfigChangeNotifyRequest)
                        → 客户端 ResponseStreamObserver.onNext()
                            → 触发本地拉取配置

十、总结

特性Nacos 2.0 gRPC 实现
通信模型双向流长连接(gRPC Streaming)
连接管理有状态连接(GrpcConnection)
推送机制服务端主动推送变更通知
可靠性ACK + 重试 + 心跳检测
性能高吞吐、低延迟、低资源占用
扩展性支持多协议、多角色(Config/Naming)

建议阅读源码路径

  1. GrpcConnection.java —— 连接封装
  2. BiRequestStreamObserver.java —— 双向流处理
  3. ConfigPushService.java —— 配置推送
  4. RemoteConnectionService.java —— 连接管理
  5. GrpcClient.java —— 客户端实现
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值