zuul网关重试机制探索

网关相关配置

1.zuul相关的默认配置 springcloud(F版)

属性 默认值 描述
zuul.retryable false 是否开启重试
ribbon.ConnectTimeout 1000 链接超时时间
ribbon.ReadTimeout 1000 读超时时间
ribbon.MaxAutoRetries 0 对第一次请求的服务的重试次数
ribbon.MaxAutoRetriesNextServer 1 要重试的下一个服务的最大数量(不包括第一个服务)
ribbon.OkToRetryOnAllOperations false 所有请求都重试
ribbon.MaxTotalHttpConnections 200 ?
ribbon.MaxConnectionsPerHost 50 ?
hystrix.command.default.execution.timeout.enabled true 是否开启

有些书上说,配置当中的ConnectTimeout和ReadTimeout是当HTTP客户使用HttpClient的时候生效的,参数会被设置到HttpClient中,但我在使用过程中,并不是只有HttpClient才会生效。

ribbon默认配置
ribbon默认配置

模拟场景

  1. 调用关系


    模拟调用关系
  2. 代码说明
    zuul主要是负责把请求转发到后面的服务上,为了模拟业务处理场景,服务暴露了一个sleep借口,接口作用是根据传过来的参数模拟业务处理时间。
    @RequestMapping(value = "/testSleep",method = 
    {RequestMethod.GET,RequestMethod.POST} )
    public ApiResult testSleep(@RequestParam("sleep") int sleep){
        logger.info("sleep..........start");
       try{
           Thread.sleep(sleep*1000);
       }
       catch (Exception e){
           logger.error(e.toString());
       }
        logger.info("sleep..........end");
        return ApiResult.SUCCESS();
    }
    
    

实验

实验一 裸奔配置(zuul全部走默认配置)

单台服务

默认情况下ribbon超时时间为1秒,我们模拟一个2秒的业务让ribbon超时。

  • 此时客户端返回了错误结果,此处进行了zuul回退机制处理


    客户端模拟
  • 业务处理2秒时,网关报了异常,日志中的ProducerFallback是因为在zuul网关中加了Fallback回退措施,打印出的异常为Read timed out


    zuul超时
  • 此时业务日志显示正常处理,时间大概为2秒


    业务调用一次
  • 结论
    我们发现现在这种情况并没有进行重试,因为我们可以看到业务日志只被调用了一次,咦!! 等等,还记得我们上面提到的MaxAutoRetries属性和MaxAutoRetriesNextServer吗,是不是因为这个所以不对当前机器进行重试,如果在不改变此值的前提下,我们再启动一台同等服务呢?

两台服务

网关超时
第一台服务命中
第二台服务未命中
  • 结论
    只有一台服务被调用,并没有重试到另一台服务上

单台服务 MaxAutoRetries修改为大于0

当MaxAutoRetries大于0时,调用也没有发生变化。
至此说明实验一中重试未起作用。

实验二 (使用okhttp)

两台服务(默认配置)

突然有一个想法,网关重试机制会不会和ribbon底层使用的http有关呢,默认情况下ribbon使用的是httpclient,那么我如果换成使用okhttp呢,于是,我把ribbon底层换成了okhttp又重复了一遍实验一


开启okhttp
  • 网关依旧超时
    但此时可以看出超时时间大致为4秒


    zuul超时3.png
  • 服务被调用了两次
    神奇的情况发生了,两台服务都被调用了,貌似自动开启了重试功能
    我们通过日志可以看出业务处理时间分别为
    18:18:11到18:18:13 处理时间2秒
    18:18:12到18:18:14 处理时间2秒
    在服务处理1秒后进行了重试


    第一台服务

    第二台服务
  • 为什么重试时网关会是4秒超时呢?
    还记我们之前的截图吗,ribbon的超时时间是通过公式计算出来的

    ribbonReadTimeout :1
    ribbonConnectTimeout:1
    maxAutoRetries:0
    maxAutoRetriesNextServer :1
    
    ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout) 
                    * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1)
    
    ribbonTimeout = (1000+1000)*(0+1)*(1+1)=4000(ms)
    
    
  • 结论
    服务打到其中一台服务器上,因为ribbon.ReadTimeout为1秒,此时业务处理时间需要2秒,所以1秒后,也就是18:18:12 的时候进行了重试,
    ribbon.MaxAutoRetries为0,所以没有在本服务进行重试,而是选择了另外一台服务。

