PlantUML-文本化绘制UML多类图表
笔者一直都是文本编辑器教派的忠实拥趸:期望将所有的任务都通过文本编辑,而非鼠标/触摸板等,进行实现。从早年的
Vim,到现而今的Emacs,对文本化完成需求是越来越习惯,也越来越依赖了。最近刚好有了些时间,把最近的一些实践整理下。
在之前的文章,emacs org-mode 绘制思维导图,中,笔者有提到在探索不跳出Emacs这一文本编辑器的情况下,完成思维导图绘制的需求。在翻了一些文章后,找到了一款神器:PlantUML。其完美的匹配了笔者的需求:
- 不仅是思维导图,工程、文档常用的
UML图像也能全部支持文本化表示; - 功能强大,颜色、文本等格式均能支持;
Emacs友好,而且可以集成到Org-mode里使用。
而且,PlantUML支持在线使用,意味着能够很方便的获取、使用。这里做下介绍。
无侵入观测服务拓扑四元组的一种实现
最近有了些时间,继续整理下之前的项目。服务四元组的信息对于故障处置、根因定位等都有重要意义。使用eBPF可以做到无侵入用户代码获取服务四元组信息的功能。这一点在工程应用上很有意义。笔者在这方面投入了一些精力,这里做一下简单的总结。
服务四元组指的是[caller, caller_func, callee, callee_func]四元组。如下图是一个调用示例,站在服务A的角度,就存在如下两个四元组: [A, /a, B, /b],[A, /a, C, /c]。站在服务B, C的角度,也存在两个四元组(可能有不同的理解): [B, /b, none, none], [C, /c, none, none]。
service call
,-------. ,-. ,-. ,-.
|outisde| |A| |B| |C|
`---+---' `+' `+' `+'
| /a | | |
|-------------->| | |
| | | |
| | /b | |
| |----------->| |
| | | |
| | /c |
| |------------------------>|
,---+---. ,+. ,+. ,+.
|outisde| |A| |B| |C|
`-------' `-' `-' `-'
在弄清楚四元组是什么之后,下面进入今天的话题:如何使用BPF来采集四元组。需要说明的是,笔者这里的语言使用的是golang-1.16。golang不同语言版本间的区别,见:golang-1.17+调用规约。
值得注意的是,关于观测服务数据,是有很多解决方案的。本文仅是笔者实践的一种解决方案,在文末会简单提到这种方案的优缺点。
按照惯例,先看下效果吧:
# 启动采集
bpftrace ./http.bt
Attaching 2 probes... # 未触发请求前,停止在这里
caller: # 触发请求后,输出
caller_path: /handle
callee:
method: GET
host: 0.0.0.0:9932
url: /echo
caller:
caller_path: /echo
callee: none
# 开始服务
./http_demo &
# 触发请求
curl http://0.0.0.0:9932/handle
go-1.17+ 调用规约
go-1.17是一个很不友好的版本,这里我指的是函数调用规约的变更。在此之前,虽然栈传参比较奇怪,但是在掌握了规律后,参数信息很好获取。升级到go-1.17之后,笔者发现变更后的寄存器传值方式并不是系统的调用规约,至少和C/C++的是完全不一致的。这个问题使得笔者在处理ebpf方案时,始终无法覆盖go-1.17+的版本。虽然短期不会造成影响,线上服务使用的大多还在go-1.16以下,但是这始终是一个绕不过去的问题。近期通过查阅资料和参考其他开源项目里对这部分内容的处理,整理了一下go-1.17+的调用规约。
go在1.17之前使用的是内存栈来传递参数,这种传参的方式使得golang的语言设计很灵活:golang函数的多返回值能够很容易的实现。同样的,由于golang需要这样灵活的能力,是的系统默认的调用规约方式并不适用。在Proposal: Register-based Go calling convention文章里对这个问题进行了详细的讨论,总结起来是golang的特性使得使用系统默认规约并不能带来多语言交互上的收益,且golang希望保持独特。
本文下面会给出总结的调用规约,并且给出验证程序。本文档的整理所基于的平台是x86_64的centos8系统。其他架构下,寄存器名称可能不同。
ebpf 采集ebpf 采集tag+tcp五元组
在这里对文章题目作一些说明。笔者想了很长时间也无法给这篇文章想个恰当的表意题目。实际上使用
ebpf来进行服务观测是有在进行的,比如获取目前l1s上的常见的四元组。但是本文不是介绍这部分可观测实践的。文章希望阐述的场景是:采集请求触发里的一些信息(诸如trace及其他header等)并和服务请求下游的传输层五元组(protocol, src-ip, src-port, dst-ip, dst-port)进行关联。这也是最近工作中实际遇到的问题。
基于ebpf的丰富的特性能够获取服务很多的信息,不同特性的组合更是可以达到极强的数据整合能力。比如通过uprobe便捷的获取业务信息后,结合kprobe来获取系统调用里的内容,可以获取一般侵入式可观测代码无法获取的内容。笔者最近遇到的一个实际问题是:获取服务A的接口/a响应后,向下游B发起的请求时,所使用的传输层五元组,同时带上结合一些/a触发时的一些内容,比如caller_fun或者traceId。
这里值得说明的是,用户态请求的是一个域名。域名的解析是在golang的http里完成的。但是请注意,golang发起tcp请求时,local port设置的是0,然后由内核态的tpc处理来选择一个空闲的port作为socket里的lport。这部分的信息通过代码的埋点显然是无法获取的(详情可参考TCP连接中客户端的端口号是如何确定的?)。
下面介绍下实现效果及思路。
关于
bpftrace使用的介绍,可以参见:bpftrace 无侵入遍历golang链表,关于ebpf来进行数据采集的实践,可以参见ebpf采集mysql请求信息及ebpf对应用安全的思考。
emacs org-mode 绘制思维导图
工作中难免会搞一些思维导图,一些小的需求又不希望切换窗口到另外一个界面去特地绘制。使用 emacs 来整理思维导图可以提升一些的效率,在当前窗口(文本编辑器)里即可完成简单思维导图的绘制。同时可以便于对工作内容进行归档(比如把相关的文本都放到一起)。live in emacs.
依赖内容
- org-contrib 扩展文件。用来将 org-mode 格式的文本转换成 freemind mm 文件。
- freemind 软件。用来查看生成的 mm 文件。
笔者试了一下,Xmind思维导图看起来无法打开mm文件,freemind工作正常。也可能是我操作有问题。
此外,生成的思维导图展现样式肯定没有目前专业的思维导图工具丰富,如果有正式的使用需求,还是首先考虑下专业的思维导图工具。
golang常见类型作为参数的eBPF解析
即将过去的2022年,笔者相当比例的精力都投入在了eBPF上。最初的时候,写了一篇golang 常见类型字节数 ,开启了
eBPF+golang的总结性工作。此后陆续整理了一些关于ebpf的使用文章,同时项目也在逐步的推进。eBPF的实际落地有很大的挑战,但是最终还是找到了一些落地的场景。年底了,结合最近的调研工作,笔者整理了这篇文章。既算是对之前文章的呼应,也是对今年整理内容的总结。
eBPF能够提供一种切入服务细节的独特视角。本文即通过实例,对golang常见类型作为函数参数时进行解析,期望读者能够感受这一视角。需要说明的是,本文是基于golang-1.16来整理的。