Facebook TSDB论文Gorilla分析

背景

TSDB时序数据库用于存储时间相关的数据,常用于监控系统的数据存储,分布式的TSDB提供了海量的数据存储能力,如InfluxDB、OpenTSDB等。关于TSDB更多详情,可以参考该系列博客:时间序列数据的存储和计算
随着监控数据量增长,对TSDB查询性能的要求越来越高,尤其是自动化运维系统,大量的查询操作让基于磁盘的TSDB系统难以满足。
Facebook基于此需求推出了TSDB论文,设计了一个基于内存的TSDB:Gorilla。并开源了Gorilla的原型项目beringei
本文主要基于Facebook官方论文相关解读分析Gorilla的架构和数据结构。

Gorilla架构

Gorilla是一个内存TSDB。它在监控数据写入HBase存储之前,起到一个write-through cache的作用。Gorilla的数据模型是一个简单的3元组,包括一个string类型的key、一个64-bit整型timestamp和一个双精度浮点类型value。Gorilla使用一种新的timeseries压缩算法,可以按照时间顺序将单条数据从16字节压缩到平均1.37字节,缩小12倍。Gorilla的内存数据结构设计使得在保持对单个时间序列进行时间段查找的同时也能快速和高效的进行全数据扫描。
Gorilla无状态的架构支持非常好的水平扩展能力。监控数据中定义的key用来唯一标识一个timeseries。根据key将timeseries数据进行shard(分片),每个timeseries数据集会被映射到一台单独的Gorilla主机上。因此扩展Gorilla主机时,可以通过调整分片算法将新的timeseries数据映射到新的主机上。
Gorilla支持高可用,通过将同一个timeseries数据写到2个不同地域的主机中,来应对单节点故障、网络切换、甚至是整个数据中心故障。在检测到故障时,所有读取操作会failed over到可用区域的主机,以确保用户不会感知到任何中断。

压缩算法


Gorilla引入了对timestamp和value的高压缩比算法,可大幅降低数据存储的大小。Timestamp根据时间关联的条目进行差值计算、以及差值的差值计算得到占用字节数非常小的数值并进行保存。同样Value使用XOR算法进行计算得到占用存储更小的数值进行保存。该算法在论文里描述的非常清楚,此处不再详述。

内存数据结构

TSmap

Timeseries Map (TSmap)是Gorilla实现的主要数据结构。如上图所示,TSmap包括一个C++ Vector和一个map(unordered_map)。Vector里保存指向timeseries的指针(shared_ptr)。Map里保存timeseries name(key)到timeseries指针(value)的映射,该map大小写不敏感并保留原有大小写。
Vector用于高效的分页扫描所有数据(根据vector下标)。Map用于特定时间的timeseries查询。该设计既满足快速按时间查询的需求,又能提供高效的数据扫描。
C++的shared-pointers可以在几毫秒时间内扫描拷贝整个vector(或者几个pages),可以有效避免对新写入数据流的影响。删除的timeseries会将对应的vector设置为“墓碑状态”,即对应的内存不释放,而是标记为dead,并用于新的timeseries重复使用。
Map和vector的并行访问使用一个简单的读写spin lock进行保护。每个timeseries上使用一个1-byte的spin lock实行互斥。单个timeseries相关很少的写流量,因此读写的锁争用较少。

ShardMap

如上图所示,还有一个ShardMap用于保存shardId(分片ID)到TSmap的映射。Timeseries在保存的时候根据timeseries name哈希散列到不同shardId(0 ~ NumberOfShard)。该map也是使用大小写不敏感hash算法。系统中的Shard总数几千以内,因此存储空指针的额外开销可以忽略。同样ShardMap也使用一个读写spin lock实现并行。
由于数据根据shard进行了分区,单个map变得足够小(大约100万个条目),C++的unordered-map有足够的性能,没有锁争用的问题。

Timeseries data block