单台服务 MaxAutoRetries修改为1

ribbon.MaxAutoRetries: 1

  • 网关超时
    但是我们细心一点可以发现,此时的网关也是4秒后超时的


    网关超时
  • 服务调用
    日志显示业务被触发了4次。1秒一次


    服务调用日志
  • 为什么服务被调用了4次
    现象应该是

    4次重试顺序.png

  • 为什么重试时网关也是4秒超时呢?
    按照我们之前的计算公式应该是8秒才对啊

     ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout) 
            * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1)
     ribbonTimeout =(1000+100)*(1+1)*(1+1)=8000(ms)
    
    

通过打印异常堆栈,可以发现其中的端倪

异常.png

异常已经清晰的告诉我们了原因:
Number of retries on next server exceeded max 1 retries ,就是重试机器的次数已经答到了设置的上限,因为我们MaxAutoRetriesNextServer设置的是1,意思就是我们重试一台。因此我们吧

单台服务 MaxAutoRetries修改为2

ribbon.MaxAutoRetries: 2

  • 网关超时时间已经变为了大概6秒


    网关6秒.png
  • 业务被调用了6次 也是一秒一次


    6次调用.png
  • 结论
    ribbon超时时间虽然是8秒,但实际过程中还要看重试策略。

实验三

zuul使用httpClient并支持重试

  • 修改pom 增加重试包
      <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
  • 打开重试开关
    zuul.retryable=true

  • 网关发起调用


    网关日志
  • 服务调用日志


    1机器被调用

    另一台机器被调用

实验总结

  • 当ribbon使用的是httpclient时,重试机制是默认关闭的,如果要启动重试机制需要在项目中引用spring-retry包,以及手工打开zuul.retryable=true设置,其实除此之外spring.cloud.loadbalancer.retry.enabled=true 也是需要设置的只不过这个值默认为true,所以此处可以忽略设置。

  • 当ribbon使用的是okhttp时,重试机制是自动打开的,重试的效果与我们设置的ribbon超时时间以及重试次数都有关系。

  • 虽然二种机制都能达到zuul网关调用的重试,但细心一点的朋友还是应该可以看出一点区别的,使用httpclient进行重试时,客户端进行重试超时返回时,控制台并没有打印Exception日志,但是当我们替换成okhttp后,控制台会打印出Exception日志 如下图对比


    日志对比

    okhttp是通过AbstractRibbonCommand.getFallbackResponse,


    AbstractRibbonCommand

    httclient是通过RibbonRoutingFilter.setResponse(ClientHttpResponse resp)
    RibbonRoutingFilter
  • 在AbstractRibbonCommand中我们可以看到两个计算时间的方式
    getRibbonTimeout 上面我们已经说过,除些之外还有一个计算hystrix的时间方法getHystrixTimeout,默认情况下hystrix超时时间defaultHystrixTimeout为0,网上大部分都说默认是1秒,但其实我认为在zuul网关这个场景下,这种说法不对的。如果我们设置了hystrix超时时间,刚会已我们设置的为准,但如果我们不设置,代码会使用ribbon的超时时间为hystrix超时时间。


    hystrixTimeout计算

    而且当hystrixTimeout设置的值小于ribbonTimeout,则会打印警告。也就是说当hystrixTimeout<ribbonTimeout ribbon的超时设置就没有意义了,因为提前触发了hystrix的服务降级策略.但是反过来,如果 hystrixTimeout>ribbonTimeout ribbonTimeout的设置也没意义了啊,因为ribbon超时了,也触发网关回退机制了,hystrixTimeout就没意思了,但感觉这点设计的比较乱。

  • 此外,重试默认都是只支持get请求,如果我把请求方式修改为post重试是不生效的,我们需要设置OkToRetryOnAllOperations为true, 这种情况不太建议,因为post请求大多都是写入请求,如果要支持重试,服务自身的幂等性一定要健壮。

zuul网关重试就先写到这,主要是记录了一下我自己的使用当中遇到的情况。欢迎拍砖。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容