分类 Java 相关 下的文章

http 客户端常见的三种 timeout

微服务的开发部署方式已经在业界广泛被采用, 许多微小的服务共同组成一个完整的软件系统, 对外提供有价值的商业服务. 一个完整的系统组合起来, 离不开内部各个微服务之间的依赖调用, 于是微服务之间形成了一个密集的调用网. 因此我们在微服务的代码中看到许多的 http 客户端到服务端的调用, 而且当应用出问题时候, 我们经常看到各种 http client 相关的各种问题. 这些问题当中, 尤其与 timeout 相关的问题特别多, 本系列的几篇文章将以典型的 Liunx 上 Java 的 http client 为例, 来详细讨论常见的 http 客户端的3种timeout 问题.

connect timeout 和 read timeout

首先, 我们看一个最简单的服务间的调用过程:

  1. 客户端发起 tcp 连接, 服务端应答, tcp 连接建立;
  2. 客户端发出 http request;
  3. 服务端收到请求, 处理请求, 发回 http response;
  4. 客户端收到应答, 关闭 tcp 连接(open issue)

在上面的过程中, 客户端可能会面临2种timeout.

  1. 在上面的第(1)步建立 tcp 连接的过程中, 如果客户端发出 syn, 迟迟收不到服务端的应答, 会产生 connect timeout;
  2. 在上面的过程中, 如果客户端发出了请求, 迟迟收不到 http response, 或收不到完整的response, 则可能产生 read timeout;

从连接池租借连接 timeout

如果某个服务调用的频率非常高, 那么按照上面的流程, 每次都新建一个 tcp 连接就显得非常消耗系统资源和时间. 于是一个可以优化的选项就是在客户端建立连接池, 每次需要发送请求的时候, 从连接池租借出一个连接. 若连接池有现成的连接, 则可以立即借来用. 若没有, 才去新建. 当连接用完之后, 不是关闭连接, 而是返还给连接池以备下次使用. 一般情况下, 连接池不可能有无限的连接, 通常设置一个最大值, 当被借出的连接达到最大值之后, 后续的请求通常要等待空闲的连接可用 (这里介绍的连接池是一个比较简单的模型, 查看专门的书籍去查看更多关于连接的模型和策略).
所以, 从连接池去租借一个可用的连接, 并不一定每次都能立即拿到, 所以有可能迟迟拿不到连接, 所以这里会出现从连接池租借连接的等待 timeout.

所以, 一个客户端的请求会出现3种可能的timeout. 如下图:
timeouts.png

针对上面的3种timeout, 在我们常见的代码中, 它们的默认值是什么呢? 我们应该如何设置这些值呢? 如果设置不合理, 又可能出现那些问题呢?

诊断docker container 里面的 Java 进程内存泄漏

在公司有台台式机, 平时办公不用它, CPU 性能还可以, 有16G 内存, 为了充分利用它, 在它上面装了docker, 然后通过container的方式安装了不少工具, 比如: MySQL+phpmyadmin, ElasticSearch+kibana, MongoDB+mongoUI, Splunk, Clickhouse, Prometheus, Jupter Notebook, Neo4J, Janusgraph, Nginx 等应用, 平时做个测试或者小工具, 直接连这些应用, 非常方便. 直到有一天, 给它接了一个外接显示器, 第二天早上看到下面这个系统日志, 发现这个上面有个应用一直OOM.

- 阅读剩余部分 -