Retry

集群中有client、server1, server2三台机器,client需要向server请求数据,如果server1响应超时,则请求server2。server1、server2互为备份,包含同样的数据。

client:

for (id = 0; id < 2; id++)
{
   if (TIMEOUT == do_request(server[id], timeout, req) )
   {
          continue; // retry next server
   }
}

timeout是外部传给client的总超时数。上面的代码有一个问题:当网络阻塞或者server十分繁忙的时候,do_request会超时,一旦超时,则总超时时间都被耗尽,根本没有剩余时间去重试下一个server。

因此,正确的retry设计需要考虑到“网络阻塞或者server十分繁忙”的情况,分给每个server的timeout时间只能是总timeout的一部分,代码改写如下:

for (id = 0; id < 2; id++)
{
   if (TIMEOUT == do_request(server[id], timeout * get_timeout_percent(), req) )
   {
          continue; // retry next server
   }
}

不过,对于server挂掉的情况(socket层面无法连接)do_request请求这个server会立即失败,可以不设置timeout_percent。

Backup Request

Jeff Dean的一篇论文中介绍了Google利用backup request来大幅度降低响应延迟的问题,在论文中他将这种请求成为Tied Request。他在Achieving Rapid Response Times in Large Online Services这篇ppt中对此进行了专门的论述。

其原理很简单,用一个例子来简单阐述:

集群中有client、server1, server2三台机器,client需要向server请求数据,如果server1响应超时,则请求server2。server1、server2互为备份,包含同样的数据。client收到任意响应数据后立即通知其他请求过的server取消操作。

有两种设计方案:

方案一:

  1. client向server1发出req请求,req在server1任务队列中排队
  2. server1开始执行req,在执行前给client发一个quick response
  3. client如果在超时时间内收到quick response则不发起backup task,否则client一旦超时,就立即发起backup task
  4. client收到任意server的结果时,立即给其它所有发给过请求的server发cancel request
  5. client先行退出
  6. 对于执行任务的server,它如果及时收到了cancel request,则直接取消任务,如果收到不及时,任务已经开始,则还是老老实实做任务。任务做完后丢弃结果。
  7. client收到过期的结果直接丢弃

方案二:

  1. client向server1发出req请求
  2. client等待超时,则立即向server2发req请求
  3. 任意server返回了req结果,则发cancel request给其它相关server
  4. client收到过期的结果直接丢弃

note:无论方案1还是方案二,实现这样的异步系统的时候都要很小心,一要防止内存泄露,一要方式提前析构导致野指针。

超时如何选择

建议选择p99或者p95,因为backup request操作是用来实现消除长尾的,并不是提升性能的。如果将该值设置过低,则会由于backup request的请求量过大而导致集群压力增大(假设选择p50作为其延时,这样便会有50%的请求向server2发送请求,系统负载便会增大50%)。

如果超时设置的是p999时间,大约1000个请求里只有1个请求会发送backup request,因此额外请求量(也就是开启backup request的额外开销)比例在0.1%左右。依此类推,若想要降低P99时延,则可以将超时设置为P99延迟,由此会增加1%的额外读流量。

设计要点

设计Backup request的关键是要防止服务器繁忙时期的请求风暴。在服务器繁忙时期client容易发生等待超时,倾向于发送backup request。大量的backup request会进一步让服务器更繁忙,于是请求风暴诞生了。防止请求风暴的要点是区分普通超时和风暴期超时。

从统计的角度看,普通超时的模式与风暴期超时的模式肯定有很大区别,这是一个入手点。

从使用方式上,区分scan和get也可以一定程度防止请求风暴。在OceanBase中,get请求是对延迟敏感的,scan请求则要求低一些。而恰好get请求对系统的压力也小很多。所以,在OceanBase中可以只对get请求使用backup request。

对于非幂等性操作慎用backup request!!!

小结

retry和backup request之前的区别在于retry不会给server发送cancel request,也不会等待多次请求使用最先返回的响应。

转载CSDN且有完善和修改

posted @ 2021-07-06 17:04 彭伟 阅读(1453) 评论(0) 推荐(1) 编辑
摘要: 以前我们只能在Linux或者WSL里使用dotnet-dump+调试Linux Core Dump,没有图形界面,只有一个一个得敲命令,但现在可以使用强大的Visual Studio调试了。 前提条件: Visual Studio 16.8 .NET Core 3.1.7+ 使用Visual Stu 阅读全文
posted @ 2020-11-13 21:23 彭伟 阅读(478) 评论(0) 推荐(1) 编辑
摘要: Harmony是一个开放源代码库,旨在在运行时替换、修饰或修改任何现有C#方法。它的主要用在用Mono语言编写的游戏和插件,但是该技术可以与任何.NET版本一起使用。它还照顾对同一方法的多次更改(它们累积而不是覆盖)。 它为每个原始方法创建DynamicMethod方法,并向其织入代码,该代码在开始 阅读全文
posted @ 2020-02-20 16:38 彭伟 阅读(2263) 评论(0) 推荐(1) 编辑
摘要: 大家经常出现同步调用Redis超时的问题,但改成异步之后发现错误非常少了,但却可能通过前后记日志之类的发现Redis命令非常慢。 PS: 以后代码都在Windows bash中运行,StackExchange.Redis版本为1.2.6 先快速重现问题和解决问题,大家先运行下面的代码 public 阅读全文
posted @ 2018-07-21 19:01 彭伟 阅读(5633) 评论(13) 推荐(6) 编辑
摘要: 公司数据库使用sql server 2014 AlwaysOn+硬件LB做读写分离,有好几个AlwaysOn集群,此次事故由多个条件共同发生造成的。事故相关有两个集群,这两个集群节点结构如下: 主集群A(核心集群)结点结构如下: 写:DB-01 读:DB-02(同步) DB-06(异步) DB-09 阅读全文
posted @ 2017-03-16 11:03 彭伟 阅读(363) 评论(0) 推荐(0) 编辑
摘要: 在页面头部加入可简单CSS Hack,IE6、IE7、IE8jQuery兼容代码 阅读全文
posted @ 2013-09-04 20:39 彭伟 阅读(216) 评论(0) 推荐(0) 编辑
摘要: 图片水平居中很简单,text-align: center即可,但垂直居中比较麻烦vertical-align: middle可不一定有效,在IE6下更加麻烦 阅读全文
posted @ 2012-10-15 15:50 彭伟 阅读(2313) 评论(2) 推荐(1) 编辑
摘要: 你还在为如何删除之前的空行而苦恼吗?这里有你想要的解决方案 阅读全文
posted @ 2012-09-02 20:30 彭伟 阅读(2646) 评论(10) 推荐(3) 编辑
摘要: 当将a标签设置为display:block时在IE下会出现“Empty Text Node”,在某些情况下会将高度撑高。解决办法是添加zoom:1。a { display: block; zoom: 1; } 阅读全文
posted @ 2012-08-09 16:58 彭伟 阅读(486) 评论(0) 推荐(0) 编辑
摘要: 众说周知,Main方法是.net程序的入口,那有什么方法可以在Main方法之前执行代码呢? 阅读全文
posted @ 2012-04-20 13:21 彭伟 阅读(4169) 评论(17) 推荐(5) 编辑
点击右上角即可分享
微信分享提示