【OceanBase DBA早下班系列】—— 性能问题如何 “拍CT“ (一键获取火焰图和扁鹊图)

news2025/1/12 0:54:07

1. 前言

最近接连遇到几个客户的环境在排查集群性能问题,总结了一下,直接教大家如何去获取火焰图、扁鹊图(调用关系图),直击要害,就像是内脏的疾病去医院看病,上来先照一个CT,通过分析CT,大概的毛病也就定位的七七八八了。

2. 火焰图/扁鹊图一键收集

2.1. 步骤一:安装部署obdiag

参考文档: OceanBase分布式数据库-海量数据 笔笔算数

安装obdiag并配置被诊断集群信息(~/.obdiag/config.yml),说明:obdiag 是一款25MB大小的针对OceanBase的黑屏命令行的诊断小工具,功能强大,部署简单。

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/oceanbase/OceanBase.repo
sudo yum install -y oceanbase-diagnostic-tool
source /usr/local/oceanbase-diagnostic-tool/init.sh

# 配置被诊断集群信息
obdiag config -hxx.xx.xx.xx -uroot@sys -Pxxxx -p*****

2.2. 步骤二:一键收集火焰图/扁鹊图

obdiag gather perf

收集过程如图:

1718261610

解压之后的结果

$tree
.
├── flame.data # 火焰图的数据,后面会用到
├── flame.viz
├── sample.data
├── sample.viz # 扁鹊图的数据,后面会用到
└── top.txt

2.3. 步骤三:将火焰图/扁鹊图数据可视化

git clone https://github.com/brendangregg/FlameGraph.git

# 将上面采集到的flame.viz数据经过两次处理,就可以火焰图
./FlameGraph/stackcollapse-perf.pl flame.viz | ./FlameGraph/flamegraph.pl - > perf.svg

火焰图:

1718268132

扁鹊图

perfdata2graph.py

#!/usr/bin/python

import sys
import os
import subprocess
import datetime

class Edge:
  def __init__(self):
    self.count = 0
    self.to = None
    self.label = None
    self.penwidth = 1
    self.weight = 1.
    self.color = "#000000"

class Node:
  def __init__(self):
    self.identify = ""
    self.name = ""
    self.count = 0
    self.self_count = 0
    self.id = None
    self.label = None
    self.color = "#F8F8F8"
    self.edges = {}

  def __str__(self):
    return "id: %s, name: %s, count %s, edges %s" % (self.id, self.name, self.count, len(self.edges))


