省流

中医四诊"望闻问切"与程序诊断有异曲同工之妙。在Golang问题排查中,我们需要建立系统化的诊断思维:通过观察表象(望)、收集信息(闻)、追溯根源(问)、精准施治(切)四个维度,形成完整的诊断闭环。

引入prometheus上报

Prometheus能有效暴露线上服务实时数据,包括程序指标和运营指标,也能对指标设定阈值告警,是服务可观测的标配组件。

官方地址:https://prometheus.io/docs/prometheus/latest/getting_started/

引入jaeger链路追踪系统

链路追踪系统可以看作加强版的日志,能解决日志关联性差、信息易缺失的问题,更是分布式服务排查问题的好帮手。能对开发和线上问题调试提供重要助力。

其中数据存储方式有很多种,建议使用ES部署,并在框架提供上报频率配置。

https://www.jaegertracing.io/

探活机制

实现一些实时对服务进行检测的接口,用于异常时验证服务状态,以及使用类k8s的方式对服务进行巡检。

  1. 返回工作队列任务数。
  2. 检测DB和缓存健康。
  3. 返回服务发现状态。

望+闻:察其表象,观其脉络

第一道防线:Prometheus

通过prometheus,我们能制作进程内存、CPU等系统指标,也能对在线、QPS等业务指标进行上报监控。指标监控和日志往往是上线项目发现问题的第一现场。

当某项数值过高、过低,或变动较大时,我们可以设置告警。版本更新发布后也常通过prometheus观察发布后在线、接口报错等时候符合预期。

prometheus常结合grafana使用,prometheus负责收集服务数据,grafana负责显示数据,通过编写hql语句生成线形图。

sum rate大法,常用于查看平均值。这里查询对2min取平均值,计算每秒每个服务、接口发生了多少次调用
sum(rate(requests_total[2m])) by (server,cmd)

日志系统

日志系统也是日常开发用的最多的,那么一个好的日志系统应具备哪些能力?

  1. 应具备中间件,支持框架、项目手动给日志打tag,记录关键信息。默认追加调用接口名、UID等关键信息。
  2. 针对error、fatal级别日志,打印其错误堆栈、traceID等关键信息;Error级别日志做每日汇总,FATAL级别日志需立刻告警。
  3. 支持线上实时调整日志级别。

    日志和监控往往是发现问题的第一现场,但打日志对于业务是冗杂工作,会在主线开发之外增大工作量,在框架层开发中间件等机制能明显让业务开发放空大脑。

系统性能观测(vmstat/top)

vmstat能够实时输出系统的各种资源使用情况,比如进程信息、内存使用、CPU使用以及IO情况。监控系统级 资源瓶颈(CPU、内存、I/O、进程队列)。

$ vmstat 1  # 每秒刷新
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 250000 10240 180000 0 0 50 20 100 200 30 10 55 5 0
  • procs:进程队列。r表示可运行进程数,反应CPU饱和度。b表示阻塞的进程数(例如等IO)。
  • memory:内存使用。swpd表示已用交换分区(若持续增长警惕内存不足)。free为空闲内存。
  • cpu:us:用户态,sy:内核态,id:空闲,wa:I/O 等待

top显示当前系统正在执行的进程的相关信息,包括进程ID、内存占用率、CPU占用率等。实时监控单个进程 的资源占用(CPU、内存等)。

  • load average:分别是1分钟、5分钟、15分钟的负载情况。超过18需要重点关注。
  • cpu:当sy过高时,需要考虑是否过度使用系统函数。
  • 进程信息:重点关注每个进程使用的内存、CPU。

有一次服务接口调用耗时非常高,我们排查到机器发现机器load值超过了20,进一步排查发现业务侧开启了过多time.Timer导致CPU调用忙。

资源限制诊断(ulimit/lsof)

另一类常见报错是系统资源限制,例如:too many open files,或文件描述符泄露。

显示指定pid进程打开的fd
lsof -p

通过ulimit -n命令查看系统文件描述符上限;若确诊,通过prlimit --pid --nofile=65535:65535临时调整fd限制,再通过ulimit -n 65535修改当前会话fd限制,后续再修改系统文件保证机器重启也生效。

问:追本溯源,审证求因****

这里的问可能并不是问go哪里病了,而是定位问题原因,针对具体问题获取更明确的信息。

实时火焰图:pprof

CPU火焰图生成
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile?seconds=30 内存分配分析
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/heap 通过web查看pprof火焰图
go tool pprof -http :18000 pprof.comet.alloc_objects.alloc_space.inuse_objects.inuse_space.002.pb

在第一步中我们可以通过prometheus和top发现进程病了,接下来我们可以通过go tool火焰图观察病灶在哪里,往往就能确定病灶。

  • 对于CPU问题,火焰图会显示占用CPU最高的调用在哪里。
  • 对于内存问题,火焰图会显示目前使用堆内存最高的函数调用堆栈。

实时堆栈:pprof

pprof还有一个功能是抓取当前所有go routine实时堆栈,查看有无问题。

排查协程泄露:
go tool pprof http://localhost:6060/debug/pprof/goroutine?debug=2

