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

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/pythonimport sys
import os
import subprocess
import datetimeclass Edge:def __init__(self):self.count = 0self.to = Noneself.label = Noneself.penwidth = 1self.weight = 1.self.color = "#000000"class Node:def __init__(self):self.identify = ""self.name = ""self.count = 0self.self_count = 0self.id = Noneself.label = Noneself.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 = fmtself.all_nodes = {}self.samples = 1self.s100 = 100.self.node_drop_pct = node_drop_pctself.edge_drop_pct = edge_drop_pctself.next_edge_color = 0if edge_drop_pct is None:self.edge_drop_pct = node_drop_pct / 5.self.node_drop_cnt = 0self.edge_drop_cnt = 0self.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.samplesif pct > 10:e.penwidth = 3 + min(pct, 100) * 2. / 100elif pct > 1:e.penwidth = 1 + pct * 2. / 10else:e.penwidth = 1def set_edge_weight(self, e):e.weight = e.count * 100. / self.samplesif e.weight > 100:e.weight = 100elif e.weight > 10:e.weight = 10 + e.weight / 10.def set_edge_color(self, e):i = self.next_edge_colorself.next_edge_color += 1e.color = self.edge_colors[i % len(self.edge_colors)];def set_node_color(self, n):v = n.self_count / self.s100for 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 = identifyn.name = nameself.all_nodes[identify] = nreturn ndef add_edge(self, f, t):if f.edges.has_key(t.identify):e = f.edges[t.identify]e.count += 1else:e = Edge()e.to = te.count = 1f.edges[t.identify] = edef 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 = Noneself.samples = 1for l in sub.stdout:l = l.strip()if (not l) and (not prev):# avoding continous empty linescontinuetmp = l.split(' ')addr = tmp[0]name = (" ".join(tmp[1:])).strip()if '[unknown]' == name:name = addrif not l:addr = 'fake_addr'name = '::ALL::'# we use name to identify nodesn = self.get_node(name, name)if prev == n:continuen.count += 1if prev:self.add_edge(n, prev)prev = nif not l:self.samples += 1prev = Nonedef formalize(self):self.s100 = self.samples / 100.self.node_drop_cnt = self.samples * self.node_drop_pct / 100self.edge_drop_cnt = self.samples * self.edge_drop_pct / 100i = 0;for n in self.all_nodes.values():n.id = "n%s" % (i)i+=1n.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:continueout.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:continuefor e in n.edges.values():if e.count <= self.edge_drop_cnt or e.to.count <= self.node_drop_cnt:continuetip = '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:passif __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.0ed_pct = len(sys.argv) > 3 and float(sys.argv[3]) or 0.2c = 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.mzph.cn/web/26531.shtml

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

相关文章

for循环结构

循环&#xff1a; 循环是一个重复执行一个代码的结构。只要满足循环的条件&#xff0c;会一直执行这个代码。 循环条件&#xff1a;在一定范围之内&#xff0c;按照指定的次数来执行循环。 循环体&#xff1a;在指定的次数内&#xff0c;执行的命令序列。只要条件满足&#…

【iOS】KVC相关总结

目录 1. 什么是KVC&#xff1f;2. 访问对象属性常用方法声明基础使用KeyPath路径多值操作 3. 访问集合属性4. 集合运算符自定义集合运算符 5. 非对象值处理访问基本数据类型访问结构体 6. 属性验证7. 设值和取值原理基本的Getter搜索模式基本的Setter搜索模式NSMutableArray搜索…

vue3+ele-plus+sortableJs对el-table使用sortableJs插件对表格拖拽时限定某列或某行不允许拖拽

如需有对el-table表格进行拖拽的需求&#xff0c;请点击&#xff1a; eleplus对el-table表格进行拖拽(使用sortablejs进行列拖拽和行拖拽)&#xff1a;-CSDN博客 如果你已实现拖拽需求&#xff0c;但拖拽后发现表头并未改变的话&#xff0c;请点击&#xff1a; 解决el-table表…

Windows本地使用SSH连接VM虚拟机

WIN10 VM17.5 Ubuntu:20.04 1.网路设置 1)选择编辑->更改设置 配置完成 2.修改了服务器文件&#xff0c;修改sshd配置&#xff0c;在此文件下/etc/ssh/sshd_config&#xff0c;以下为比较重要的配置 PasswordAuthentication yes PermitRootLogin yes PubkeyAuthenticat…

如何优雅地中断一个网络请求

在前端开发中&#xff0c;网络请求无处不在。但有时候&#xff0c;由于各种原因&#xff08;如用户取消操作、页面跳转等&#xff09;&#xff0c;我们需要中断正在进行的网络请求&#xff08;本文只针对前端实现&#xff09;。那么&#xff0c;如何优雅地实现这一功能呢&#…

C++学习笔记“类和对象”:多态;

目录 4.7 多态 4.7.1 多态的基本概念 4.7.2 多态案例--计算器类 4.7.3 纯虚函数和抽象类 4.7.4 多态案例二 - 制作饮品 4.7.5 虚析构和纯虚析构 4.7.6 多态案例三-电脑组装 4.7 多态 4.7.1 多态的基本概念 多态是C面向对象三大特性之一 多态分为两类 静志多态: 函数…

apex触发器满足条件时弹出对话框

