2020-07-27

此为临时链接,仅用于预览,将在短期内失效。[关闭](javascript:;)

关于OKHttp的一些经验总结

言锡 [言锡](javascript:void(0);) 7月5日

从问题出发,学习OkHttp。

这篇文章从问题的背景开始,围绕OkHttp介绍该问题的解决方案,OkHttp的部分源码解读以及其中涉及的技术点。

01

背景

自己owner的一个服务,在国外机房经常出现调用第三方连接超时的异常。前段时间忙于其他工作没空理它,直到最近收到了用户的几例反馈,才下决心要解决这个问题。

这个服务是一个dubbo服务,为其上层应用提供数据支持。数据来源于第三方,服务中使用了OkHttp框架调用第3方。服务的单台实例调用第3方的qps在5000左右。

下面是创建OkHttpClient实例的方法,httpClient  作为OkHttpClient的单例存在。
httpClient = new OkHttpClient.Build()
我在日志中发现的异常信息如下:
image
可以很明显的看到,连接超时了。[](http://mp.weixin.qq.com/s?__biz=MjM5NDAwMTA2MA==&mid=2695729815&idx=1&sn=7c7feb801bfb8fcf5dfe4e782a4ba3c1&chksm=83d74b5cb4a0c24a21e621ed3428fd808e80c2c5e806a8162cceee62a5930b0430d5506e0f8c&scene=21#wechat_redirect)

02

解决过程

从日志中看到的信息不难得出初步的结论,第3方的服务有问题。所以马上联系了他们,让他们排查。最后给出的结论是他们在和我们相同机器配置下,ab测试单机能够达到5000qps,没有出现我们日志中的连接超时错误。第3方建议我们自己排查一下。

首先,我找运维确认了我们的vip以及后面的网关集群有没有问题,得到的反馈是vip目前负载较低,没有出现问题。

其次,需要排除下部署服务的机器有没有问题,会不会是带宽不够,因为服务不仅要调第3方,还要接受上层应用的请求。我发现进入服务的单台机器流量在200Mbps左右,出口流量在50Mbps。也没有发现问题。

最后,只能怀疑是自己的代码方面的问题了。从代码来看,只能是网络方面的OkHttpClient的参数配置有问题了。

第一个发现的问题是自己没有指定线程池,而OkHttpClient默认的是线程池是:
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 

可以看到,线程池的最大线程数是Integer的最大值,意味着可以无限增加线程,显然是不合理的。另外再通过查找资料,我配置了连接池,最大请求数等参数,最终的OkHttpClient配置如下:

ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));

重启应用后,日志中已经没有看到连接超时的log了,并且消除了很多TCP中的timewait状态,说明连接得以复用了,网络性能大幅提升。

image

03

参数详解

| 参数
| 说明
| 备注
|
| executorService
| 执行http请求的线程池 | 通过自定义线程池,可以预估请求量,从而设置一个适合业务的值。默认线程池是可以无限创建线程的,如果把控不好,会导致系统资源耗尽。
|
| MAX_IDLE_CONNECTIONS | 连接池的大小
| 默认是5,这个值可以设置为请求其他系统的qps
|
| KEEP_ALIVE_DURATION | 连接池中的连接的最大时长
| 默认5分钟,根据业务场景不同而设置
|
| DEFAULT_CONNECT_TIMEOUT | 连接超时时间
| 默认10秒
|
| DEFAULT_READ_TIMEOUT | 读超市时间
| 默认10秒,如果是流式读,需要设置长一点
|
| MAX_REQUEST | OKhttpClient实例最大的并发请求数
| 默认64,根据业务需要设置。一般要大于等于MAX_REQUEST_PER_HOST,如果小于的话,那请求3方的最大并发不会超过MAX_REQUEST。同时需要考虑线程池的大小
|
| MAX_REQUEST_PER_HOST | 对单个被请求方域名的最大请求并发数
|

默认4,需要考虑几点:

1,如果被调用方所支持的最大qps只有500,那么这个值设置不要超过500

2,如果okhttpClient实例只调用一个3方服务,那么这个值建议设置为和MAX_REQUEST一致

3,如果okhttpClient要调用n个3方,那么建议n * MAX_REQUEST_PER_HOST接近MAX_REQUEST

同时,需要结合上述线程池的大小合理设置

|

04

源码解读

[图片上传失败...(image-b23fb4-1595856859249)]

微信扫一扫
关注该公众号

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。