经典输出结果如下:

goroutine 1 [running]:

main.main()

/path/to/file.go:10 +0x45

goroutine 2 [runnable]:

runtime.gopark(0x123456, 0x0, 0x0, 0x0)

/usr/local/go/src/runtime/proc.go:307 +0x89

...

  1. 阻塞分析:特别关注状态为 [semacquire]、[IO wait] 或 [select] 的 Goroutine
  • IO Wait的go routine可以认为是在等待网络回包。可能是DB或RPC连接。
  • semacquire状态的协程一般是在等待锁,可以根据堆栈判断是在竞争哪里的锁。重点注意阻塞时间。
  • select就是我们写的select,在等待channel,重点注意阻塞时间。

    所有 Goroutine 都处于等待状态时可能发生死锁。
  1. 泄漏检测:长期处于 [runnable] 但无实际工作的 Goroutine 可能是泄漏
  • 占用大量CPU资源的罪魁祸首

更详细的日志:Jaeger

链路追踪系统用于将请求中发生的离散事件记录并连接。

比如一个简单的请求会从:gatesrv->gamesrv->db,我们可以给UID、RedisKey等关键指标打上标签,文本中记录请求、响应内容,记录从DB中读出了什么,并对出现error的接口进行定向上报。将记录和上报放置于框架中,业务开发时无需操作即可完成自定义集成。

这将极大提高测试环境开发以及线上定位问题的效率:当请求和响应,中间发生的任何rpc和db调用都一目了然,又能对函数调用进行自定义补充时,我们能掌控接口的所有。

jaeger在公司也是战功赫赫:

  • 项目出现诡异报错,通过对指定UID进行灰度抓取,发现其DB数据有问题。
  • 业务时常反馈第三方登录、支付偶现报错,通过jaeger快速发现第三方报错。
  • 开发时减少bug定位修复时间,调用中发生了什么都心中有数。

系统工具(tcpdump/netstat)

针对网络问题,我们往往通过抓包直接获取原始数据。

tcpdump -i any tcp -nn 'tcp port 9096' -w game_20240110.pcap

抓到包后,直接扔到Wireshark进行分析。

  1. 连接问题,检查是否有断连、重连,检查握手是否正常,检查断开连接。
  • 客户端SYN无响应 → 服务未监听/防火墙拦截
  • SYN后立即收到RST → 服务崩溃或拒绝连接
  1. 检查消息收发。出现异常也可能会导致C/S主动断开连接。
  • 请求后无响应 → 服务端未处理
  • 连续包间隔 >200ms → 网络延迟或应用处理慢
  • 检查是否回空包。

有一次遇到线上问题,现象为部分接口回空包并直接关闭连接。

通过tcpdump定位到是proxy,proxy设置http超时时间为3s,但上传文件消耗时间过长,导致该请求在代理被认为是超时,连接被关闭。

切:精准把脉,对症下药

综合案例:计时器滥用诊治

望:接口耗时一路飚高,但观察到DB耗时没有异常。且部分队列出现 "queue busy"触发熔断,观察到CPU也在一路增高,通过top发现服务"us"调用明显高。重启后过短暂恢复,但会继续呈现一路增高。

问:通过查pprof,我们发现CPU耗时指向计时器——但正常情况下大部分CPU会集中在proto的序列化,我们还发现go routine在不断增多。通过查阅业务代码,定位为计时器滥用。

综合案例:网络问题诊治

望:公司有个客户端日志收集服务,接口之一需要上传日志文件,耗时大部分为500ms。测试阶段一切正常,上线后发现有时需要的日志没传上来。通过检查服务日志,发现日志服务正常响应了,

问:我们模拟了巨大文件的上传,并用tcpdump抓取了回包,发现网关层回了空包。检查代码发现我们使用proxy时,给http.transport设置了1s的超时。线上网络环境非常复杂,时常就会上传耗时超过1s。

综合案例:业务BUG

望:这个BUG不会看到接口异常或耗时增加,但会损伤玩家利益。线上玩家反馈,进行游玩有时会丢棋盘上的道具。该功能项目的实现是,客户端进行一系列合成操作并生成结果,并周期性地将合成操作和棋盘同步到服务器,若出现检查异常,服务器将对客户端操作进行回滚。

棋盘同步会有大量的请求,通过日志难以完整复现玩家操作。

问:项目打开了链路追踪的UID尾号采样机制,对出现棋盘回滚+被尾号命中的玩家一系列请求进行分析,发现客户端和服务器在某步出现逻辑不一致。

