省流

中医四诊"望闻问切"与程序诊断有异曲同工之妙。在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. 密码学报如何正确Latex投稿?

    记录一下<密码学报>投稿遇到的坑,要不研究一下,投稿都不会投!(死在第一步) 模版地址 http://www.jcr.cacrnet.org.cn/CN/column/column13.s ...

  2. react父传子(以及默认值)

    子组件 import React, { Component } from "react"; import "./base.css" // 父组件 export ...

  3. 认识soui4js(第5篇):使用扩展控件

    无论内置控件多么丰富,也不可能满足用户所有需求.总有时候用户需要自己扩展控件. soui4js推荐使用C++来扩展控件,然后通过实现一个js模块来提供js使用. 扩展控件通常涉及到图形上下文的频繁交互 ...

  4. 天翼云亮相操作系统大会&openEuler Summit 2023,斩获多项大奖!

    近日,由开放原子开源基金会等主办,以"崛起数字时代 引领数智未来"为主题的操作系统大会&openEuler Summit 2023在北京举行.大会邀请院士.产业组织及全球开 ...

  5. 帮您了解CDN节点如何做到访问加速与安全防护

    本文分享自天翼云开发者社区<帮您了解CDN节点如何做到访问加速与安全防护>,作者:尹****荷 网站业务痛点 在当前网站快速发展的背景下,网站业务突增往往伴随着一系列网络安全隐患.主要会有 ...

  6. Django设置跨域请求解决方案

    Django设置跨域请求解决方案 在现代Web开发中,跨域资源共享(CORS,Cross-Origin Resource Sharing)是一个常见的需求.尤其是在前后端分离的开发模式下,Django ...

  7. flutter-构造方法给数组list默认空值

    1 class NewstStyle extends StatelessWidget { 2 final List<DkCenterUpload> upload; 3 const News ...

  8. WPF 线程处理

    参考链接:https://docs.microsoft.com/zh-cn/previous-versions/dotnet/netframework-3.5/ms771750(v=vs.90)

  9. 傻妞PLUS机器人教程——安装

    特性 简单易用的消息搬运功能. 简单强大的自定义回复功能. 完整支持 ECMAScript 5.1 的插件系统,基于 otto. 支持通过内置的阉割版 Express / fetch ,接入互联网. ...

  10. 爱快路由-宽带刷下行流量docker版教程

    疑难解答加微信机器人,给它发:进群,会拉你进入八米交流群 机器人微信号:bamibot 简洁版教程访问:https://bbs.8miyun.cn 一天天看直播上行流量太高,给你下行加加速吧,让你下行 ...