从http.Transport看连接池的设计

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 本文基于Golang 1.17.6 1.前言 之前萌叔曾在文章 imroc/req 连接池使用须知 提及过Golang标准库net/http提供的连接池http.Transport,但是是浅尝辄止。 本文萌叔想从http.Transport出发来谈谈一个连接池设计应该考虑哪些问题? 2.连接池的功能特征 下图是针对Grpc和Thrift压测结果(见参考资料1)。我么可以看出,长连接相比与短连接相比,QPS大概提升了1倍多。这是因为长连接减少连接建立的所需的3次握手。 要对长连接进行管理,特别是对闲置的长连接进行管理,就不可避免的引入连接池。 特征 需要一个连接时,并不一定真的创建新连接,而是优先尝试从连接池选出空闲连接;如果连接池对应的连接为空,才创建新连接。 销毁并不是真的销毁,而是将使用完毕的连接放回连接池中(逻辑关闭)。 这里引出了几个问题。 Q1:获取连接阶段,我们有没有办法知道从连接池中取出的空闲连接(复用)是有效的,还是无效的? Q2:把使用完毕的连接放回连接池的阶段,空闲连接数量是否要做上限的约束。如果空闲连接数量有上限约束且空闲连接的数量已经达到上限。那么把连接放回连接池的过程,必然需要将之前的某个空闲连接进行关闭,那么按照什么规则选择这个需要关闭的连接。 Q3:放置在连接池中的连接,随着时间的流逝,它可能会变成无效连接(stale)。比如由于Server端定时清理空闲连接。那么为了确保连接池中连接的有效性,是否需要引入定时的检查逻辑? 3.net/http中连接池的实现 net/http中连接池的实现代码在 net/http/transport.go 中 获取连接 Transport.RoundTrip() -> Transport.getConn() 放回连接(逻辑关闭) Response.Body.Close() -> bodyEOFSignal.Close() -> Transport.tryPutIdleConn() 为了约束空闲连接的数量,连接池引入了几个变量: MaxIdleConns MaxIdleConns controls the maximum number of idle (keep-alive) connections across all hosts. 所有host总的最大空闲连接数量,默认值是100 MaxIdleConnsPerHostif non-zero, controls the maximum idle (keep-alive) connections to keep per-host。 针对每个Host能够保持的最大空闲连接数量。默认值是2 这个是一个比较有意思的变量,因为默认情况,所有的HTTP请求都使用同一个连接池,由于MaxIdleConns存在,如果针对某个Host的 连接占用了大量空间,那么针对其它Host的连接可能就没有存储空间了。 MaxConnsPerHost MaxConnsPerHost optionally limits the total number of connections per host, including connections in the dialing, active, and idle states. 默认值是0,表示不限制。 ...

June 20, 2022 · 2 min

packetbeat 初探

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 packetbeat是elastic公司开发的网络抓包、嗅探以及分析工具。 和tcpdump一样,它的底层依赖libpcap。但它比tcpdump、tcpcopy功能强大的多。 它能够直接解析以下的网络协议 ICMP (v4 and v6) DHCP (v4) DNS HTTP AMQP 0.9.1 Cassandra Mysql PostgreSQL Redis Thrift-RPC MongoDB Memcache TLS 将网络包转换成JSON字符串,然后导出到以下output File Console Elasticsearch Logstash Kafka Redis 简单描述过程 event -> filter1 -> filter2 … -> output 让我非常吃惊的是它能够捕获MySQL、Redis等的二进制通讯协议,能够从捕获的记录中,清晰的看到每一条SQL查询语句,以及每一条Redis命令 2. 我们能拿它做什么? 据笔者的了解。 以前做线上的流量复制和重放,大致有这么几种方法 (1) 使用tcpcopy (2) 在服务中引起流量复制模块 (3) 服务打印特殊格式的日志 供后期解析,并做重放 (1)是二进制数据流,人无法阅读,(2)、(3)对服务有入侵,不够友好。 JSON格式的数据,对程序优化,对人来说阅读的障碍也不大。个人认为是个不错的选择 有了这些捕获的数据,我们可以用来做 线上排障 服务功能测试/压力测试 对请求(HTTP请求,MySQL、Redis请求等)进行统计分析,为服务优化提供必要的数据支持。 3. 安装&配置&使用 3.1 安装 见参考资料4 ...

December 17, 2018 · 2 min

requests 库的另类用法(stream)

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: 同事让我帮他抓取一批URL,并获取对应URL的<title>标签中的文字,忽略对应URL网站的封禁问题,这个任务并不是一个特别麻烦的事情。然后实际跑起来,却发现流量打的很高,超过10Mb/s。 经过排查发现,是因为很多URL,实际是下载链接,会触发文件下载,这些URL对应的html中根本不会包含<title>标签,那么处理逻辑就很清晰了,先拿到headers,取出Content-Type,判断是否是 text/html,如果不是,则该Response的body体,就没有必要读取了。 查找requests的相应资料 By default, when you make a request, the body of the response is downloaded immediately. You can override this behaviour and defer downloading the response body until you access the Response.content attribute with the stream parameter: tarball_url = &#039;https://github.com/kennethreitz/requests/tarball/master&#039; r = requests.get(tarball_url, stream=True) At this point only the response headers have been downloaded and the connection remains open, hence allowing us to make content retrieval conditional: ...

January 1, 2018 · 1 min