RPC 集群,gRPC 广播和组播

一、集群抽象:cluster

它是指我们在调用远程的时候,尝试解决:

1、failover:即引入重试功能,但是重试的时候会换一个新节点

2、failfast: 立刻失败,不需要重试

3、广播:将请求发送到所有的节点上

4、组播:组播和分组功能不太一样,组播是指请求发送到一组节点上,而不是只发送到一个单一节点上

注意:failover

二、 gRPC 的 Interceptor 分成好几种:

UnaryClientInterceptor: 用于拦截 gRPC unary 请求

StreamClientIntercepror 用于拦截 gRPC 的 stream 请求。

三、gRPC 广播:注册中心获取所有节点

思路:

利用拦截器捕获调用

利用注册中心来获取所有的服务实例

在拦截器内遍历所有的服务端实例

四、gRPC 限流:

利用服务端拦截器调用,进行限流逻辑

五、gRPC 广播实现

gRPC 广播利用客户端拦截器实现,步骤也非常简单,以下几步:

1、利用注册中心获取所有节点

2、利用filter 过滤节点

3、grpc.Dial 循环调用节点,发起tcp 请求

注意:reflect.TypeOf(reply).Elem() 以及 reflect.New(typ).Interface() 生成一个新的Reply 避免覆盖, filter 是nil 就是广播,非nil 就是组播

对节点进行过滤

type MyIntercaptor struct {
   register registry.Register
   method   string
   filter   Filter
}
​
type SetOptions func(optins *MyIntercaptor)
​
func NewMyInterceptor(register registry.Register, method string, options ...SetOptions) *MyIntercaptor {
   t := &MyIntercaptor{
      register: register,
      method:   method,
      filter: func(g1 string, ctx context.Context) bool {
         return true
      },
   }
   for _, opt := range options {
      opt(t)
   }
   return t
}
​
func WithMyInterSetFilter(filter Filter) SetOptions {
   return func(option *MyIntercaptor) {
      option.filter = filter
   }
}
​
func (m *MyIntercaptor) Intercaptor() grpc.UnaryClientInterceptor {
   return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
      list, er := m.register.ListServices(ctx, m.method)
      if er != nil {
         return er
      }
      // 是否是广播
      ok, resp := IsBroadCast(ctx)
      defer func() {
         close(resp)
      }()
      if !ok {
         return invoker(ctx, method, req, reply, cc, opts...)
      }
      var err errgroup.Group
      for _, li := range list {
         if !m.filter(li.Group, ctx) {
            continue
         }
         if li.Addr == "" {
            continue
         }
         typ := reflect.TypeOf(reply).Elem()
         addr := li.Addr
         // 并发调用
         err.Go(func() error {
            dial, er := grpc.Dial(addr, grpc.WithInsecure())
            if er != nil {
               resp <- Resp{
                  Err: er,
               }
               return nil
            }
            rep := reflect.New(typ).Interface()
            // 发送方法请求
            er = invoker(ctx, method, req, rep, dial, opts...)
            resp <- Resp{
               Err:   er,
               Reply: rep,
            }
            return nil
         })
​
      }
      return err.Wait()
   }
}
​
type Filter func(g1 string, ctx context.Context) bool
​
func NewFilter() Filter {
   return func(g1 string, ctx context.Context) bool {
      group, ok := ctx.Value("group").(string)
      return ok && group == g1
   }
}
​
type broadcastKey struct {
}
​
func UseBroadcastKey(ctx context.Context) (context.Context, chan Resp) {
   ch := make(chan Resp)
   return context.WithValue(ctx, broadcastKey{}, ch), ch
}
​
func IsBroadCast(ctx context.Context) (bool, chan Resp) {
   resp, ok := ctx.Value(broadcastKey{}).(chan Resp)
   return ok, resp
}
​
type Resp struct {
   Err   error
   Reply any
}

