hello,大家好,我是小楼。
今天给大家分享一个关于HBase数据倾斜的排查案例,不懂调用链?不懂HBase?没关系,看完包懂~
背景
最近HBase负责人反馈HBase存储的调用链数据偶尔出现极其严重的倾斜情况,并且日常的倾斜情况也比较大,讲的通俗点就是出现了热点机器。
举个例子,有三台HBase机器存储调用链数据,其中大部分数据读写都在一台机器上,导致机器负载特别大,经常告警,这就是HBase倾斜,也叫热点现象。本文主要讲述了治理倾斜情况的过程,以及踩的几个坑。
知识铺垫
为什么会出现HBase倾斜的情况呢?既然是调用链数据HBase倾斜,那么首先简单介绍下几个调用链和HBase的背景知识。
全链路追踪
全链路追踪
可能是一个比较统一的叫法,平常最多的叫法叫调用链
,也可能有其他的叫法,不过说的都是同一个东西,本文全都用调用链
来指代。
调用链是分布式服务化场景下,跨应用的问题排查和性能分析的工具。
说的直白点,就是可以让你看到你的代码逻辑在哪个地方调用了什么东西,比如在serviceA的methodA的逻辑里,依次调用了redis、mysql、serviceB等,可以看到每个调用的耗时、报错、出入参、ip地址等信息,这就是调用链。
目前调用链有一个统一的标准,以前叫OpenTracing
,现在与其他的一些标准整合进了OpenTelemetry
,不过调用链的标准基本没变。
调用链标准的最核心的概念如下,只列出了一些最核心的元素,不代表全部:
- Span:调用链最基本的元素就是Span,一次 Dubbo Server 请求处理,一次 HTTP 客户端请求,乃至一次线程池异步调用都可以作为一个 Span。
- SpanID:一个Span的唯一标识,需要保证全局唯一
- TraceID:一条调用链的唯一标识,会在整个调用链路中传递
- ParentID:父 Span 的 SpanID。当存在 A -> B 这样的调用关系时,B Span 的 ParentID 是 A Span 的 SpanID。ParentID 用来构造整个调用链路的树形结构。每次发起新的请求时,都要把当前的 SpanID 作为 ParentID 传递给下一个 Span。
- Segment:Segment是特殊的Span,一般表示这是一个应用的边界 Span。如作为 Dubbo Server 的一次请求处理;作为 HTTP Server 的一次请求处理;作为 NSQ Consumer 的一次消息处理等。
- Trace:一条调用链就是一条Trace,Trace是一堆Span的集合,每一个Trace理论上来说是一颗树
下面用一张图来演示一次简单的三个服务间的Dubbo调用来展示调用链的数据是如何、何时产生的,以及各Span之间是通过什么关联起来的,用于深入理解上面的核心概念。
文字描述:外部请求调用了ServiceA.MethodA, SA.MA依次调用了SB.MB、Redis、MySQL, SB.MB调用了SC.MC, SC.MC内部只有计算逻辑。
注意:
- 图里Span内容只包含了一部分,不代表全部内容。
- 可能不同的调用链系统上报存储的方式不一样,有的是每个Segment上报一次,有的是每个Span上报一次,图中表示的是每个Span上报一次
HBase
网上关于HBase介绍的文章很多,这里不做详细的介绍,只是列出来一些基本的概念用于理解。
HBase是一个可以存储海量数据的数据库,既然是数据库,那么最基本的操作就是添加和查询
- RowKey
HBase基本的数据操作都是通过RowKey这个东西,RowKey是HBase的一个核心概念,如何设计Rowkey是使用HBase最关键的部分。
RowKey在HBase里的作用是什么?一个是数据的操作要通过rowkey,可以把rowkey理解为mysql的主键,有索引的作用,另一个是用来做负载均衡。Rowkey的数据格式是字节流,也就是byte数组,这个概念很重要。
什么是byte?就是一个8位字符,值在-128到127之间,所以即使你的rowkey不是那