张锐| 存储和缓存工程师
由徐静涵,王健和工程师张天颖合着
在Pinterest,开发人员依靠Statsboard来监视其系统并发现问题。 可靠高效的监控系统对于开发速度非常重要( 3 = S ! 8 L。 过去,我们曾使用OpenTSDB来摄取和提供指标数据。 但是,随着Pinterest的增长,服务的数量也从数百种增加到数千种,每秒生成数百万个数据点,并且还在增长。
尽管Oc 8 - w WpenTSDB在功能[ K [ 8上运行良好,但随着Pinterest的增长,其性能下降,从而导致运营开销(例如,严重* + 3 } w . Q _的GC问题以及HBase经常崩溃)。 作为解决方案,开发了Goku-我们的内部时间序列数据库,其中包含用C ++编写的OpenTSDB兼容API,以支持有效的数据提取和昂贵的时间序列查询。
Two-level sharding with Goku
时间序列数据模型
时间序列数据
Goku遵循OpenTSDB的时间序列数据模型。 时间序列由键和随时间变& @ 化的一系列数字数据点组成。 键=指标名称+一组标签键值对。 例^ X B e j如,\" tc.pk O ` } 2roc.stat.cpu.total.infra-goku-a-prod {hoF , { / 2 +st = infra-goku-a-prodN E B E G # Y-001,cell_id = aws-us-east-1}\"。 数据点=键+值。 值是时间戳和值对X t } Q T } x 9。 例如(1525724520,1} P b = w { p 874706.61),(1525724580,173456.08)。
时间序列查询
每个查询都包含以下部分/全部:度量标准名称,过滤器,聚合器,下采样器,速3 ? 9 O ~率选w A [ m @项以及开始时间和结束时间。
1)度量标准名称的示例是\" tc.proc.stat.cpu.total.infra-goku-a-prod\"。
2)对标签值应用过滤器,以减少在查询或组中选择序列并汇总到各种标签上的) { w次数。 Goku支p = X | Q x H % n持的过滤器示例包括:完全匹配,通配符,或,否或正则表达式。
3)聚合器指定将多个时间序列合并为一个时间序列的数学方法。 Goku支持的聚合器示例包括:Sum,Max /C z E Y / b Min f w 8 ` 2 ^ )n,Avg,Zimsum,Count,Dev。 4)下采样器需要一个时间间隔和一个聚合器。 聚合器用于在指定间隔内跨所有数据点计算一个新数据点。
4)Rate Option可以选择计算变化率。 有关详细信息,请参见OpenTSDB数据模型。
挑战性
Goku解决了OpenTSDB中的许多限制,包括:
1)不必= 7 g ^ $ {要的扫描:悟空用反向索引引擎取代了OpenTSDB的低效率扫描。
2)数据大小:OpenTSDB中的数据点为20字节。 我们采用大猩猩压缩技术来实现12倍压缩。
3)单机聚合:OpenTSB q | g N g e 7DB将数据读取到一台服务器上并进y A ` P @ n a @ `行聚合,而Goku的新查询引擎? R k z 9 n @ V将计算移至存储层附近,从而可以在叶节S o Q % w O s点上进行并行处理,然后再聚合根节点上的部分结果。
4)序列化:OpenTSDB使用JSON,当要返回的数据点太多时,这很慢; Goku使用节俭的二进制文件代替。
架构
储存引擎
Goku在内存存储引擎中使用了Facebook Gorilla,以存储过去24小时的最新数据。
Brief introduction of the storage en7 Y $ Q Tgine. If you want to know the details, please chw n k j Q o ^ Keck the Gorilla
如上所示,在存储引擎中,时间序列被分为称为BucketMap的不同碎片。 对于一个时间序列,它也分为时段可以配置的时段(内部使用2小时时段)。 在每个BucketMap中,每个时间序列都分配有一个唯一的ID,并链接到一个BucketTimeSeries对象。 BucketTimeSe* H p i ^ ries在BucketStor& d O g x s i r ?age中将最新的可修改缓冲区存K 8 J R $ . X s N储区和存储ID保留到不可变数据存储区。 配置了存储桶时间后,BucketTiE I I W L e umeSeries中的数据将被写入BucketX ^ (Storage并变得不可变。
为了实现持久性,还将BucketData写入磁盘。 当Gf I Hoku重新启动时,它将把数据从磁盘读入内存。 我们使用NFS存6 l 5 ; p : s储数据,从而可以轻松进行a A $ r $ = 9分片迁移。
分片和路由
我们使用两层分片策略。 首先,我们对指标名称进行哈希处& _ (理,以确定一个时间序列所属的分片组。 接下来,对度量标准名称+标记键值集进行哈希处理,以确定时间序列在该组中的哪个分片。此策略可确保数据在各个分片之间保持平衡。 同时,由于每个查! k = M i a 6询仅进入一组,r z | P ) a因此扇出保持较低,以减少网络开销和尾部延迟。 此外,我们可以独立扩展3 c t 3每个分片组。
查询引擎
倒排索引
Goku, G K c } z通过指定标签键和标签值来支持查询。 例如,如果我们想知道一台主机host1的CPU使用率,则可以发送l | S b a查询cpu.usage {host = host1}。 为了支持这种查询,我们实现了反向索引。 (内部是从搜索词8 H v : ! 7 % ^ v到位集的哈希表。)搜索词可以是指标名称(例如cpu.usage)或标记键值对(例如host = host1)。 有了这个反向索引引擎,我们可以快速执行AND,OR,NOT,WILDARD和REGEX操作,与原始的基于OpenTSDB扫描的查询相比,它还F p {减少了许多不必要的查找。
聚合
从存储引擎中检索数据后,进入汇总和构造最终结果的步骤。
我们最初使用其内置的查询引擎尝试了OpenTSDB。 由于所有原B . J C m 3始数据都需要进入网络,因此性能严重下降,而且这些寿命短8 r _ ; = P J D {的对象也导致大量GC。
因此,我们在Goku中复制了OA V ( % & zpenTSDB的聚合层。 我们还尽早推动了计算,以尽量减少在线数据。
典型的查询流程如下:
来自Statsboard客户端(Pinterest的内部指标监控UI)的查询会转到任何代理Goku实例
代理* k ^ 6悟空将基于分片配置的查询扇出到同一组中的相关悟空实* T y t ! r ? e I例
每个悟空读取倒排索引以获取相关的时间序列ID,然后继续获取其数据
每个悟空根据查询聚合数据,例如聚合器,下采样器等
代理goku在从每个go? D : u s 0 Z -ku收集结果之后执行第二轮聚合,并返回给客户端
性能
与以前使用的O0 q 6 o I :penTSDB / HBase解决方案相比,Go{ N Bku在几乎所有方面的性能都更好。
这是另一个延迟图,{ K ^ v E M l X重点讨论了使用Goku之前和之后的高基数查询。
下一步是什么
基于磁盘的长期数据存储
Goku最终A 7 y p将支持超过一天的查询。 对于一年之类的长期查询,我们不会过多地关注在一秒钟内发生的情况,而是关注整体趋m ] } 3 6 n势。 因此,我们将进行下采样和压缩,以将每小时的存储分区合并为长期的存储分区,从而减少数据量并提高查询性能。
Goku Phase #2 — Disk based: Data iE E . bncludes index data and time series data
复写
目前,我们有两个执行双重写入操作的goku群集。 此设置为我们提供了高可用性:当一个群集中出现问题时,我们可以轻松地将流量切换到另一个群集。 但是,由于两个群集是独立的- 6 $ - _ x,因此很难确保数据的一致性。 例如,如果一次7 ) r j I写入成功而另一次写入失败,则数据将变得不一致。 另一个缺点是故障转移始终是群集级别的粒度。 我们正在努力进行基于日志的集群内复制,以支持主从分片。 这将提高读取可用性,以碎片级别的粒度保留数据一致性和故障转移。
分析用例
所有行业都广泛需要分析,Pinterest也不例外。 每分钟都会询问诸如实验结果和l i h J M A j $ Y广告系列效果之类的问题。 当前,我们主要将离线作业和HBase用于分析目的,这意味着没有实时数据,并且有很多不必要的预聚合。 由于时间序列数据的性质,Goku可以轻松地适应它,不仅可以提供实时数据,还可以按需聚合。
我们将继续探索Goku的用例。 如果您对这样的项目感兴趣,请查看我们的\"职业\"页面!
致谢:非常感谢Bu 2 m 2 trian Overstry 8 _ ! & P Y veet,能见度团队的Wei Zhu以及Paul Bindels和Chiyoung Seo协助推出了Goku和设计建议。
(本文翻译自Pinterest Engineering的文章《Goku: Building a scalable and highV . | N Q ! 7 per* { ( f % Jformant time serd d d 1ies database system》,参考:https://medium.com/pinterest-engineering/goku-building-a-scalable-and-high-perfor$ t t { hmant-time-series-database-system-a8ff5758a181)