2019年8月11日

问题追查:QA压测工具http长连接总是被服务端close情况

1. 背景

最近QA对线上单模块进行压测(非全链路压测),http客户端 与 thrift服务端的tcp链接总在一段时间被close。
查看服务端日志显示 i/o timeout.
最后的结果是: qps太小, 长时间不发送请求, server主动关闭socket

2. 查看thrift框架原代码

thrift框架处理请求伪代码如下:

//服务端listen
for {
	// 服务端接收一个tcp连接请求
	client := server.accept()

	// 独立启动一个goroutine处理client后续请求
	go fun () {
		inputTrans := xxx(client)
		outputTrans := xxx(client)
		if inputTrans != nil {	//return 时, 关闭读
			defer 	inputTrans.close()   
		}
		if outputTrans != nil {
			defer 	outputTrans.close()	//return时, 关闭写
		}
		
		//独立goroutine处理写结果 (使用channel同步)
		go func(
			for {
				//超时,或者其他错误, return
			}
		) ()

		//for循环: 服务读取请求 (两个for循环使用channel同步)
		for {
			//超时,或者其他错误, return
		}
	}()
}

可以看出,

  • thrift框架并没有使用像epollo那样的io多路复用,而是为每个client单独启一个goroutine进行处理
  • tcp时双通道, 上面代码中读、写分别处理,使用channel进行同步
  • 遇到client 超时或者错误,server会主动关闭tcp连接 (使用SetDeadline,SetReadDeadline,SetWriteDeadline设置超时时间)

3. 可能的两种超时情况

3.1 server写超时

压测工具,只负责发送请求,一般不读取请求。
如果使用socket直接连服务器thrift端口,只send数据,不recv数据。可能使得server发送缓冲区满,发送数据超时。

3.2 server 读超时

client qps太小,发送请求时间间隔大于server设置的读超时时间。

4. 总结

这里不是长连接、短连接的问题,是server服务器端的一种自我保护机制。
服务器用于接收大量的client请求,如果存在大量的无用连接不仅会占用服务器资源,更严重的情况会使得其他client无法连接服务器的情况。
可以使用其他方法解决:

  • client和server自定义心跳协议。如secret的发送no-op命令
  • 比如redis client, 如果连接断开可以进行重发一次(先连接,再发)

posted @ 2019-08-11 14:38 旭东的博客 阅读(1129) 评论(0) 推荐(1) 编辑

2019年6月2日

Raft一致性算法

摘要: 动画网址 http://thesecretlivesofdata.com/raft/ 阅读全文

posted @ 2019-06-02 10:52 旭东的博客 阅读(390) 评论(0) 推荐(1) 编辑

go并发编程 WaitGroup, Mutex

摘要: 1.背景 记录一下,方便后续写代码直接使用。 需要注意几点: chan 默认支持多协程工作,不需要加锁。 其他变量操作需要使用锁保护(map多协程并发写会panic, 并且无法捕获)。 启动goroutine时, 通常需要传递参数。不读取局部变量。 需要使用waitgroup等待所有goroutin 阅读全文

posted @ 2019-06-02 08:54 旭东的博客 阅读(1592) 评论(0) 推荐(1) 编辑

2019年4月25日

golang使用chan注意事项

摘要: 背景 最近老代码中遇到的一个问题,表现为: goroutine数量在高峰期上涨,上涨后平峰期将不下来。也就是goroutine泄露 使用pprof看,进程堵塞在chan chan的使用经验 在使用chan时,需要注意堵塞问题 chan做为参数传递时,每个接收方都需要注意chan可能的堵塞(否则cha 阅读全文

posted @ 2019-04-25 08:27 旭东的博客 阅读(6826) 评论(0) 推荐(1) 编辑

2019年4月6日

Go 语言学习笔记

摘要: 1. go没有static关键字 面向对象编程中,尽量对函数进行封装,对于没有函数变量的对象,使用static关键字尤其方便。 go中没有static关键字,必须每次new一个出来。 2. go没有while; do...while循环 go语言里面的for循环比较灵活 go func main() 阅读全文

posted @ 2019-04-06 17:09 旭东的博客 阅读(1685) 评论(0) 推荐(0) 编辑

2018年12月31日

Go语言无锁队列组件的实现 (chan/interface/select)

摘要: 1. 背景 go代码中要实现异步很简单,go funcName()。 但是进程需要控制协程数量在合理范围内,对应大批量任务可以使用“协程池 + 无锁队列”实现。 2. golang无锁队列实现思路 Channel是Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据 阅读全文

posted @ 2018-12-31 11:56 旭东的博客 阅读(6320) 评论(1) 推荐(0) 编辑

2018年11月25日

Go web编程实例

摘要: 1. go web编程入门 记录个web编程例子方便以后使用。 主要有: chan的使用(带缓存,不带缓存) client发起get/post请求 server解析get/post请求参数 http.HandleFunc 根据请求uri设置对应处理func 2. server.go, 参数解析返回 阅读全文

posted @ 2018-11-25 14:24 旭东的博客 阅读(4583) 评论(0) 推荐(0) 编辑

2018年8月18日

分布式环境中,模块数据交互协议分析 (百度brpc)

摘要: 1. 背景 之前听到同事说,要为自己的模块考虑写个数据协议。今天有空想了一下。写出来,方便后续使用。 中可以支持多种协议,nshead、redis、mongo等20多种协议。 2. 什么是数据交互协议? 这里说的协议,不是tcp/ip这些网络协议。 在分布式环境中,我们需要将模块的数据通过网络bit 阅读全文

posted @ 2018-08-18 13:46 旭东的博客 阅读(2662) 评论(0) 推荐(0) 编辑

2018年8月16日

百度brpc 压测工具rpc_press解析

摘要: 1. 背景 昨天看到一段brpc中的压测代码rpc_press, 看着不错。整理一下。 发压工具的难点不是发送请求,而是要注意下面的2点: 保证能发出 ,比如上万qps ,比如控制为5qps,不可以大量发压 2. brpc 中的是关键实现 2.1 如何确保发送足够qps rpc_press 采用多线 阅读全文

posted @ 2018-08-16 08:05 旭东的博客 阅读(2940) 评论(0) 推荐(0) 编辑

2018年8月12日

Reactor反应器模式 (epoll)

摘要: 1. 背景 最近在看redis源码,主体流程看完了。 在网上看到了reactor模式,看了一下,其实我们经常使用这种模式。 2. 什么是reactor模式 反应器设计模式(Reactor pattern)是一种为处理并发服务请求,并将请求提交到一个或者多个服务处理程序的事件设计模式。 当客户端请求抵 阅读全文

posted @ 2018-08-12 18:44 旭东的博客 阅读(8234) 评论(0) 推荐(1) 编辑

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示