一次Go应用上云后线上性能异常排查

简介: 先说结论:资源使用不合理导致机器性能浪费起因:线上某应用告警机器负载及资源占用异常,登陆机器查看进程vmstat发现idle比较低线上是一个Go的应用,而且已经开启了PProf,索性就利用该工具分析一下性能瓶颈在哪PProf如何使用不在本文赘述,经分析初步断定在`ReceiveMessage`这个接口该方法是阿里云的SDK三方包提供的,按道理三方包不会出问题通过代码分析出send函数本质是通过一个

先说结论:资源使用不合理导致机器性能浪费

起因:线上某应用告警机器负载及资源占用异常,登陆机器查看进程

vmstat发现idle比较低

  • 线上是一个Go的应用,而且已经开启了PProf,索性就利用该工具分析一下性能瓶颈在哪
  • PProf如何使用不在本文赘述,经分析初步断定在` ReceiveMessage `这个接口
  • 该方法是阿里云的SDK三方包提供的,按道理三方包不会出问题

通过代码分析出send函数本质是通过一个三方的fasthttp来发送网络api请求

func (p *MNSQueue) ReceiveMessage(respChan chan MessageReceiveResponse, errChan chan error, waitseconds ...int64) {
	resource := fmt.Sprintf("queues/%s/%s", p.name, "messages")
	if waitseconds != nil {
		for _, waitsecond := range waitseconds {
			if waitsecond <= 0 {
				continue
			}
			resource = fmt.Sprintf("queues/%s/%s?waitseconds=%d", p.name, "messages", waitsecond)
			p.qpsMonitor.checkQPS()
			resp := MessageReceiveResponse{}
			_, err := send(p.client, p.decoder, GET, nil, nil, resource, &resp)
			if err != nil {
				// if no
				errChan <- err
			} else {
				respChan <- resp
				// return if success, may be too much msg accumulated
				return
			}
		}
	} else {
		p.qpsMonitor.checkQPS()
		resp := MessageReceiveResponse{}
		_, err := send(p.client, p.decoder, GET, nil, nil, resource, &resp)
		if err != nil {
			errChan <- err
		} else {
			respChan <- resp
		}
	}
	// if no message after waitsecond loop or after once try if no waitsecond offered
	return
}

func send(client MNSClient, decoder MNSDecoder, method Method, headers map[string]string, message interface{}, resource string, v interface{}) (statusCode int, err error) {
	var resp *fasthttp.Response
	if resp, err = client.Send(method, headers, message, resource); err != nil {
		return
	}

	if resp != nil {
		statusCode = resp.Header.StatusCode()

		if statusCode != fasthttp.StatusCreated &&
			statusCode != fasthttp.StatusOK &&
			statusCode != fasthttp.StatusNoContent {

			// get the response body
			//   the body is set in error when decoding xml failed
			bodyBytes := resp.Body()

			var e2 error
			err, e2 = decoder.DecodeError(bodyBytes, resource)

			if e2 != nil {
				err = ERR_UNMARSHAL_ERROR_RESPONSE_FAILED.New(errors.Params{"err": e2, "resp":string(bodyBytes)})
				return
			}
			return
		}

		if v != nil {
			buf := bytes.NewReader(resp.Body())
			if e := decoder.Decode(buf, v); e != nil {
				err = ERR_UNMARSHAL_RESPONSE_FAILED.New(errors.Params{"err": e})
				return
			}
		}
	}

	return
}

为什么会有问题?去业务代码里反推调用层

  • 调用关系分别向下推进发现业务上是起了 多个协程 去调用最终的 ReceiveMessage 方法

重点来了,MNS的消息机制本质是客户端主动去服务器主动拉的

  • 如果服务器没有消息,会造成大量的资源浪费
  • 分析该业务的线上实际情况,有两个解决思路
  • 每天MNS的消息量共不到1000条, 真的有必要开多个协程拉消息吗
  • 大部分时间的请求都是浪费的 ,向服务器请求以后如果没有消息, 我们是不是可以睡一会儿腾出IO
  • 回过头来再分析MSN是否有提供休眠的接口?
  • 那这个问题解决起来就简单了,调整一下参数,看下线上效果,只需要 让他睡一会儿

  • 最终结合实际业务情况,我们又 调整了线上的并发参数 ,看下最终效果
  • 再也没有负载很高的情况了,问题得到了解决

为什么上云之前没有:

  • 上云之前,磁盘是本地IO、上云后,由于是虚拟盘,本质上是通过virtio走网络IO,如果磁盘和网络同时进行IO操作的话,会造成一定的系统瓶颈,负载很大的情况,会造成IO-Hang,CPU假死等情况,具体科普,可以去看一下虚拟云盘是什么

最后再来总结一下:

  1. 通过Go的PProf能够帮助我们分析绝大部分线上的异常情况
  2. 出了问题,如果初步判定是三方库的原因,先不着急下结论,虽然它设计上可能有问题,但也可能是没用对
  3. 解决问题的方法很多,要结合实际业务情况,作出当前阶段最适合的做法,才是技术同学该追求的东西

相关文章
|
1月前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
82 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
4天前
|
监控 编译器 Go
1 行命令引发的Go应用崩溃
这篇文章分析了Go编译时插桩工具导致go build -race竞态检测产生崩溃的原因。
|
2月前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
173 4
|
2月前
|
缓存 监控 前端开发
在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统
本文深入探讨了在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统。
161 1
|
2月前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
179 1
|
2月前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
2月前
|
Go 数据处理 API
Go语言在微服务架构中的应用与优势
本文摘要采用问答形式,以期提供更直接的信息获取方式。 Q1: 为什么选择Go语言进行微服务开发? A1: Go语言的并发模型、简洁的语法和高效的编译速度使其成为微服务架构的理想选择。 Q2: Go语言在微服务架构中有哪些优势? A2: 主要优势包括高性能、高并发处理能力、简洁的代码和强大的标准库。 Q3: 文章将如何展示Go语言在微服务中的应用? A3: 通过对比其他语言和展示Go语言在实际项目中的应用案例,来说明其在微服务架构中的优势。
|
3月前
|
Cloud Native Go API
Go语言在微服务架构中的创新应用与实践
本文深入探讨了Go语言在构建高效、可扩展的微服务架构中的应用。Go语言以其轻量级协程(goroutine)和强大的并发处理能力,成为微服务开发的首选语言之一。通过实际案例分析,本文展示了如何利用Go语言的特性优化微服务的设计与实现,提高系统的响应速度和稳定性。文章还讨论了Go语言在微服务生态中的角色,以及面临的挑战和未来发展趋势。
|
2月前
|
SQL 监控 算法
为Go应用无侵入地添加任意代码
这篇文章旨在提供技术深度和实践指南,帮助开发者理解并应用这项创新技术来提高Golang应用的监控与服务治理能力。在接下来的部分,我们将通过一些实际案例,进一步展示如何在不同场景中应用这项技术,提供更多实践启示。
|
3月前
|
运维 Go 开发者
Go语言在微服务架构中的应用与优势
本文深入探讨了Go语言在构建微服务架构中的独特优势和实际应用。通过分析Go语言的核心特性,如简洁的语法、高效的并发处理能力以及强大的标准库支持,我们揭示了为何Go成为开发高性能微服务的首选语言。文章还详细介绍了Go语言在微服务架构中的几个关键应用场景,包括服务间通信、容器化部署和自动化运维等,旨在为读者提供实用的技术指导和启发。