写在前面
HBase存在存储OpenTSDBtree数据的表,了解这个对OpenTSDB的存储机制就会有一定了解。
原地址:http://opentsdb.net/docs/build/html/user_guide/trees.html
除了元数据,OpenTSDB 2.0还引入了树的概念,这是一种将时间序列组织成易于导航的结构的分层方法,可以像计算机上的文件系统一样进行浏览。用户可以使用各种规则集定义多个树,这些规则集将TSMeta对象组织为树结构。然后,用户可以通过HTTP API端点浏览生成的树。有关详细信息,请参见/ api / tree。
树的术语
-
分支 - 每个分支是树的一个节点。它包含子分支和叶子列表以及父分支列表。
-
Leaf - 分支的结尾,代表一个独特的时间序列。叶子将包含可用于生成TSD查询的TSUID值。分支可以并且可能会有多个叶子
-
Root - 根分支是树的开头,所有分支都从该根伸出。它的深度为0。
-
深度 - 每次将分支添加到另一个分支时,深度会增加
-
严格匹配 - 启用时,时间序列必须与规则集的每个级别中的规则匹配。如果一个或多个级别无法匹配,则时间序列将不会包含在树中。
-
路径 - 层次结构中当前分支上方的每个分支的名称和级别。
树干
树的每个节点都被记录为分支对象。每个分支包含以下信息:
-
分支ID - 分支的ID。这是下面描述的十六进制值。
-
显示名称 - 分支的名称,由树规则集从TSMeta对象解析。
-
深度 - 分支驻留在层次结构中的深度。
-
路径 - 每个父分支的深度和名称(包括本地分支)。
-
分支 - 子分支在此分支下方的一个深度级别。
-
叶子 - 属于这个分支的叶子。
导航树从根分支开始,根分支始终具有与分支所属的树的ID匹配的ID。根应该有一个或多个子分支,可用于向下导航树的一个级别。每个孩子都可以用来导航他们的孩子,等等。根没有任何父分支,并且总是在0的深度。如果刚刚定义或启用了树,它可能还没有根分支,并且通过扩展,将不会有任何子分支。
每个分支通常都有一个子分支列表。但是,如果分支位于路径的末尾,则它可能没有任何子分支,但它应该有一个叶子列表。
分支ID和路径
分支ID是十六进制编码的字节数组,类似于TSUID但具有不同的格式。分支ID始终以2个字节编码的树的ID开头。根分支的分支ID等于树ID。因此树的根1
将具有分支ID 0001
。
每个子分支都有一个DisplayName
值,该值的散列用于为分支生成32位整数ID。使用的哈希函数是Java java.lang.String
哈希函数。然后将整数值的4个字节编码为8个十六进制字符。例如,如果我们有一个sys
分支的显示名称,则返回的散列将是102093.TSD将该值转换为十六进制0001BECD
。
分支ID由树ID与当前分支上方的每个父级的ID连接组成,并与当前分支的ID连接。因此,如果我们的子分支sys
是根的子代,我们将具有分支ID 00010001BECD
。
假设有一个分支显示名称为cpu
off sys
子分支。cpu
返回一个98728的散列,转换为000181A8
十六进制。这个孩子的身份证是00010001BECD000181A8
。
ID是以这种方式创建的,主要是由于分支和叶子存储的方法,但也是一种从树结构中任何位置的树枝导航备份树的方法。如果您知道路径的结束分支并希望向上移动一级或更多级别,则此功能尤其有用。不幸的是,深树可以创建非常长的分支ID,但是设计良好的树实际上不应该超过5到10个深度。在达到URI字符约束之前,大多数URI请求应支持最多100级的分支。
树叶
唯一的时间序列表示为树上的叶子。叶子可以出现在结构中的任何分支上,包括根。但它们通常会出现在分支中的一系列分支的末尾,分支中有一个或多个叶子但没有子分支。每个叶子包含要在查询中使用的时间序列的TSUID以及度量标准和标记名称/值。它还包含一个显示名称,该名称从规则集中解析,但可能与任何度量标准,标记名称或标记值不同。
理想情况下,时间序列只会出现在树上一次。但是,如果时间序列的TSMeta对象,或者修改了度量或标记的UIDMeta,则可以再次处理它,并添加第二个叶子。特别是在树具有度量标准,标记名称或标记值的自定义规则(其中已处理TSMeta,然后用户添加与规则集匹配的自定义字段)的情况下,可能会发生这种情况。在这些情况下,建议在树上启用严格匹配,以便在添加自定义数据之前不会显示时间序列。
规则
每个树都是根据用户定义的一组规则动态构建的。规则集必须至少包含一个规则,并且通常包含多个规则。每个集合都有多个级别,用于确定规则处理的顺序。首先处理位于级别0的规则,然后处理级别1的规则,依此类推,直到所有规则都应用于给定的时间序列。规则集中的每个级别可能有多个规则来处理可能没有提前计划出度量标准或标记或某些任意数据可能已经陷入其中的情况。如果多个规则存储在一个级别中,则第一个规则成功匹配将被应用,其他人将被忽略。这些规则也按订单排序字段,以便首先处理具有订单0的规则,然后处理具有订单1的规则,依此类推。在日志和使用测试端点时,规则通常以“[<treeId>:<level>:<order>:<type>]”的格式给出ID,例如“[1:0:1:0]”表示树1的规则,级别0,类型的顺序1 METRIC
。
规则类型
每个规则都作用于时间序列数据的单个组件。目前可用的类型包括:
类型 | ID | 描述 |
---|---|---|
公制 | 0 | 处理与时间序列关联的度量标准的名称 |
METRIC_CUSTOM | 1 | 搜索给定辅助名称的度量标准元数据自定义标记列表。如果匹配,则将处理与标记名称关联的值。 |
TAGK | 2 | 在标签列表中搜索给定名称。如果匹配,将处理与标记名称关联的tagv值 |
TAGK_CUSTOM | 3 | 在标签列表中搜索给定名称。如果匹配,则搜索tagk元数据自定义标签列表以查找给定的辅助名称。如果匹配,则将处理与自定义名称关联的值。 |
TAGV_CUSTOM | 4 | 在tagv列表中搜索给定名称。如果匹配,则搜索tagv元数据自定义标记列表以查找给定的辅助名称。如果匹配,则将处理与自定义名称关联的值。 |
规则配置
单个规则可以处理正则表达式,分隔符或无。如果为规则定义了正则表达式和分隔符,则仅处理正则表达式并忽略分隔符。
验证对规则的所有更改以确认填写了适当的字段,以便规则可以处理数据。必须为每种规则类型填写以下字段:
类型 | 领域 | 的CustomField |
---|---|---|
公 | ||
Metric_Custom | X | X |
TagK | X | |
TagK_Custom | X | X |
TagV_Custom | X | X |
显示格式化程序
有时,从标签或指标中提取的数据可能不是非常具有描述性。例如,应用程序可以输出具有诸如“port = 80”或“port = 443”的标签对的时间序列。使用与tagk值“port”匹配的标准规则,我们将有两个名称为“80”和“443”的分支。不熟悉的人可能不知道这些数字是什么意思。因此,用户可以定义基于令牌的格式化程序,该格式化程序将改变分支的输出以显示有用的信息。例如,我们可以声明格式化程序“{tag_name}:{value}”,分支现在将显示“port:80”和“port:443”。
令牌区分大小写,每个格式化程序只能出现一次。它们也必须在下表中完全脱离:
代币 | 描述 | 适用的规则类型 |
---|---|---|
{} ovalue | 规则处理的原始值。例如,如果规则使用正则表达式提取值的一部分但您不想要提取的值,则可以在此处使用原始值。 | 所有 |
{值} | 处理后的价值。如果规则具有提取的正则表达式组,或者该值由分隔符分割,则表示该处理发生后的值。 | 所有 |
{标签名称} | 与该值关联的tagk或自定义标记的名称。 | METRIC_CUSTOM,TAGK_CUSTOM,TAGV_CUSTOM,TAGK |
{} tsuid | 时间序列的TSUID | 所有 |
正则表达规则
在某些情况下,您可能只想提取度量标准,标记或自定义值的组件以用于分组。例如,如果多个数据中心的计算机具有包含DC名称的完全限定域名,但并非所有度量标准都包含DC标记,则可以使用正则表达式提取DC进行分组。
该regex
规则参数必须使用有效的正则表达式包括一个或多个提取运算符,即,括号中设置。如果正则表达式与提供的值匹配,则提取的数据将用于构建分支或叶。如果正则表达式中提供了多个提取,则可以使用该regex_group_index
参数选择要使用的提取值。索引基于0并且默认为0,因此如果要选择第二次提取的输出,则应将此索引设置为1.如果正则表达式与值不匹配或提取无法返回有效字符串,该规则将被视为不匹配。
例如,如果我们有一个tagv为的主机tagk web01.nyc.mysite.com
,我们可以使用类似的正则表达式.*\.(.*)\..*\..*
来提取FQDN的“nyc”部分,并将“nyc”数据中心中所有服务器分组到“nyc”分支下。
分隔规则
许多系统的度量通常是带有分隔符的字符串,例如句点,以划分度量的组件。例如,“sys.cpu.0.user”。要构建有用的树,可以使用分隔符规则,该规则将根据字符序列拆分字符串,并从每个单独的值创建分支或叶。将分隔符设置为“。” 对于前面的例子,将产生三个分支“sys”,“cpu”,“0”和一个叶子“user”。
优先顺序
每个规则只能处理正则表达式,分隔符或两者都不。如果规则在各自的字段中同时具有“正则表达式”和“分隔符”值,则只会在时间序列上执行“正则表达式”。“分隔符”将被忽略。如果既未定义“正则表达式”或“分隔符”,则当规则的“字段”匹配时,该字段的整个值将被处理为分支或叶子。
树的构建
首先,tsdb-tree
如果尚未在HBase中创建表,则必须在HBase中创建表。如果启用树处理并且表不存在,则TSD将不会启动。
树可以用两种方式构建。该tsd.core.tree.enable_processing
配置设置允许实时树创建。每当用户创建或编辑新的TSMeta对象时,TSMeta将通过每个已配置和启用的树。生成的分支将被记录到存储中。如果发生冲突或TSUID在任何规则上都不匹配,则会记录警告,如果配置了树选项,则可能会将其记录到存储中。
或者,您可以通过CLI uid
工具定期同步所有TSMeta对象。这将扫描tsdb-uid
表并通过已配置和启用的树传递每个发现的TSMeta对象。有关详细信息,请参阅uid
注意
对于实时树构建,您还需要启用该tsd.core.meta.enable_tracking
设置,以便在收到时间序列时创建TSMeta对象。
创建和构建树的一般过程如下:
-
通过HTTP API创建一个新树
-
通过HTTP API为树分配一个或多个规则
-
通过HTTP API使用一些TSMeta对象测试规则
-
在非常好的分支出现后,将树的
enable
标志设置为true
-
uid
使用treesync
sub命令运行该工具以同步树中的现有TSMeta对象
注意
创建新树时,默认情况下将禁用它,因此不会通过规则集处理TSMeta对象。这样您就有时间配置规则集并对其进行测试,以验证树是否按照您的预期构建。
规则处理顺序
树通常会有多个规则,以便生成的树有用。如上所述,规则分为级别和顺序。TSMeta通过从0级和0级开始的规则集进行处理。处理按递增顺序在级别上执行规则。在成功匹配TSMeta数据的级别上的第一个规则之后,处理跳到下一级别。这意味着关卡中的规则实际上是“或”。如果级别0具有0,1,2和0阶的规则,并且规则上的TSMeta匹配顺序为1,则将跳过具有顺序2和3的规则。
编辑规则时,可能会跳过某些级别或订单或将其留空。在这些情况下,处理只是跳过空位置。你应该尽力保持正确的组织,但规则处理器有点宽容。
严格匹配
所有TSMeta对象都通过每棵树进行处理。如果您只想要一个单一的整体树来组织所有的OpenTSDB时间序列,这不是问题。但是,如果要为特定的信息子集创建多个树,则可能需要从创建叶中排除某些时间序列条目。strictMatch
树上的标志有助于过滤掉属于一棵树但不属于另一棵树的时间序列。启用严格匹配后,时间序列必须匹配规则集中每个级别(具有一个或多个规则)的规则,以便将其包含在树中。如果元无法在任何级别上与规则匹配,则它将被记录为不匹配的条目,并且不会生成叶子。
默认情况下,禁用严格匹配,以便可以在树中捕获尽可能多的时间序列。如果在树上更改此设置,则可能需要删除现有分支并运行重新同步。
碰撞
由于规则集的灵活性以及各种度量标签,标记名称和值命名,两个不同的TSMeta条目几乎不可避免地会尝试在树上创建相同的叶子。每个分支只能有一个具有给定显示名称的叶子。例如,如果一个分支有一个以user
tsuid 命名的叶子,010101
但是树试图添加一个以user
tsuid为名称020202
的新叶子,则新叶子将不会添加到树中。相反,将记录树的碰撞条目,以说tsuid 0202020
与tsuid 的现有叶相撞010101
。然后,可以使用HTTP API查询冲突列表,以查看特定TSUID是否由于冲突而未出现在树中。
不匹配
当为树启用严格匹配时,TSMeta必须匹配规则集的每个级别上的规则才能添加到树中。如果一个或多个级别无法匹配,则不会添加TSUID。与冲突类似,将为未能写入树的每个TSUID记录不匹配的条目。该条目将包含TSUID以及有关哪个规则和级别无法匹配的简短消息。
例子
假设我们的TSD存储了以下时间序列:
TS# | 公 | 标签 | TSUID |
---|---|---|---|
1 | cpu.system | dc = dal,host = web01.dal.mysite.com | 0102040101 |
2 | cpu.system | dc = dal,host = web02.dal.mysite.com | 0102040102 |
3 | cpu.system | dc = dal,host = web03.dal.mysite.com | 0102040103 |
4 | app.connections | 主机= web01.dal.mysite.com | 010101 |
五 | app.errors | host = web01.dal.mysite.com,owner = doe | 0101010306 |
6 | cpu.system | dc = lax,host = web01.lax.mysite.com | 0102050101 |
7 | cpu.system | dc = lax,host = web02.lax.mysite.com | 0102050102 |
8 | cpu.user | dc = dal,host = web01.dal.mysite.com | 0202040101 |
9 | cpu.user | dc = dal,host = web02.dal.mysite.com | 0202040102 |
请注意,对于此示例,我们不会使用任何自定义值规则,因此我们不需要显示TSMeta对象,但假设这些值填充了TSMeta。此外,为了便于说明,每个UID截断TSUID为1个字节。
现在让我们设置一个strictMatching
禁用的树和以下规则:
水平 | 订购 | 规则类型 | 字段(值) | 正则表达式 | 分隔器 |
---|---|---|---|---|---|
0 | 0 | TagK | DC | ||
0 | 1 | TagK | 主办 | 。* \(。*)\。mysite的\ .COM | |
1 | 0 | TagK | 主办 | \。 | |
2 | 0 | 公 | \。 |
这套规则的目标是按数据中心,然后是主机,然后按公制来订购我们的时间。我们公司可能在全球拥有数千台服务器,因此将它们全部显示在树的一个分支中是没有意义的,而是我们希望按数据中心对它们进行分组,并让用户根据需要进行深入分析。
在我们的示例数据中,我们有一些没有dc
标记名称的旧时间序列。但是,host
标记确实具有嵌入了数据中心名称的完全限定域名。因此,我们的规则集的第一级有两个规则。第一个将查找dc
标记,如果找到,它将使用该标记的值,并跳过第二个规则。如果dc
标记不存在,则第二个规则将扫描host
标记的值并尝试从FQDN中提取数据中心名称。第二级有一个规则,用于分组的值host
标记,以便属于该主机的所有指标都可以显示在其下方的分支中。最终级别具有度量规则,该规则包括用于通过包含的数据进一步对时间序列进行分组的分隔符。由于我们有多个CPU和应用程序指标,所有指标均按期间划分,因此此时添加分隔符是有意义的。
结果
生成的树看起来像这样:
-
DAL
-
web01.dal.mysite.com
-
应用
-
连接(tsuid = 010101)
-
错误(tsuid = 0101010306)
-
-
中央处理器
-
系统(tsuid = 0102040101)
-
用户(tsuid = 0202040101)
-
-
-
web02.dal.mysite.com
-
中央处理器
-
系统(tsuid = 0102040102)
-
用户(tsuid = 0202040102)
-
-
-
web03.dal.mysite.com
-
中央处理器
-
系统(tsuid = 0102040103)
-
-
-
-
松
-
web01.lax.mysite.com
-
中央处理器
-
系统(tsuid = 0102050101)
-
-
-
web02.lax.mysite.com
-
中央处理器
-
-
系统(tsuid = 0102050102)