<think>嗯,用户问的是关于Nacos RPC的面试题,我需要先理清楚NacosRPC的关系。Nacos作为阿里巴巴开源的配置中心服务发现件,通常RPC框架比如Dubbo一起使用。但用户可能想知道Nacos自身是否涉及RPC机制,或者面试中常问的相关问题。 首先,我得回忆Nacos的基本功能,服务注册与发现、配置管理,这些是核心。然后考虑RPC部分,Nacos本身不处理RPC通信,但作为注册中心,它为RPC框架提供服务发现的能力。所以面试题可能围绕Nacos如何集成到RPC框架中,比如Dubbo如何利用Nacos进行服务发现。 接下来,常见的面试问题可能包括Nacos的服务注册流程、心跳机制、健康检查,以及与Eureka的区别。同时,Nacos的CPAP模式切换,一致性协议如Raft,这些也是重点。需要解释Nacos在RPC中的作用,比如服务发现如何帮助RPC客户端找到可用的服务节点。 用户可能需要具体的例子,比如NacosDubbo的整合配置,或者如何处理服务下线的情况。还有可能涉及高可用性、负载均衡策略,以及Nacos的配置中心如何动态更新服务配置,影响RPC调用。 还要注意区分Nacos本身不实现RPC,而是支撑RPC框架的服务治理部分。因此,面试题可能考察对微服务架构中各个件职责的理解,比如Nacos负责服务注册发现,Dubbo负责RPC通信,两者如何协同工作。 另外,可能的问题包括Nacos的持久化机制,集群部署方式,如何保证数据一致性,以及如何处理网络分区的情况。这些都是Nacos作为注册中心在RPC场景下的关键点。 最后,需要总结常见的面试考点,比如Nacos的核心功能、与RPC框架的集成、高可用设计、一致性模型等,帮助用户系统化准备。可能还需要提到实际项目中遇到的问题解决方案,展示深入理解。</think>以下是关于Nacos与RPC的常见面试考点及解析,建议结合项目经验理解原理: --- ### **1. Nacos核心功能** - **服务注册与发现**:微服务通过Nacos注册地址,RPC客户端通过Nacos动态获取可用服务节点 - **配置中心**:支持动态配置管理,可实时调整RPC超时时间、负载均衡策略等参数 - **健康检查**:主动探测服务状态,自动剔除异常节点(TCP/HTTP探测) --- ### **2. Nacos与RPC框架协作** **典型流程**: ```java // Dubbo + Nacos示例 @DubboReference(version = "1.0.0", check = false) private UserService userService; // RPC客户端通过Nacos发现服务地址 ``` 1. 服务提供者启动时向Nacos注册元数据 2. 消费者通过Nacos订阅服务列表 3. RPC框架(如Dubbo/gRPC)基于负载均衡策略选择目标节点 4. 长连接建立后直接进行网络通信 --- ### **3. 高频面试题** #### **(1) Nacos服务注册发现原理** - **注册流程**:服务实例发送心跳包(默认5秒)到Nacos Server - **数据存储**:临时实例用内存存储(AP模式),持久化实例用Raft协议(CP模式) - **服务发现**:客户端定时拉取服务列表,本地缓存+增量更新 #### **(2) Nacos与Eureka区别** | 特性 | Nacos | Eureka | |--------------------|--------------------------------|------------------------| | 一致性协议 | AP+CP可切换 | AP模型 | | 健康检查 | TCP/HTTP/MYSQL/客户端上报 | 客户端心跳 | | 配置中心 | 原生支持 | 需配合Spring Cloud Config | | 服务权重 | 支持 | 不支持 | #### **(3) 如何保证高可用?** - **集群部署**:至少3节点集群,使用内嵌Raft协议保证数据一致性 - **数据持久化**:配置MySQL存储持久化数据(默认使用内嵌Derby) - **故障转移**:客户端自动重连其他可用节点 #### **(4) Nacos如何处理服务雪崩?** - **保护阈值**:设置比例(如0-1),当健康实例比例低于阈值时,仍返回不健康节点 - **熔断机制**:结合Sentinel实现RPC调用的熔断降级 - **集群隔离**:不同业务使用不同Namespace/Group --- ### **4. 进阶问题** **Q:Nacos如何实现配置动态推送?** - 客户端长轮询(Long Polling)监听配置变更 - Server端使用UDP广播+HTTP对比MD5值的方式减少网络开销 **Q:如何设计一个服务注册中心?** - 参考Nacos架构: 1. 数据分区(临时/持久化) 2. 心跳续约机制 3. 多级缓存(内存注册表+本地文件快照) 4. 集群一致性协议(Raft/Distro) 5. 开放OpenAPISDK --- ### **5. 实践建议** - **故障场景模拟**:主动断开Nacos节点,观察服务发现是否正常 - **性能调优**:调整心跳间隔(`spring.cloud.nacos.discovery.heartbeatInterval`) - **安全加固**:开启鉴权(`nacos.core.auth.enabled=true`) 建议结合源码分析核心类:`NacosNamingService`(注册发现)、`ConfigService`(配置管理)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值