最终保存的Timeseries数据结构(图中TS)由一系列closed data blocks和一个open data block组成。每个data block保存2小时的数据,Closed data block用于保存2小时以前的数据,Open data block用于保存2小时内最近的数据。Open data block是一个append-only的string,新的压缩后的timestamps和values追加到该string后面。一旦Open data block写满2小时,则将其close。Closed data block不允许修改,直到将其从内存里删除。在closing过程中,数据将被拷贝到从large slabs里分配的内存以减少内存碎片。拷贝之后open data block可以直接用于新的数据写入,避免open data block经常改变size导致reallocate内存从而导致内存碎片。
根据时间范围查询时,将拷贝关联的data blocks数据给远程调用者。整个data block直接返回给Client,并由Client完成timestamp和value的解压缩。

Timeseries key string

一般TSDB的数据模型里通常有一个Metric(如CPU使用率)和一些TAG(如host=10.10.10.10,cluster=A),并提供针对Metric和TAG的查询、聚合等功能。而Gorilla每个timeseries都有一个key string字符串作为其唯一标识。论文中没有太多描述,只是提了一下依赖更高层的工具去抽象和定义这个key string。简单的实现可能就是MetricName+TAG1(key=value)+TAG2..组成一个string。

磁盘数据结构

Gorilla使用GlusterFS存储持久化数据,以应对单机故障。GlusterFS是一个兼容POSIX的3副本分布式文件系统。之所以没有选择MySQL或者RocksDB,是因为Gorilla不需要提供一种数据库查询语言。
一个Gorilla主机上有多个shards的数据,每个shard有一个单独的目录,目录下包括4中类型的文件:Key list、append-only log、complete block files、checkpoint files。

  1. Key list是一个map用于保存timeseries string key到内存数据结构vector的ID的映射,新的key会被追加到当前key list文件尾,Gorilla会定期扫描每个shard里所有的keys并重写key list文件(猜测是为了保证一致性)。
  2. log file用于存储最新的数据流,包括压缩后的timestamps和values。每个shard只有一个log file,所以交替保存了多个timeseries的值。它和内存中的数据结构不同点在于每个timestamp-value pair都有一个32-bit整型ID标记,该ID应该就是key list里的vectorID,标记它属于哪个timeseries。log file并不是write-ahead-log(WAL),数据写入磁盘前会缓存64KB,因此宕机会导致几秒数据的丢失。不过Gorilla不需要提供ACID特性,相比WAL日志带来的收益,提供了更好的数据写入效率。
  3. complete block file存储压缩后的整个block数据,每隔2小时从内存中拷贝block数据并进行压缩,所以它比log file小了很多。该文件包含两个部分:一组连续的64KB slabs大小的block data;一个timeseriesID->data block指针pair的列表,用于标记block data属于哪个timeseries。这里timeseriesID应该和key list的vectorID是一个概念。
  4. checkpoint file用于标记某个时间的complete block file已经flush到磁盘。此时,对应的log file将被删除,数据流写入新的log file。宕机后接管该Shard的主机根据checkpoint file来确定从log file还是complete block file里读取数据。

总结

综上,Gorilla提供了一个对26小时内监控数据内存级分布式水平扩展的TSDB,在long-term分布式TSDB基础上提供了短时间(也是大部分查询需求时间段)内秒级快速查询的能力。