在Salesforce中&#xff0c;Apex触发器是在记录的数据库操作&#xff08;如插入、更新、删除&#xff09;之前或之后执行的逻辑。由于Apex触发器运行在服务器端&#xff0c;无法直接触发客户端&#xff08;浏览器&#xff09;上的对话框。不过可以通过以下方法间接实现这一需求…

[ue5]建模场景学习笔记(6)——必修内容可交互的地形,交互沙(4)

1.需求分析&#xff1a; 现在我们已经有了可以在世界内近于无限的跑动痕迹&#xff0c;现在需要对痕迹进行细化&#xff0c;包括例如当人物跳起时便不再绘制痕迹&#xff0c;以及痕迹应该存在深浅&#xff0c;应该由两只脚分别绘制&#xff0c;同时也应该对地面材质进行进一步处…

程序性能分析:工具与策略

在软件开发中&#xff0c;程序性能分析是一个至关重要的环节。无论是为了确保代码的正确性&#xff0c;还是为了提高程序的运行效率&#xff0c;性能分析都是不可或缺的。本文将介绍程序性能分析的策略以及一系列性能分析和内存检查工具。 一、性能分析的策略 先保证正确性&a…

Vue基本使用-02

上节我们讲了什么是mvvm模型&#xff0c;以及我们vue的一些常用指令&#xff0c;今天给大家讲一下vue的基本使用&#xff0c;在将之前我们需要重点讲解我们的一个指令&#xff0c;v-model指令 v-model v-model 可以在组件上使用以实现双向绑定,什么是双向绑定呢?意思就是当我们…

景芯SoC A72的时钟树分析

innovus的ctslog中的Clock DAG信息可以报出来CTS主要运行步骤的关键信息&#xff0c;比如clustering&#xff0c;balancing做完后的clock tree的长度&#xff0c;clock tree上所用的buffer、inverter&#xff0c;icg cell数量&#xff0c;clock skew等信息。我们以景芯SoC A72 …

wordpress站群搭建2代码初始化

海鸥技术下午茶-wordpress站群搭建2项目代码初始化 1.后端环境 项目框架使用 go-zore https://go-zero.dev/docs/tasks 集成了各种工程实践的 web 和 rpc 框架。含极简的 API 定义和生成工具 goctl&#xff0c;可以根据定义的 api 文件一键生成 Go。可以很大程度上提高开发效…

代码随想录算法训练营第三十六天|LeetCode56 合并区间、LeetCode738 单调递增的数字

题1&#xff1a; 指路&#xff1a;56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 思路与代码&#xff1a; 相似于昨天的引爆气球(第三题)&#xff0c;这个题的题意更为清晰。我们只要取有交集元素的并集区间即可&#xff0c;其他区间照常返回。同样&#xff0c;我们…

React Router 路由详解

文章目录 1. 安装 react-router-dom2. 创建路由3. 创建链接和导航4. 渲染路由参数和查询字符串 在React中&#xff0c;我们通常使用 react-router-dom 这个库来处理路由。 1. 安装 react-router-dom 首先&#xff0c;你需要安装 react-router-dom &#xff0c;可以使用 npm 或…

Centos离线安装Python3

目录 1.准备工作 2.解压python压缩包 3.编译 4.安装、更改环境变量 5.建立pip连接 使用的是Centos7服务器&#xff0c;Py版本是py3.9.0 1.准备工作 首先确保服务器中存在相关的编译器&#xff0c;例如GCC&#xff1b;这里不做过多叙述&#xff0c;需要者前往&#xff1a…

自动化压测工具开发(MFC)

1. 背景 为了减轻测试人员在进行MFC程序压力测试时的重复手动操作&#xff0c;本文档描述了开发一个自动化压力测试工具的过程。该工具能够根据程序界面某块区域的预定状态变化&#xff0c;自动执行鼠标点击或键盘输入操作。 2. 技术概览 串口控制&#xff1a;用于控制外部设…

空间搜索geohash概述;redis的geo命令

概述 通常在一些2C业务场景中会根据用户的位置来搜索一些内容。通常提供位置搜索的都是直接通过redis/mongodb/es等中间件实现的。 但是这些中间件又是怎么实现位置搜索的呢&#xff1b; 查了一番资料&#xff0c;发现背后一个公共的算法Geohash。 搜索的时候可以根据距离对…

Vitis HLS 学习笔记--移除内存分配malloc

目录 1. 简介 2. 示例解析 2.1 源码解释 2.2 malloc 分析 2.3 替代方案分析 3. 总结 1. 简介 Vitis HLS 也不支持动态创建或删除 C/C 对象&#xff08;用于综合&#xff09;。 本文探究如何在C/C代码中避免使用显式的malloc函数来分配内存。在硬件设计和FPGA开发中&…

Xcode无法使用设备:Failed to prepare the device for development

问题&#xff1a; Xcode无法使用设备开发&#xff0c;失败报错如下&#xff1a; Failed to prepare the device for development. This operation can fail if the version of the OS on the device is incompatible with the installed version of Xcode. You may also need…

致 粉丝de信

致 粉丝 -本文呢看不下去别看&#xff0c;但是学业是真的重要&#xff08;平常有信奥&#x1f62b;&#xff09;&#xff0c;电脑没收……更新可能得到暑假&#xff0c; 同学&#xff1a;小没苯agoe &#xff08;aaa&#xff0c;学霸&#xff01;&#xff01;&#xff01;&…