记一次线上Go服务内存占用异常问题排查

简介: 记一次线上Go服务内存占用异常问题排查

背景


最近线上有个服务内存异常增长, 默认服务启动实存应该是25M左右, 但是这个服务运行了一段时间实存达到了32G的量级, 并且还在缓慢增长, QA重启之后内存就恢复到了初始水准, 需要我们定位一下内存异常的问题进行解决


0b7079eb67ca4170a73c5a884869a5b4.png

过程


整吧那就, pprof整起来, 在main 函数增加三行代码

import _ "net/http/pprof"
func main() {
  go func() {
    _ = http.ListenAndServe("0.0.0.0:6060", nil)
  }()
}

点进源码就看见它会注册5个接口, 用来查看维度数据

9418bb2057e74ae1b3216a69e3b358d7.png

代码部署上去之后用top命令可以看到服务占用实存确实是在缓慢增加, 想单看这个服务的top可以用 top -p pid 指定进程id查看

e6dc63cfaf7f4a23bbd84464e20b56d3.png


里面 VIRT 是虚存, 即程序申请的内存; RES就是实存了, 即当前程序已经占用的内存

等服务跑一会就可以进网址http://127.0.0.1:6060/debug/pprof上查看服务占用情况了

9a13920b5d2c4b24a0aa55f1667fc910.png


也可以在命令行里面进行交互, 因为要查内存问题, 所以就直接看堆占用

go tool pprof http://127.0.0.1:6060/debug/pprof/heap

用top命令可以查看占用前十的函数

(pprof) top
Showing nodes accounting for 4109.08kB, 100% of 4109.08kB total
Showing top 10 nodes out of 91
      flat  flat%   sum%        cum   cum%
    1028kB 25.02% 25.02%     1028kB 25.02%  bufio.NewReaderSize (inline)
  518.02kB 12.61% 37.62%   518.02kB 12.61%  go.uber.org/zap/buffer.(*Buffer).AppendByte
  514.38kB 12.52% 50.14%   514.38kB 12.52%  encoding/json.typeFields
  512.44kB 12.47% 62.61%   512.44kB 12.47%  encoding/pem.Decode
  512.19kB 12.46% 75.08%   512.19kB 12.46%  runtime.malg
  512.05kB 12.46% 87.54%   512.05kB 12.46%  regexp.newOnePassMachine
  512.01kB 12.46%   100%   512.01kB 12.46%  github.com/jinzhu/gorm.(*Scope).getModelStruct
         0     0%   100%     1028kB 25.02%  bufio.NewReader
         0     0%   100%   512.44kB 12.47%  crypto/tls.(*Conn).Handshake
         0     0%   100%   512.44kB 12.47%  crypto/tls.(*Conn).clientHandshake

可以看到还都比较正常, 没有异常占用的函数; 这样的话就再看一眼网页版的堆占用情况

http://127.0.0.1:6060/debug/pprof/heap?debug=1

6700ac4e130341e2af087c3d79d4880d.png


可以看到有很多关于 GetTransactionLevelList 这个方法的占用, 在项目里找到这个方法就很容易就定位到了一行异常代码

context.Set(_r, "key", val)


查看一下源代码


8bf161eabedc4cb394fc3f6281551f99.png

发现这是 gorilla 里面对当前请求存储特定键值的一个包, 关键是代码调用只有插入(Set)没有删除(Clear), 导致底层 data 和datat 一直在储存所有请求的数据及时间戳;

9b1cf4369dec406e8d5b6a1e5f33711c.png

这就是这个服务内存异常的原因, 坑的是发现竟然连Get方法都没有调用, 相当于只存不用…emmm由于这块代码是已经离职的同事写的, 检查没用就直接干掉了, 顺便把所有的服务都自查了一下, 相对应的方法都清理了一遍;

改完代码重新部署服务, 果然内存稳定在了初始水准, 问题解决;


结束


这次问题解决是比较顺利的, pprof还有很多好用的可视化界面(需要安装 graphviz) 以及火焰图(需要安装原生pprof工具)供调用分析, 有兴趣的可以看下面两篇博客去实验玩一玩

