HTrace 与 Zipkin 简单教程

原文地址:https://www.inlighting.org/archives/htrace-zipkin-tutorial/

最近阅读 HDFS 的源码,看到在 DFSClient 中很多地方用到了 HTrace 这款框架,所以特意学习下。

HTrace 是一款由 Cloudera 开发的分布式追踪框架,在设计上借鉴了 Google 的 Dapper 论文,虽然 HTrace 已经停止了更新,在 Apache 里面孵化失败了,但是它现在任然被 Hadoop 和 HBase 所采用。

HTrace 产生的数据通常不够直观,我们还会使用 Zipkin 进行数据的可视化。

作用

在分布式系统中,用户发送的一个 RPC 请求,会在后台产生多个请求。例如用户通过 HDFS Client 上传一个文件,中间可能涉及到从 Client 到 NameNode,Client 到 DataNode,NameNode 到 DataNode 的 RPC 请求。但是我们该如何追踪这些具体 RPC 请求的性能呢?传统的方法只能监控到 Client 上传文件整一个过程的耗时,而无法捕捉到其间各个请求的性能,从而无法定位性能产生瓶颈的地方。这也就是 HTrace 所需要解决的问题。

术语

Span

HTrace 中追踪的最小单位。一个 Span 表示一个操作所消耗的时间,它包含开始时间,结束时间和描述信息。

TraceScope

TraceScope 管理 Span 的生命周期,当一个 TraceScope 创建,也就代表创建了一个 Span。当 TraceScope 关闭了,也就代表这个 Span 结束了。关闭 TraceScope 后,会把 Span 的信息发送给 SpanReceiver 进行处理。TraceScope 通过 ThreadLocal 保存数据,所以在监控多线程的时候,可以使用 Trace.wrap() 的方式,防止 Span 的数据丢失。

例如原本

Thread t1 = new Thread(new MyRunnable());
// doing something...       

改为

Thread t1 = new Thread(Trace.wrap(new MyRunnable()));
// doing something...

即可,更多用法,可以看 https://www.scalyr.com/blog/htrace-tutorial-how-to-monitor-distributed-systems/

Tracer

Tracer 提供 API 用于创建 TraceScope。你可以把它当做 log4j 中的 Log,一个项目可以有多个 Tracer 对象,Tracer 是线程安全的,你可以多线程同时访问同一个 Tracer 创建 TraceScope,官方也是推荐这么干的。

Sampler

一个系统中 RPC 产生的次数肯定是很多的,如果我们记录每一个 RPC 请求,则会给系统带来巨大的压力,而且产生过多的数据。所以我们可以通过采样的方法,选择性的进行追踪。

HTrace 提供了如下 Sampler:

  • ProbabilitySampler 一定概率进行采样,通过 sampler.fraction 进行概率配置。
  • AlwaysSampler 一直采样。
  • NeverSampler 永不采样。
  • CountSampler 每 N 次进行一次采样,N 通过 sampler.frequency 进行配置。

SpanReceivers

顾名思义,用于接收 Span 的,HTrace 提供了如下 Receiver:

  • LocalFileSpanReceiver 将 Span 信息输出在本地,通过 local.file.span.receiver.path 配置输出路径。
  • StandardOutSpanReceiver 将 Span 信息输出在控制台。
  • ZipkinSpanReceiver 将 Span 信息输出到 Zipkin。

环境搭建

Maven 添加

考虑到我们需要将数据输出到 Zipkin,我们添加如下两个 maven:

<!-- https://mvnrepository.com/artifact/org.apache.htrace/htrace-core4 -->
<dependency>
  <groupId>org.apache.htrace</groupId>
  <artifactId>htrace-core4</artifactId>
  <version>4.2.0-incubating</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.htrace/htrace-zipkin -->
<dependency>
  <groupId>org.apache.htrace</groupId>
  <artifactId>htrace-zipkin</artifactId>
  <version>4.2.0-incubating</version>
</dependency>

Zipkin 安装

根据官方文档,下载 Zipkin jar 包,并运行。

注意,运行的时候需添加 COLLECTOR_SCRIBE_ENABLED=true,否则 Zipkin 无法正常接收到来自 HTrace 的数据。因为这种接收方法过于老土,Zipkin 默认是不开启的。

COLLECTOR_SCRIBE_ENABLED=true java -jar zipkin-server-2.23.2-exec.jar

访问 127.0.0.1:9411 即可看到 Zipkin 的 WebUI 界面。

代码示例

追踪单机版

配置 Tracer

每一个 Tracer 的创建需要我们自己传入配置信息,例如如下:

Map<String, String> config = new HashMap<>();
config.put("sampler.classes", "org.apache.htrace.core.AlwaysSampler");
config.put("span.receiver.classes", "org.apache.htrace.impl.ZipkinSpanReceiver;org.apache.htrace.core.StandardOutSpanReceiver");
Tracer tracer = new Tracer.Builder("simple").conf(HTraceConfiguration.fromMap(config)).build();