class PerfToGraph:
  def __init__(self, fmt = "svg", node_drop_pct = 1., edge_drop_pct = None):
    self.fmt = fmt
    self.all_nodes = {}
    self.samples = 1
    self.s100 = 100.
    self.node_drop_pct = node_drop_pct
    self.edge_drop_pct = edge_drop_pct
    self.next_edge_color = 0
    if edge_drop_pct is None:
      self.edge_drop_pct = node_drop_pct / 5.
    self.node_drop_cnt = 0
    self.edge_drop_cnt = 0
    self.colors = [
        (0.02, "#FAFAF0"),
        
        (0.2, "#FAFAD2"),
        (1.0, "#F9EBB6"),
        (2.0, "#F9DB9B"),
        (3.0, "#F8CC7F"),
        (5.0, "#F7BC63"),

        (7.0, "#FF8B01"),
        (9.0, "#FA6F01"),
        (12.0, "#F55301"),
        (15.0, "#F03801"),
        (19.0, "#EB1C01"),
        (23.0, "#E60001")
        ]
    self.edge_colors = [
        "#FF8B01",
        "#EB1C01",
        "#DC92EF",
        "#9653B8",
        "#66B031",
        "#D9CA0C",
        "#BDBDBD",
        "#696969",
        "#113866",
        "#5CBFAC",
        "#1120A8",
        "#960144",
        "#EA52B2"
        ]

  def convert(self):
    self.read_stdin()
    self.formalize()
    self.output()

  def set_pen_width(self, e):
    pct = e.count * 100. / self.samples
    if pct > 10:
      e.penwidth = 3 + min(pct, 100) * 2. / 100
    elif pct > 1:
      e.penwidth = 1 + pct * 2. / 10
    else:
      e.penwidth = 1

  def set_edge_weight(self, e):
    e.weight = e.count * 100. / self.samples
    if e.weight > 100:
      e.weight = 100
    elif e.weight > 10:
      e.weight = 10 + e.weight / 10.

  def set_edge_color(self, e):
    i = self.next_edge_color
    self.next_edge_color += 1
    e.color = self.edge_colors[i % len(self.edge_colors)];

  def set_node_color(self, n):
    v = n.self_count / self.s100
    for p in self.colors:
      if v >= p[0]:
        n.color = p[1]

  def get_node(self, identify, name):
    if self.all_nodes.has_key(identify):
      return self.all_nodes[identify]
    n = Node()
    n.identify = identify
    n.name = name
    self.all_nodes[identify] = n
    return n


  def add_edge(self, f, t):
    if f.edges.has_key(t.identify):
      e = f.edges[t.identify]
      e.count += 1
    else:
      e = Edge()
      e.to = t
      e.count = 1
      f.edges[t.identify] = e

  def read_stdin(self):
    # $ escape not needed?
    cmd = "sed -e 's/<.*>//g' -e 's/ (.*$//' -e 's/+0x.*//g' -e '/^[^\t]/d' -e 's/^\s*//'"
    sub = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell = True)
    prev = None
    self.samples = 1
    for l in sub.stdout:
      l = l.strip()
      if (not l) and (not prev):
        # avoding continous empty lines
        continue
      tmp = l.split(' ')
      addr = tmp[0]
      name = (" ".join(tmp[1:])).strip()
      if '[unknown]' == name:
        name = addr
      if not l:
        addr = 'fake_addr'
        name = '::ALL::'
      # we use name to identify nodes
      n = self.get_node(name, name)
      if prev == n:
        continue
      n.count += 1
      if prev:
        self.add_edge(n, prev)
      prev = n

      if not l:
        self.samples += 1
        prev = None

  def formalize(self):
    self.s100 = self.samples / 100.
    self.node_drop_cnt = self.samples * self.node_drop_pct / 100
    self.edge_drop_cnt = self.samples * self.edge_drop_pct / 100

    i = 0;
    for n in self.all_nodes.values():
      n.id = "n%s" % (i)
      i+=1
      n.self_count = n.count - sum([x.count for x in n.edges.values()])
      n.label = "%s\\nTotal: %.2f%% | Call: %.2f%%\\nSelf: %.2f%%(%s)" % (n.name.replace("::", "\\n"), n.count/self.s100, (n.count - n.self_count)/self.s100, n.self_count/self.s100, n.self_count)
      self.set_node_color(n)

      for e in n.edges.values():
        e.label = "%.2f%%" % (e.count/self.s100)
        self.set_pen_width(e)
        self.set_edge_weight(e)
        self.set_edge_color(e)

  def to_dot(self):
    out = []
    out.append("""
    digraph call_graph_for_perf_data {
    style = "perf.css";
    node [shape = box, style=filled ];
    """)

    out.append('note [ label = "%s\\nTotal samples: %d\\nDrop nodes with <= %.2f%%(%d)\\nDrop edges with <= %.2f%%(%d)", fillcolor="#00AFFF" ];' % (datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), self.samples, self.node_drop_pct, int(self.node_drop_cnt), self.edge_drop_pct, int(self.edge_drop_cnt)))

    for n in self.all_nodes.values():
      if n.count <= self.node_drop_cnt:
        continue
      out.append('%s [ label = "%s", tooltip = "%s", fillcolor="%s"];' % (n.id, n.label, n.name, n.color))

    for n in self.all_nodes.values():
      if n.count <= self.node_drop_cnt:
        continue
      for e in n.edges.values():
        if e.count <= self.edge_drop_cnt or e.to.count <= self.node_drop_cnt:
          continue
        tip = 'edgetooltip = "%s ==> %s", labeltooltip = "%s ==> %s"' % (n.name, e.to.name, n.name, e.to.name)
        out.append('%s -> %s [ penwidth = %.2f, weight = %f, color = "%s", label = "%s", fontcolor = "%s", %s ];' % (n.id, e.to.id, e.penwidth, e.weight, e.color, e.label, e.color, tip))

    out.append("}")
    return "\n".join(out)

  def output(self):
    if "dot" == self.fmt:
      print self.to_dot()
    elif "svg" == self.fmt:
      cmd = "dot -T svg"
      sub = subprocess.Popen(cmd, stdin=subprocess.PIPE, shell = True)
      dot = self.to_dot()
      sub.communicate(input = dot)
    elif "top" == self.fmt:
      try:
        for n in sorted(self.all_nodes.values(), key = lambda n : n.self_count, reverse = True):
          print "%s %.2f%%" % (n.name, n.self_count/self.s100)
      except:
        pass

if __name__ == "__main__":
  support_fmt = { "svg" : None, "dot" : None, "top" : None }
  if len(sys.argv) < 2 or (not support_fmt.has_key(sys.argv[1])):
    print "%s dot/svg/top [node_drop_perent] [edge_drop_percent]" % (sys.argv[0])
    sys.exit(1)
  fmt = sys.argv[1]
  nd_pct = len(sys.argv) > 2 and float(sys.argv[2]) or 1.0
  ed_pct = len(sys.argv) > 3 and float(sys.argv[3]) or 0.2
  c = PerfToGraph(fmt, nd_pct, ed_pct)
  c.convert()
 