Facebook TSDB论文Gorilla分析的更多相关文章

  1. CVPR2018 关于视频目标跟踪(Object Tracking)的论文简要分析与总结

    本文转自:https://blog.csdn.net/weixin_40645129/article/details/81173088 CVPR2018已公布关于视频目标跟踪的论文简要分析与总结 一, ...

  2. AlphaTensor论文阅读分析

    AlphaTensor论文阅读分析 目前只是大概了解了AlphaTensor的思路和效果,完善ing deepmind博客在 https://www.deepmind.com/blog/discove ...

  3. Practical Lessons from Predicting Clicks on Ads at Facebook (2014)论文阅读

    文章链接: https://quinonero.net/Publications/predicting-clicks-facebook.pdf abstract Facebook日活跃度7.5亿,活跃 ...

  4. [源码分析] Facebook如何训练超大模型---(1)

    [源码分析] Facebook如何训练超大模型---(1) 目录 [源码分析] Facebook如何训练超大模型---(1) 0x00 摘要 0x01 简介 1.1 FAIR & FSDP 1 ...

  5. [源码分析] Facebook如何训练超大模型 --- (2)

    [源码分析] Facebook如何训练超大模型 --- (2) 目录 [源码分析] Facebook如何训练超大模型 --- (2) 0x00 摘要 0x01 回顾 1.1 ZeRO 1.1.1 Ze ...

  6. [源码分析] Facebook如何训练超大模型 --- (3)

    [源码分析] Facebook如何训练超大模型 --- (3) 目录 [源码分析] Facebook如何训练超大模型 --- (3) 0x00 摘要 0x01 ZeRO-Offload 1.1 设计原 ...

  7. 计算广告CTR预估系列(七)--Facebook经典模型LR+GBDT理论与实践

    计算广告CTR预估系列(七)--Facebook经典模型LR+GBDT理论与实践 2018年06月13日 16:38:11 轻春 阅读数 6004更多 分类专栏: 机器学习 机器学习荐货情报局   版 ...

  8. [论文翻译] 分布式训练 Parameter sharding 之 ZeRO

    [论文翻译] 分布式训练 Parameter sharding 之 ZeRO 目录 [论文翻译] 分布式训练 Parameter sharding 之 ZeRO 0x00 摘要 0x01 综述 1.1 ...

  9. [论文翻译] 分布式训练 Parameter Sharding 之 Google Weight Sharding

    [论文翻译] 分布式训练 Parameter sharding 之 Google Weight Sharding 目录 [论文翻译] 分布式训练 Parameter sharding 之 Google ...

随机推荐

  1. GetTop(),GetTopLeft()等等

    Panel_BattleInfo挂在屏幕最上方 protected override void OnStart() { Vector3 = pos = GetTop(); transform.Find ...

  2. Javascript-DOM笔记

    参考 javascript原生dom操作方法 JavaScript原生的dom操作方法 第一类:节点查找相关方法和属性 document/父节点.getElementById()document/父节 ...

  3. Luogu2114 [NOI2014]起床困难综合症 【位运算】

    题目分析: 按位处理即可 代码: #include<bits/stdc++.h> using namespace std; ; int n,m; int a[maxn],b[maxn]; ...

  4. STL学习笔记--临时对象的产生与运用

    所谓的临时对象,就是一种无名对象(unnamed objects).它的出现如果不在程序员的预期之下,往往造成效率上的负担.但有时刻意制造一些临时对象,却又是使程序干净清爽的技巧.刻意制造临时对象的方 ...

  5. sap程序下载

    有时需要下载sap 中的程序   一屏一屏的拷贝非常麻烦 这里是在网上找的的一个下载工具   实际就是一个sap程序   建立好sap程序 把代码拷贝进去 在参数处输入程序名字  和下载位置  F8运 ...

  6. 前端开发快速定位bug的一些小技巧

    1,根据报错信息定位: (1) Uncaught TypeError: Cannot read property 'attr' of undefined; 此类型为变量或者对象属性未定义类型. (2) ...

  7. 高仿JDK动态代理 底层源码实现

    动态代理实现思路 实现功能:通过Proxy.newProxyInstance返回代理对象 1.创建一个处理业务逻辑的接口,我们也和JDK一样,都使用InvocationHandler作为接口名,然后接 ...

  8. Python文件操作,异常语法

    1.文件 2.异常 1.文件的输入输出 #1.打开文件 open 函数open(file,[option])#file 是要打开的文件#option是可选择的参数,常见有 mode 等​#2.文件的打 ...

  9. linux系统安全加固--账号相关

    linux系统安全加固 一.账号相关 1.禁用或删除无用账号 减少系统无用账号,降低安全风险. 当我们的系统安装完毕后,系统默认自带了一些虚拟账户,比如bin.adm.lp.games.postfix ...

  10. linux防火墙添加端口

     防火墙配置文件: /etc/sysconfig/iptables 1.使用命令查看端口开启情况(下图为安装时未选择开启防火墙) [root@fullstack ~]# iptables -L -n ...