这里测试我们使用了 AlwaysSampler,追踪每一次操作。

同时我们添加了两个 SpanReceiver,一个输出到 Zipkin,一个输出到控制台,这里使用 ; 间隔即可。

创建 TraceScope

这里使用了两种创建 TraceScope 的方式

  • try catch

    因为当 try catch 结束后,会自动关闭 TraceScope,更加优雅。

  • 传统方法,需要手动关闭 TraceScope。

下面贴上完整代码:

scope1scope2 分别采用了两种不同的方式创建 TraceScope。

public class SimpleHTrace {
    public static void main(String[] args) {
        Map<String, String> config = new HashMap<>();
        config.put("sampler.classes", "org.apache.htrace.core.AlwaysSampler");
        config.put("span.receiver.classes", "org.apache.htrace.impl.ZipkinSpanReceiver;org.apache.htrace.core.StandardOutSpanReceiver");
        Tracer tracer = new Tracer.Builder("simple").conf(HTraceConfiguration.fromMap(config)).build();
        try (TraceScope scope1 = tracer.newScope("1st operation")) {
            System.out.println("Doing 1st operation");
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }

        TraceScope scope2 = tracer.newScope("2st operation");
        System.out.println("Doing 2st operation");
        try {
            Thread.sleep(500);
        } catch (Exception e) {
            e.printStackTrace();
        }
        scope2.close();
        tracer.close();
   }
}

运行可以看到控制台输出如下:

Doing 1st operation
{"a":"33bc155592be3f5022294b89a5000a2a","b":1611226202469,"e":1611226203470,"d":"1st operation","r":"simple/192.168.3.22","p":[]}
Doing 2st operation
{"a":"fe300340f95fcbe5a5b3f71bc904a48c","b":1611226203495,"e":1611226203996,"d":"2st operation","r":"simple/192.168.3.22","p":[]}

可以看到每一个 Span 的结果是一串 json 字符串

  • a:Span ID
  • b:开始时间戳
  • e:停止时间戳
  • d:scope 名称
  • r:tracer ID
  • p:父 Span ID

查看 Zipkin 的 WebUI,serviceName 就是我们创建 Tracer 时候取的名字。

2021-01-21-RYvWDr

追踪分布式

接下来通过多线程来模拟远程 RPC,并用 HTrace 进行追踪。

在分布式的追踪过程中,因为请求会分布在各个节点,不在同一台电脑上,所以 HTrace 使用 SpanId 来追踪请求。你只需要在每一个 RPC 请求中附带上当前 TraceScope 的 SpanId 就行了,然后在接收端创建新的 TraceScope 时需指定其 parent SpanId 是 RPC 请求传输过来的那一个。具体代码如下:

这里分别模拟了三个过程:Send-RPC -> Receive RPC -> Handle RPC

public class DistributedHTrace {

    private static Tracer getTracer() {
        Map<String, String> config = new HashMap<>();
        config.put("sampler.classes", "org.apache.htrace.core.AlwaysSampler");
        config.put("span.receiver.classes", "org.apache.htrace.impl.ZipkinSpanReceiver;org.apache.htrace.core.StandardOutSpanReceiver");
        return new Tracer.Builder("Distributed").conf(HTraceConfiguration.fromMap(config)).build();
    }

    private static Runnable theTask(SpanId parentSpanId) {
        Tracer tracer = getTracer();
        return new Runnable() {
            @Override
            public void run() {
                SpanId temp = null;
                try(TraceScope traceScope = tracer.newScope("Receive RPC", parentSpanId)) {
                    // 接收 RPC 耗时
                    Thread.sleep(1000);
                    temp = traceScope.getSpanId();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                try(TraceScope traceScope = tracer.newScope("Handle RPC", temp)) {
                    // 处理 RPC 耗时
                    Thread.sleep(600);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }

    public static void main(String[] args) throws Exception {
        Tracer tracer = getTracer();
        TraceScope rootScope = tracer.newScope("Send RPC");
        Thread.sleep(200); // 发送耗时
        Thread t = new Thread(theTask(rootScope.getSpanId()));
        t.start();
        // 发送完成,关闭 rootScope
        rootScope.close();
        // 等待所有任务完成
        t.join();
        tracer.close();
    }
}

然后我们看 Zipkin,可以看到 3 个过程的具体耗时:

2021-01-21-5EQJuY

其他

这里只介绍了 HTrace 的简单用法

更多的 HTrace 配置可以看:https://github.com/apache/incubator-retired-htrace/blob/master/src/main/site/markdown/configuration.md

官方写的两篇教程:

https://github.com/apache/incubator-retired-htrace/blob/master/src/main/site/markdown/developer_guide.md

http://htrace.org

第三方写的教程:

https://www.scalyr.com/blog/htrace-tutorial-how-to-monitor-distributed-systems/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容