# 生成扁鹊图
cat sample.viz | ./perfdata2graph.py svg sample.svg

1718268035

3. obdiag 一键收集火焰图和扁鹊图原理

其实obdiag收集信息是依赖于远端ob节点上的perf工具,所以务必要在ob节点上安装perf工具。相当于obdiag帮你去各个节点上执行了如下命令:

# 注意:-p 后面是进程ID,改成你要 perf 的进程

## 生成调用图(扁鹊图)
sudo perf record -e cycles -c 100000000 -p 87741 -g -- sleep 20
sudo perf script -F ip,sym -f > sample.viz

## 生成火焰图
sudo perf record -F 99 -p 87741 -g -- sleep 20
sudo perf script > flame.viz

感兴趣的可以通过obdiag gather perf -v 查看详细的obdiag 日志,通过日志你就能大概知道obdiag的执行过程了。

4. 附录

  • obdiag 下载地址: OceanBase分布式数据库-海量数据 笔笔算数
  • obdiag 官方文档: OceanBase分布式数据库-海量数据 笔笔算数
  • obdiag github地址:  GitHub - oceanbase/obdiag: obdiag (OceanBase Diagnostic Tool) is designed to help OceanBase users quickly gather necessary information and analyze the root cause of the problem.
  • obdiag SIG 营地: 诊断工具 · OceanBase 技术交流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1820131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS Next 系列之HTTP请求封装和Token持久化存储(四)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现&#xff08;一&#xff09; HarmonyOS Next 系列之验证码输入组件实现&#xff08;二&#xff09; HarmonyOS Next 系列之底部标签栏TabBar实现&#xff08;三&#xff09; HarmonyOS Next 系列之HTTP请求封装和Token…

家用洗地机排行榜前十名:2024十大王牌机型精准种草

最近很多人都在问我洗地机相关的问题&#xff0c;不愧是改善家庭生活品质的“三神器”之一。洗地机依靠其清洁力和清洁效率吸引了越来越多的平时需要做家务人群的兴趣&#xff0c;为了解答大家关于洗地机的各种疑问&#xff0c;我把市面上目前非常火爆的洗地机型号和参数都进行…

探索未来通信的新边界:AQChat一款融合AI的在线匿名聊天

探索未来通信的新边界&#xff1a;AQChat一款融合AI的在线匿名聊天 在数字时代&#xff0c;即时通讯变得无处不在&#xff0c;但隐私和性能仍旧是许多用户和开发者关注的焦点。今天&#xff0c;我要介绍一个开创性的开源项目 —— AQChat&#xff0c;它不仅重定义了在线匿名聊…

Spring IoC注解

一、回顾反射机制 反射的调用三步&#xff1a;1&#xff09;获取类。2&#xff09;获取方法。3&#xff09;调用方法 调用方法&#xff1a;调用哪个对象&#xff0c;哪个方法&#xff0c;传什么参数&#xff0c;返回什么值。 方法&#xff08;Do&#xff09;类&#xff1a; …

eFuse电子保险丝,需要了解的技术干货来啦

热保险丝作为一种基本的电路保护器件&#xff0c;已经成功使用了150多年。热保险丝有效可靠、易用&#xff0c;具有各种不同的数值和版本&#xff0c;能够满足不同的设计目标。然而&#xff0c;对于寻求以极快的速度切断电流的设计人员来说&#xff0c;热保险丝不可避免的缺点就…

【高校科研前沿】北京大学赵鹏军教授团队在Nature Communications发文:揭示城市人群移动的空间方向性

文章简介 论文名称&#xff1a;Unravelling the spatial directionality of urban mobility 第一作者及单位&#xff1a;赵鹏军&#xff08;教授|第一作者|北京大学&#xff09;&王浩&#xff08;博士生|共同一作|北京大学&#xff09;; 通讯作者及单位&#xff1a;赵鹏军…

SCI二区|鲸鱼优化算法(WOA)原理及实现【附完整Matlab代码】

目录 1.背景2.算法原理2.1算法思想 3.结果展示4.参考文献5.代码获取 1.背景 2016年&#xff0c;S Mirjalili受到自然界座头鲸社会行为启发&#xff0c;提出了鲸鱼优化算法&#xff08;Whale Optimization Algorithm, WOA&#xff09;。 2.算法原理 WOA模拟了座头鲸的社会行为…

会议室占用全透明化,内幕大揭秘!

会议室管理的现实问题 &#x1f3e2; 有限的会议室资源: 在现代办公环境中&#xff0c;会议室资源通常是有限的&#xff0c;特别是在大型企业或繁忙的办公楼内&#xff0c;会议室的预订和管理变得尤为重要。 &#x1f552; 复杂的预订流程: 常常会出现会议室预订流程繁琐、不…

2024年6月14日 十二生肖 今日运势

