提高RPC Server throughput的请求延时回复处理

前言


在一套完整的分布式系统中,client端向server端发起一个请求,然后client等待此请求被server端处理完毕,然后接受到serve的返回结果。自此一个请求就算作是被处理完了。这种block等待处理结果的请求处理行为在我们日常的系统中十分的常见。但是这种处理方式的一个明显弊端是,未处理完成的请求势必会占住server端的处理资源。因此一般常见的改进做法是提高server端的Handler数量,来提高服务端的请求并发处理能力,这种做法是比较简单直接的。但其实这里还有另外一个方向点的优化,是否能够提高单个请求的处理时间来做优化呢?比如一些已经被处理完毕的请求,但是正处于返回response结果的,这也是会占着Handler资源的。因为返回response操作也是在请求被处理环节的一部分。假设说我们能将回复请求的阶段从处理请求方法中拆分出去,通过延时返回的方式,毫无疑问,这也会在一定程度上提高server端的throughput。本文笔者来聊聊关于RPC Server请求的回复延时处理以及Hadoop RPC Server是如何做这部分优化的。

Server端延时请求回复的优劣势


按照前面我们所说的,如果将server端的<请求即刻处理->请求即时回复>变为<请求即刻处理->请求延时恢复>,它会给整个系统带来怎样的变化呢?

以下是其所带来的好的一面和不好的一面:

优势:
增大系统整体的throughput,因为请求结果回复变为了延时异步的方式,这相当于提早释放了Handler的资源,让Handler能够马上接下来处理其它客户端的请求。

弊端:

  • 请求回复的延时处理意味着server端于client的open connection会增多,因为client的请求回复还没有被执行,这些连接并没有被关闭。
  • Server端因为此改动接受了过多的请求,导致请求回复阶段成为bottleneck。

Hadoop RPC Server的请求延时回复处理


下面我们通过Hadoop RPC Server内部目前已经优化了的请求回复处理例子,来具体了解下这部分的处理逻辑。

样例一:增加延时请求计数的处理

这个改动源自Hadoop社区JIRA:HADOOP-10300:Allowed deferred sending of call responses

它的一个主要思路是这样的:

1) 在每个PRC call里面多添加了一个请求等待的计数值,初始值为1
2)正常情况下,Server端在处理完请求后,会执行sendResponse方法,然后会将上述计数值做减1操作,然后执行请求回复操作。
3)但是,如果我们想要做请求的延时回复处理,我们可以额外执行一个postponeResponse的方法来增大请求回复等待的计数值。这样的话,在正常逻辑中的sendResponse则不会实际执行请求回复操作,它只做计数值的减操作。只有再第二次Server被触发执行了sendResponse后,才会执行请求回复操作。

相关代码如下:

/** 请求回复等待计数值 */
private AtomicInteger responseWaitCount = new AtomicInteger(1);

...

 
/**
 * Allow a IPC response to be postponed instead of sent immediately
 * after the handler returns from the proxy method.  The intended use
 * case is freeing up the handler thread when the response is known,
 * but an expensive pre-condition must be satisfied before it's sent
 * to the client.
 */
@InterfaceStability.Unstable
@InterfaceAudience.LimitedPrivate({
   "HDFS"})
public void postponeResponse() {
   
  // 执行延时回复处理,将计数值加1
  int count = responseWaitCount.incrementAndGet();
  assert count > 0 : "response has already been sent";
}

@InterfaceStability.Unstable
@InterfaceAudience.LimitedPrivate({
   "HDFS"})
public void sendResponse() throws IOException {
   
  // 执行请求回复操作时,减小计数值
  int count = responseWaitCount.decrementAndGet();
  assert count >= 0 : "response has already been sent";
  // 如果计数值为0了,则进行实际回复返回操作,否则不进行response信息的返回
  if (count == 0) {
   
    assert rpcResponse != null : "response has not been set";
    connection.sendResponse(this);
  }
}

下面是对应的testcase:

// Test that IPC calls can be marked for a deferred response.
// call 0: immediate
// call 1: immediate
// call 2: delayed with wait for 1 sendResponse, check if blocked
// call 3: immediate, proves handler is freed
// call 4: delayed with wait for 2 sendResponses, check if blocked
// call 2: sendResponse, should return
// call 4: sendResponse, should remain blocked
// call 5: immediate, prove handler is still free
// call 4: sendResponse, expect it to return
@Test(timeout=10000)
public void testDeferResponse() throws IOException, InterruptedException {
   
  final AtomicReference<Call> deferredCall = new AtomicReference<Call>();
  final AtomicInteger count = new AtomicInteger();
  final Writable wait0 = new IntWritable(0);
  final Writable wait1 = new IntWritable(1);
  final Writable wait2 = new IntWritable(2);
  
  // use only 1 handler to prove it's freed after every call
  Server server = new Server(ADDRESS, 0, IntWritable.class, 1, conf){
   
    @Override
    public Writable call(RPC.RpcKind rpcKind, String protocol,
        Writable waitCount, long receiveTime) throws IOException {
   
      Call call = Server.getCurCall().get();
      int wait = ((IntWritable)waitCount).get();
      // 根据传入的wait次数值,做postponeResponse的处理,意为这个call需要做额外对应次数的sendResponse方法才会有结果返回
      while (wait-- > 0) {
   
        call.postponeResponse();
        deferredCall.set(call);
      }
      return new IntWritable(count.getAndIncrement());
    }
  };
  server.start();
  
  final InetSocketAddress address = NetUtils.getConnectAddress(server);
  final Client client = new Client(IntWritable.class, conf);
  Call[] waitingCalls = new Call[2];
      
  // calls should return immediately, check the sequence number is
  // increasing
  assertEquals(0
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值