05 | HTTP调用:你考虑到超时、重试、并发了吗?
该思维导图由 AI 生成,仅供参考
配置连接超时和读取超时参数的学问
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了在进行HTTP调用时需要关注的超时、重试和并发方面的问题,特别是在使用Spring Cloud的Feign和直接使用Spring Boot进行微服务开发时可能会遇到的挑战。文章首先强调了配置连接超时和读取超时参数的重要性,以及对业务应用的特殊意义。接着详细解释了Feign客户端默认的两个全局超时时间的设置方法和注意事项,包括配置的优先级、坑点和误区。文章还介绍了如何针对单独的Feign Client设置超时时间,以及如何通过配置Ribbon组件的参数来修改超时时间。最后,文章指出了同时配置Feign和Ribbon的超时时,以Feign为准的结论。通过深入浅出的方式,本文详细介绍了开发人员在进行HTTP调用时需要注意的问题,为读者提供了宝贵的技术指导。文章内容涵盖了Feign和Ribbon的配置细节,以及对HTTP调用中可能出现的重试问题进行了深入分析,对于开发人员在微服务开发中遇到的挑战提供了有益的解决思路。
《Java 业务开发常见错误 100 例》,新⼈⾸单¥59
全部留言(62)
- 最新
- 精选
- 徐典阳✔️置顶朱老师,请问Feign声明式HTTP接口调用可以针对某服务单个接口配置读取超时参数吗?我们这边一个微服务有n个接口,有一些接口处理耗时长有一些处理耗时短,但调用方又不期望针对同一个微服务声明多个Feign client。我简单翻了源码没有找到。
作者回复: 可以,补充了一个例子: https://github.com/JosephZhu1983/java-common-mistakes/blob/master/src/main/java/org/geekbang/time/commonmistakes/httpinvoke/feignpermethodtimeout/FeignPerMethodTimeoutController.java Feign比较新的版本才会支持: https://github.com/OpenFeign/feign/pull/970 相关源码: SynchronousMethodHandler Options findOptions(Object[] argv) { if (argv == null || argv.length == 0) { return this.options; } return (Options) Stream.of(argv) .filter(o -> o instanceof Options) .findFirst() .orElse(this.options); }
2020-04-17223 - Monday置顶我们来分析一下源码。打开 RibbonClientConfiguration 类后,会看到 DefaultClientConfigImpl 被创建出来之后,ReadTimeout 和 ConnectTimeout 被设置为 1s: /** * Ribbon client default connect timeout. */ public static final int DEFAULT_CONNECT_TIMEOUT = 1000; /** * Ribbon client default read timeout. */ public static final int DEFAULT_READ_TIMEOUT = 1000; @Bean @ConditionalOnMissingBean public IClientConfig ribbonClientConfig() { DefaultClientConfigImpl config = new DefaultClientConfigImpl(); //此行打断点 config.loadProperties(this.name); config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT); config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT); config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD); return config; } 被死扣的毛病折腾着,以上这段描述和代码中,有两个疑问,烦老师解惑,谢谢。 1、使用默认配置,我在标注行打了断点,debug启动时未进断点。是不是表明默认值不是在此段代码设置的? 2、找到了feign配置的原始类FeignClientProperties,但是没找到ribbon的。
作者回复: 1、启动时不进断点不代表不是,执行后会进断点,原因是LoadBalancerFeignClient.execute(),运行时注入依赖的,这个方法一路追下去: IClientConfig getClientConfig(Request.Options options, String clientName) { IClientConfig requestConfig; if (options == DEFAULT_OPTIONS) { requestConfig = this.clientFactory.getClientConfig(clientName); } else { requestConfig = new FeignOptionsClientConfig(options); } return requestConfig; } 2、ribbon是netflix的三方库,不是spring boot @ConfigurationProperties玩法,Key定义在: com.netflix.client.config.CommonClientConfigKey
2020-03-2011 - 蚂蚁内推+v置顶老师,我这边工作过程中遇到服务端 499 这块要怎么从链接超时和读取超时设置去分析呢?
作者回复: 499情况比较特殊,虽然表现为服务端(一般为代理,比如nginx)记录和返回499状态码,但是其实是因为处理时间太长,客户端超时主动关闭连接,排查两点: 1、客户端读取超时时间多久 2、服务端为什么处理这么慢超过了客户端的读取超时 如果希望不要499的话,对于nginx可以开启 proxy_ignore_client_abort,这样可以让请求在服务端执行完成
2020-03-1924 - Darren置顶试着回答下问题: 1、为什么很少见到写入超时,客户端发送数据到服务端,首先接力连接(TCP),然后写入TCP缓冲区,TCP缓冲区根据时间窗口,发送数据到服务端,因此写入操作可以任务是自己本地的操作,本地操作是不需要什么超时时间的,如果真的有什么异常,那也是连接(TCP)不上,或者超时的问题,连接超时和读取超时就能覆盖这种场景。 2、proxy_next_upstream:语法: proxy_next_upstream [error|timeout|invalid_header|http_500|http_503|http_404|off] 默认值: proxy_next_upstream error timeout 即 error timeout会自动重试 可以修改默认值,在去掉error和timeout,这样在发生错误和超时时,不会重试 proxy_next_upstream_tries 这个参数决定重试的次数,0表示关闭该参数 Limits the number of possible tries for passing a request to the next server. The 0 value turns off this limitation.
作者回复: 👍🏻
2020-03-19260 - 👽这已经不单单是一个坑了,而是N一个场景下,多种多样的坑。 Spring Boot 带来了【约定大于配置】的说法,但是,本文告诉我们,越是约定大于配置,越是要对那些“默认配置”心里有数才行。 HTTP请求,说到底,还是网络调用。某个老师曾说过,网络,就是不靠谱的。就存在拥塞,丢包等各种情况。从而使得排查的难度更大。要考虑的角度,宽度,都更广。不单是客户端,服务端,甚至还要考虑网络环境。这对程序员具备的技术深度,广度都有了更高的要求。 今天的收货: 首先,增长了经验。知道了有这么些坑,虽然不一定能记得住,最起码留个印象。以后碰到类似的问题了能想起来。 然后,不能盲目相信默认配置。条件允许的情况下,还是需要了解关注那些默认配置以及默认实现。 最后,对HTTP调用,的测试方式与模拟方式,也了解到了测试方式。如何分别设置超时时间来找问题。 其实,还希望能听听老师讲讲HTTP调用出问题的排查思路与方案。
作者回复: 总结的不错
2020-03-1932 - Geek_d7ede4老师您好,我之前对接过一个第三方支付接口,调用支付接口a账户对b账户进行了转账操作,我业务数据库也要做一个记账操作在数据库中,如何保证调用第三方支付接口和我本地的业务是一致性的呢?就是第三方支付接口有可能已经转账成功了,但是我业务代码可能抛异常,导致回滚了。
作者回复: 很典型的问题: 1、先创建支付订单,再提交外部,创建订单的操作独立事务,不要回滚(否则出异常了,订单都没了,补偿的依据都没有) 2、只有外部接口告诉你明确成功或失败了,你才能认为操作成功或失败 3、否则由定时任务调用外部查询接口查询交易结果,然后根据查到的结果补偿本地状态
2020-03-31730 - Unravel👾老师您好 前段时间遇到过一个连接超时的问题,在springboot中使用restTemplate(无论是不配置还是增大超时时间或是加入apache http client连接池)在业务中请求另外一个服务的接口经常会出connect timeout(经过nginx或是直接连接tomcat都会出现) 此时ping、telnet、curl都是成功的 但是如果另有一个任务定时一直请求接口,那么在业务中就不会出现connect timeout了。 一直没有成功解决这个问题,想问下老师可以从哪方面入手,谢谢老师
作者回复: 既然你是遇到偶尔出现连接失败,说明对端端口是开的,这种连接超时偶发问题一般是网络问题,丢包、防火墙、带宽打满、网卡配置问题,甚至是硬件问题(网线网口)等引起的,链路上任何一个环节的软件和硬件都可能引起问题,抓包分析吧。 另外ping一次是成功的,长ping一下看看。curl一次是成功的,做一个监控10s一次curl一次试试。
2020-03-2628 - Monday花了两个晚上终于还是把这节啃了下来,准备运行环境,重现所有问题,翻看相关源码。 终于等到你,还好我没放弃。 个人感悟,这些坑对以后快速排查问题,肯定有帮助。就算以后淡忘了这节的内容,但至少还会有些许记忆的,哪个专栏,哪个老师,哪篇文章。感谢老师!
作者回复: 如果觉得有用可以多转发分享
2020-03-205 - 终结者999号老师,对于Http Client和Ok Http相比,是不是OkHttp支持得更好,而且HTTP2相比于HTTP1.1的新特性是不是也使得我们不用过去的一些配置了啊
作者回复: 我个人觉得okhttp易用性更高一点,不过okhttp应该在安卓领域更火一点,后端使用okhttp的应该不多。万变不离其宗,使用任何httpclient都要考虑连接池、超时配置、自动重试和并发问题
2020-03-194 - Mondaypublic class ClientReadTimeoutController { private String getResponse(String url, int connectTimeout, int readTimeout) throws IOException { return Request.Get("http://localhost:45678/clientreadtimeout" + url) .connectTimeout(connectTimeout) .socketTimeout(readTimeout) .execute() .returnContent() .asString(); } .... } 这第一段代码中Request这个类,是引用哪个包下的?找得好辛苦,老师第5节的代码也没上传到git
作者回复: 源码里面有,在clientreadtimeout里 Request是在这里: <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>fluent-hc</artifactId> <version>4.5.9</version> </dependency>
2020-03-1933