gRPC 对冲原理

gRPC 专栏收录该内容
28 篇文章 0 订阅

gRPC 对冲原理

gRPC 对冲开启后,当请求在指定的时间间隔后没有返回时,会发起对冲请求,继续等待,如果依然没有返回,则重复发送直到接收到返回结果或者超时取消

对冲适用于当下游服务部分节点故障无法及时响应或者响应不及时的场景,通过对冲可以减少请求的失败率,但是可能会导致延时增加

对冲和重试的流程相似,在第一次发起请求的时候根据服务名和方法名决定使用哪种策略;如果是对冲策略,则在发起请求时提交一个延时任务,这个任务会发起一个新的请求,并在执行的时候再发起一个请求,并将这些请求添加到队列中;多个请求哪个先返回就使用哪个请求的结果,将其他的请求取消并提交流

执行流程

  • io.grpc.internal.RetriableStream#start

开始第一个 RPC 调用

  @Override
  public final void start(ClientStreamListener listener) {
    // 构造一个 BufferEntry
    class StartEntry implements BufferEntry {
      @Override
      public void runWith(Substream substream) {
        substream.stream.start(new Sublistener(substream));
      }
    }

    synchronized (lock) {
      // 新建 BufferEntry,添加到 buffer 中
      state.buffer.add(new StartEntry());
    }

    // 创建 Substream
    Substream substream = createSubstream(0);
    hedgingPolicy = hedgingPolicyProvider.get();
    // 如果有对冲策略
    if (!HedgingPolicy.DEFAULT.equals(hedgingPolicy)) {
      // 如果对冲策略有效,则将重试策略置为 null
      isHedging = true;
      retryPolicy = RetryPolicy.DEFAULT;

      FutureCanceller scheduledHedgingRef = null;

      synchronized (lock) {
        // 将这个流添加到对冲中
        state = state.addActiveHedge(substream);
        // 没有提交的流,且没有达到最大对冲次数,且没有终止,且没有节流或没有达到节流阈值
        // 则创建对冲 Future
        if (hasPotentialHedging(state) && (throttle == null || throttle.isAboveThreshold())) {
          scheduledHedging = scheduledHedgingRef = new FutureCanceller(lock);
        }
      }

      // 如果对冲请求不为空,则提交延时任务
      if (scheduledHedgingRef != null) {
        scheduledHedgingRef.setFuture(
                scheduledExecutorService.schedule(
                        new HedgingRunnable(scheduledHedgingRef),
                        hedgingPolicy.hedgingDelayNanos,
                        TimeUnit.NANOSECONDS)
        );
      }
    }
    // 消耗缓冲的请求
    drain(substream);
  }
  • io.grpc.internal.RetriableStream.HedgingRunnable

对冲任务,在执行的时候发起请求,并根据当前的提交的请求数量、状态等判断是否需要取消,如果不取消则再次提交一个延时任务

  private final class HedgingRunnable implements Runnable {
    @Override
    public void run() {
      callExecutor.execute(new Runnable() {
        @Override
        public void run() {
          // 创建对冲流
          Substream newSubstream = createSubstream(state.hedgingAttemptCount);
          boolean cancelled = false;
          FutureCanceller future = null;

          synchronized (lock) {
            // 如果请求被取消了,则取消流
            if (scheduledHedgingRef.isCancelled()) {
              cancelled = true;
            } else {
              // 将新创建的流添加到对冲流集合中
              state = state.addActiveHedge(newSubstream);
              // 没有提交的流,且没有达到最大对冲次数,且没有终止,且没有节流或者没有达到节流阈值,
              // 则创建 Future
              if (hasPotentialHedging(state) && (throttle == null || throttle.isAboveThreshold())) {
                scheduledHedging = future = new FutureCanceller(lock);
              } else {
                // 否则冻结对冲
                state = state.freezeHedging();
                scheduledHedging = null;
              }
            }
          }

          // 如果请求已经取消了,则取消流并返回
          if (cancelled) {
            newSubstream.stream.cancel(Status.CANCELLED.withDescription("Unneeded hedging"));
            return;
          }
          // 如果对冲请求不为空,则提交延时任务
          if (future != null) {
            future.setFuture(
                    scheduledExecutorService.schedule(
                            new HedgingRunnable(future),
                            hedgingPolicy.hedgingDelayNanos,
                            TimeUnit.NANOSECONDS));
          }
          // 消耗缓冲的请求
          drain(newSubstream);
        }
      });
    }
  }
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页

打赏

呜呜呜啦啦啦

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值