小运播报&#xff1a;2024年6月14日&#xff0c;星期五&#xff0c;农历五月初九 &#xff08;甲辰年庚午月己酉日&#xff09;&#xff0c;法定工作日。今天世界献血日&#xff0c;捐献新鲜血液&#xff0c;挽救更多生命&#xff0c;每位献血者都是英雄&#xff01; 红榜生肖…

【论文复现|智能算法改进】基于改进鲸鱼优化算法的移动机器人多目标点路径规划

目录 1.算法原理2.数学模型3.改进点4.结果展示5.参考文献6.代码获取 1.算法原理 SCI二区|鲸鱼优化算法&#xff08;WOA&#xff09;原理及实现【附完整Matlab代码】 2.数学模型 使用 A* 算法生成所有目标点之间的距离矩阵U: U [ d 1 − 1 d 1 − 2 d 1 − 3 ⋯ d 1 − i d…

【JVM】JVisualVM的介绍、使用和GC过程

VisualVM介绍 VisualVM 是Netbeans的profile子项目&#xff0c;已在JDK6.0 update 7 中自带&#xff0c;能够监控线程&#xff0c;内存情况&#xff0c;查看方法的CPU时间和内存中的对 象&#xff0c;已被GC的对象&#xff0c;反向查看分配的堆栈(如100个String对象分别由哪几…

C#——类和对象详情

类和对象 类 类是一种数据结构&#xff0c;它可以包含数据成员&#xff08;常量和字段&#xff09;、函数成员&#xff08;方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数和析构函数&#xff09;以及嵌套类型。类类型支持继承&#xff0c;继承是一种机制&…

【第9章】“基础工作流”怎么用?(图生图/局部重绘/VAE/更多基础工作流)ComfyUI基础入门教程

🎁引言 学到这里,大家是不是会比较纠结,好像还在持续学习新的东西,未来还有多少基础的东西要学习,才能正常使用ComfyUI呢? 这其实需要转变一个心态。 AI绘画还处于一个快速迭代的过程,隔三岔五的就会有很多新技术、新模型出现,ComfyUI目前同样处于一个快速更新的阶…

Flask基础2-Jinja2模板

目录 1.介绍 2.模板传参 1.变量传参 2.表达式 3.控制语句 4.过滤器 5.自定义过滤器 6.测试器 7.块和继承 flask基础1 1.介绍 Jinja2:是Python的Web项目中被广泛应用的模板引擎,是由Python实现的模板语言,Jinja2 的作者也是 Flask 的作 者。他的设计思想来源于Django的模…

弃用Docker Desktop:在WSL2中玩转Docker之Docker Engine 部署与WSL入门

Docker技术概论 在WSL2中玩转Docker之Docker Engine部署 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://bl…

安装操作系统1-Win10版本介绍及硬件要求

注意&#xff1a;安装系统&#xff0c;首先弄清有哪些版本及所需硬件环境。 1.Win10有哪些版本 微软将 Win10为以下7个版本&#xff1a; Windows 10 家庭版&#xff08;Home&#xff09; 面向所有普通用户&#xff0c;提供Win 10的基本功能。此版本适合个人家庭用户使用&am…

Typora 破解、激活!亲测有效!2024 最新激活方法

Typora 破解、激活&#xff01;亲测有效&#xff01;2024 最新激活方法 Typora是一款简单易用的Markdown编辑器。 Markdown是一种可以使用普通文本编辑器编写的标记语言&#xff0c;通过简单的标记语法&#xff0c;它可以使普通文本内容具有一定的格式&#xff0c;其目标是实现…

机器学习第四十三周周报 aGNN

文章目录 week43 aGNN摘要Abstract1. 题目2. Abstract3. 网络架构3.1 aGNN3.1.1 输入与输出模块3.1.2 嵌入层3.1.3编码器解码器模块&#xff1a;带有多头注意力层的GCN 3.2 可释性模型&#xff1a;SHAP 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 实验区域以及场…

深度解析ONLYOFFICE协作空间2.5版本新功能

深度解析ONLYOFFICE协作空间2.5版本新功能 上个月&#xff0c;4月份&#xff0c;ONLYOFFICE协作空间推出了V2.5版本&#xff0c;丰富了一些很实用的新功能&#xff0c;之前已经有文章介绍过了&#xff1a; ONLYOFFICE 协作空间 2.5 现已发布https://blog.csdn.net/m0_6827469…

没有特斯拉的开源专利,就没有中国电动车产业今天的成就?

原文链接&#xff1a;没有特斯拉的开源专利&#xff0c;就没有中国电动车产业今天的成就&#xff1f; 特斯拉的开源专利&#xff0c;对中国电动车产业的影响有多大&#xff1f; 2014年6月12日&#xff08;June 12, 2014&#xff09;&#xff0c;特斯拉&#xff08;TESLA&…