Golang服务可观测和思路分享的更多相关文章

  1. 通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享

    今天这篇博文的主要目的是分享一下我设计Saga的实现思路来抛砖引玉,其实Saga本身非常的类似于一个简单的工作流体系,相比工作流不一样的部分在于它没有工作流的复杂逻辑处理机制(比如会签),没有条件分支 ...

  2. HyperLedger Fabric 学习思路分享

    HyperLedger Fabric 学习思路分享 HyperLedger Fabric最初是由Digital Asset和IBM公司贡献的.由Linux基金会主办的一个超级账本项目,它是一个目前非常 ...

  3. [技术分享]借用UAC完成的提权思路分享

    借用UAC完成的提权思路分享 背景 UAC(User Account Control,用户帐户控制)是微软为提高系统安全而在Windows Vista中引入的新技术,它要求用户在执行可能会影响计算机运 ...

  4. qqwry - 纯真ip库的golang服务

    qqwry 纯真 IP 库的一个服务.通过http提供一个ip地址归属地查询支持 软件介绍 我们大家做网站的时候,都会需要将用户的IP地址转换为归属地址功能,而之前的作法大都是从硬盘的数据文件中读取, ...

  5. golang 服务端和客户端(二)

    1.golang服务端 package main import( "net/http" ) func main(){ //注册处理函数,用户连接,自动调用指定的处理函数 http. ...

  6. 吾八哥学k8s(二):golang服务部署到kubernetes

    本篇主要讲解如何将golang的服务部署到kubernetes集群里,附带相关的golang的demo和yml文件内容.纯新手入门方式,生产服务需要完整的CI/CD流程来支持. golang服务代码 ...

  7. golang 服务平滑重启小结

    背景 golang 程序平滑重启框架 supervisor 出现 defunct 原因 使用 master/worker 模式 背景 在业务快速增长中,前期只是验证模式是否可行,初期忽略程序发布重启带 ...

  8. .net点选验证码实现思路分享

    哈哈好久没冒泡了,最进看见点选验证码有点意思,所以想自己写一个. 先上效果图 如果你被这个效果吸引了就请继续看下去. 贴代码前先说点思路: 1.要有一个汉字库,并按字形分类.(我在数据库里是安部首分类 ...

  9. 三十、【C#.Net开发框架】WCFHosting服务主机的利用WCF服务通讯和实现思路

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...

  10. 浅谈zygote服务中的设计思路

    zygote服务是Android启动和服务APK的核心服务,每个APK都是通过zygote启动,今日阅读它的源码学习到一个不错的设计思路. 首先看看一个APK通过zygote的启动流程: 按照一般的设 ...

随机推荐

  1. redis 执行性能检测指令报错:-bash: redis-benchmark: command not found

    最近在看redis相关的内容,redis有自带检测性能的命令: -bash: redis-benchmark: command not found 碰到的所有资料中均提示不能在redis客户端中执行, ...

  2. 解决使用yarn安装依赖出现“The engine "node" is incompatible with this module. Expected version "^14.18.0 || ^16.14.0 || >=18.0.0". Got "17.9.0"”的问题

    1.问题描述 某天在使用yarn安装依赖的时候,突然出现如下错误导致安装依赖终止: The engine "node" is incompatible with this modu ...

  3. dp 常见套路总结

    dp 里存的东西值域不大的时候,考虑把状态中某一维和 dp 里存的东西交换,进行 dp. 连续段 dp 时,考虑把连续段化为对每个元素考虑接上一个元素. dp 里的值可能存在某个上界,超过这个值一定不 ...

  4. 重磅发布!DeepSeek 微调秘籍揭秘,一键解锁升级版全家桶,AI 玩家必备神器!

    DeepSeek V3/R1 火爆全网,基于原始模型的解决方案和 API 服务已随处可见,陷入低价和免费内卷. 如何站在巨人肩膀上,通过后训练(post-training)结合专业领域数据,低成本打造 ...

  5. [SCOI2016] 幸运数字 题解

    \(xor\) 最大值想到线性基,路径想到 \(lca\) 和树链剖分,由于没有修改用 \(lca\) 就可以.先用处理 \(fa\) 数组的方式处理倍增线性基(自然是得用线性基合并的),在求 \(l ...

  6. docker - [11] 数据卷之DockerFile

    通过DockerFile可以生成一个镜像 一.DockerFile的介绍 狂神:dockerfile是用来构建docker镜像的文件命令参数脚本. 狂神:dockerfile是面向开发的,我们以后要发 ...

  7. 阿里云Windows server 2016服务器Antimalware Service Executable进程占比高,cpu接近100%,强制关闭该进程实测

    问题描述:阿里云Windows server 2016服务器Antimalware Service Executable进程占比高,cpu接近100%,需要强制关闭该进程,排查问题,进入系统服务关闭, ...

  8. Git pull(拉取),push(上传)命令整理(详细)

    转自:https://www.cnblogs.com/wbl001/p/11495110.html (文档较长,请大家耐心阅读,很有帮助) git比较本地仓库和远程仓库的差异 更新本地的远程分支 gi ...

  9. 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理

    在 AI 编程领域国内外有一堆能叫的上号的应用: Cursor Windsurf Trae 阿里的「通义灵码」 百度的「文心快码」 字节跳动的「MarsCode」 科大讯飞的「iFlyCode」 Gi ...

  10. Vulnhub-Node

    利用信息收集拿到路径得到账户密码,下载备份文件,base64解密后,利用fcrackzip爆破zip压缩包,得到一个文件,查看app.js,发现泄露的账户密码,连接ssh,成功连接,利用ubuntu历 ...