目录
相关文章
|
1天前
|
监控 算法 Go
Golang深入浅出之-Go语言中的服务熔断、降级与限流策略
【5月更文挑战第4天】本文探讨了分布式系统中保障稳定性的重要策略:服务熔断、降级和限流。服务熔断通过快速失败和暂停故障服务调用来保护系统;服务降级在压力大时提供有限功能以保持整体可用性;限流控制访问频率,防止过载。文中列举了常见问题、解决方案,并提供了Go语言实现示例。合理应用这些策略能增强系统韧性和可用性。
50 0
|
1天前
|
存储 缓存 算法
深入浅出JVM(二)之运行时数据区和内存溢出异常
深入浅出JVM(二)之运行时数据区和内存溢出异常
|
1天前
|
算法 Java Go
Go vs Java:内存管理与垃圾回收机制对比
对比了Go和Java的内存管理与垃圾回收机制。Java依赖JVM自动管理内存,使用堆栈内存并采用多种垃圾回收算法,如标记-清除和分代收集。Go则提供更多的手动控制,内存分配与释放由分配器和垃圾回收器协同完成,使用三色标记算法并发回收。示例展示了Java中对象自动创建和销毁,而Go中开发者需注意内存泄漏。选择语言应根据项目需求和技术栈来决定。
|
1天前
|
Java Linux Arthas
linux上如何排查JVM内存过高?
linux上如何排查JVM内存过高?
22 0
|
1天前
|
负载均衡 算法 Go
Golang深入浅出之-Go语言中的服务注册与发现机制
【5月更文挑战第4天】本文探讨了Go语言中服务注册与发现的关键原理和实践,包括服务注册、心跳机制、一致性问题和负载均衡策略。示例代码演示了使用Consul进行服务注册和客户端发现服务的实现。在实际应用中,需要解决心跳失效、注册信息一致性和服务负载均衡等问题,以确保微服务架构的稳定性和效率。
20 3
|
1天前
|
Go 微服务
4. 参考 go 代码——服务注册与发现
4. 参考 go 代码——服务注册与发现
|
1天前
|
安全 网络安全 Android开发
云端防御策略:融合云服务与网络安全的未来构建高效的Android应用:从内存优化到电池寿命
【4月更文挑战第30天】 随着企业加速向云计算环境转移,数据和服务的云端托管成为常态。本文探讨了在动态且复杂的云服务场景下,如何构建和实施有效的网络安全措施来保障信息资产的安全。我们将分析云计算中存在的安全挑战,并展示通过多层次、多维度的安全框架来提升整体防护能力的方法。重点关注包括数据加密、身份认证、访问控制以及威胁检测与响应等关键技术的实践应用,旨在为读者提供一种结合最新技术进展的网络安全策略视角。 【4月更文挑战第30天】 在竞争激烈的移动市场中,Android应用的性能和资源管理已成为区分优秀与平庸的关键因素。本文深入探讨了提升Android应用效率的多个方面,包括内存优化策略、电池
|
1天前
|
存储 负载均衡 监控
【Go 语言专栏】构建高可靠性的 Go 语言服务架构
【4月更文挑战第30天】本文探讨了如何利用Go语言构建高可靠性的服务架构。Go语言凭借其高效、简洁和并发性能,在构建服务架构中备受青睐。关键要素包括负载均衡、容错机制、监控预警、数据存储和服务治理。文章详细阐述了实现这些要素的具体步骤,通过实际案例分析和应对挑战的策略,强调了Go语言在构建稳定服务中的作用,旨在为开发者提供指导。
|
1天前
|
数据可视化 Java 测试技术
【Go语言专栏】Go语言中的内存泄漏检测与修复
【4月更文挑战第30天】Go语言内存泄漏详解:概念、原因、检测与修复。内存泄漏由忘记释放内存、循环引用等引起,Go通过垃圾回收机制管理内存,但仍有泄漏风险。检测方法包括pprof、可视化工具、代码审查和单元测试。修复策略涉及优化代码、使用defer、减少全局变量、弱引用及及时释放资源。实践案例分析有助于理解和解决问题。了解内存管理,防止泄漏,提升Go应用性能和稳定性。
|
1天前
|
缓存 监控 测试技术
【Go语言专栏】使用Go语言构建高性能Web服务
【4月更文挑战第30天】本文探讨了使用Go语言构建高性能Web服务的策略,包括Go语言在并发处理和内存管理上的优势、基本原则(如保持简单、缓存和并发控制)、标准库与第三方框架的选择、编写高效的HTTP处理器、数据库优化以及性能测试和监控。通过遵循最佳实践,开发者可以充分利用Go语言的特性,构建出高性能的Web服务。

热门文章

最新文章