本文摘译自 Netflix TechBlog : Scaling Time Series Data Storage — Part I

重点:扩容、缓存、冷热分区、分块。

时序数据 - 会员观看历史

Netflix的用户,每天观看1.4亿小时的内容。每位用户在查看影片和保存观看记录的时候,都会提供几个数据点。Netflix分析这些观看数据并且提供实时的精确书签和个性化推荐。

观看历史数据在如下三个方面增长:

  1. 随着时间进展,每位会员都会有更多的观看数据需要被保存。
  2. 随着会员数量增长,更多的会员的观看数据需要被保存。
  3. 会员每月观看时间在增加,每位会员都有更多的观看数据需要被保存。

随着Netflix在第一个十年增长到了1亿全球会员,这里有观看历史数据也有了巨大的增长。这边文章重点关注,怎样面对持续增长的观看历史数据的巨大挑战。

简单的开始

第一个云原生的版本使用了Cassandra。

在最初的版本里,每位会员的观看数据被以一个单独行保存在了Cassandra里。这使得会员增长的扩容变得很高效,并且读一位会员的完整观看记录变得简单高效。但是随着会员的增加,更重要的是每位会员观看了更多的影片,每行的大小以及总体的大小都在增长。

当每位会员的观看数据变多的时候,读有很多列的行就会成为很大的压力。

缓存层

Cassandra在写观看历史数据方面工作的很好,但是需要去优化读延迟的问题。为了优化读延迟,在增加写工作的代价下,我们在Cassandra存储前添加了一个内存中的分片缓存层(EVCache)。每个想Cassandra的写,都会导致一个额外的缓存查找,并且在缓存命中的时候新数据会和已存在的值合并。观看历史读请求会先被缓存服务。如果缓存未命中,条目会从Gassandra中读取,并且被压缩然后插入到缓存中。

配合着额外的缓存层,单一的Cassandra表存储方式在很多年都工作的很好。基于CustomerId的分区,在Cassandra集群上也扩容的很好。到2012年,观看历史的Cassandra集群,已经是Netflix最大的Cassandra集群。

重新设计:实时和压缩存储方式

为了可以设计出足以满足未来5年增长预期的方式,团队分析了数据的特点和数据模式,然后围绕两个主要目标重新设计了观看历史的存储:

  1. 更小的存储空间。
  2. 随着每位会员的观看增长,保持读写性能的一致性。

对于每位会员,观看历史数据被分成了两个部分:

  • 实时或者最近观看历史(LiveVH): 更少数量的最近观看记录,更频繁的更新。这部分数据以未压缩的格式,保存在上述的简单设计里。
  • 压缩或者归档的观看历史(CompressedVH): 更大数量的老观看记录,更少的更新。数据被压缩以减少存储空间。压缩后的观看记录,保存在每个row key中的单一行里。

LiveVH和CompressedVh呗保存在不同的表里,并且经过不同的调校去达到更好的性能。

写流程

新的观看记录,使用和上边描述一样的方式写入LiveVH。

读流程

为了能够从新设计中获益,观看历史的API被更新增加了带有读最近或全部数据的选项。

  • 最近观看历史:对于大多数情况,结果只从LiveVH里读取。限制了数据大小以获得低得多的延迟。
  • 完整观看历史:从LiveVH 和 CompressedVH 中并行读来实现。由于数据压缩以及CompressedVH有更少的列,更少的数据被读取;因此读速度有了显著的提高。

CompressedVH 更新流程

在从LiveVH中读观看历史记录的时候,如果记录的数量超过了配置的阈值,最近观看记录会一个后台任务被汇总、压缩、保存在CompressedVH里。汇总的数据会带row key:CustomerId被保存在CompressedVH中。新汇总的记录会被记录版本,并且在被写入后会被读取检查一致性。只有在验证过新版本的一致性后,旧版本的汇总数据会被删除。

通过分块自动扩容

对于大部分会员来说,在一行里保存压缩后的全部观影数据,在读流程里有着很好的性能。但是由于少量的有着非常大观影历史的会员来说,从CompressedVH的单行里读取记录由于和上述类似的原因开始变慢。所以需要对这种少见的情况有个上限,并且避免影响到正常情况的读写延迟。

为了解决这些问题,如果数据大小超过了配置的阈值,我们会把汇总压缩的数据分成了几块。这些块保存在不同的Cassandra节点上。这样并行读写这些块使得即使非常大的观看记录也可以有个读写延迟的上限。

写流程

依照配置的块大小,汇总压缩的数据被拆封到多个块里。所有的块并行写到不同的行里,使用row key: CustomerId$Version$ChunkNumber. 在写完前边的块数据之后,Metadata 被写到他单独的行里,使用row key: CustomerId。

读流程

先通过CustomerId的key读metadata。每次读最多延迟成两次读。

缓存层变化

对于有很大观看记录的会员来说,把全部缓存记录保存在一个EVCache entry是不可能的。所以和CompressedVH模型类似,每个大观看记录缓存单元会被拆成多个块,metadata保存在第一个块里。

结果

在并行,压缩,和改进过的数据模型的共同作用下,这个团队完成了所有的目标。

  • 通过压缩打到更小的存储空间
  • 通过分块和并写读写,达到了一致性读写性能。

团队减少了6倍的数据空间,减少13倍的Cassandra的维护时间,减小了5倍的平均读延迟,和1.5倍的平均写延迟。更重要的是,给了团队一个可扩容的架构,和课协调Netflix飞速增长的观看数据的头部空间。

在下一部分,会解释最近的扩容挑战,促进了下一个观看历史数据存储架构的迭代。

增长中的时间序列存储(Scaling Time Series Data Storage) - Part I的更多相关文章

  1. 时间序列大数据平台建设(Time Series Data,简称TSD)

    来源:https://blog.csdn.net/bluishglc/article/details/79277455 引言在大数据的生态系统里,时间序列数据(Time Series Data,简称T ...

  2. Java实现购物车功能:方式一:存放在session中.方式二:存储在数据库中

    //将购物车产品加入到cookie中,方式同浏览记录.Java实现购物车,方式一(简易版):存储在session中.这种方式实现还不严谨,大家看的时候看思路即可.(1). JSP页面中,选择某一款产品 ...

  3. MySQL存储引擎的实际应用以及对MySQL数据库中各主要存储引擎的独特特点的描述

    MySQL存储引擎的实际应用以及对MySQL数据库中各主要存储引擎的独特特点的描述: 1.MySQL有多种存储引擎: MyISAM.InnoDB.MERGE.MEMORY(HEAP).BDB(Berk ...

  4. 67.Android中的数据存储总结

    转载:http://mp.weixin.qq.com/s?__biz=MzIzMjE1Njg4Mw==&mid=2650117688&idx=1&sn=d6c73f9f04d0 ...

  5. 彻底了解android中的内部存储与外部存储

    我们先来考虑这样一个问题: 打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的 ...

  6. Android笔记——Android中数据的存储方式(二)

    我们在实际开发中,有的时候需要储存或者备份比较复杂的数据.这些数据的特点是,内容多.结构大,比如短信备份等.我们知道SharedPreferences和Files(文本文件)储存这种数据会非常的没有效 ...

  7. Android笔记——Android中数据的存储方式(一)

    Android中数据的存储方式 对于开发平台来讲,如果对数据的存储有良好的支持,那么对应用程序的开发将会有很大的促进作用. 总体的来讲,数据存储方式有三种:一个是文件,一个是数据库,另一个则是网络.其 ...

  8. ArcGIS Engine开发之旅07---文件地理数据库、个人地理数据库和 ArcSDE 地理数据库中的栅格存储加以比较 、打开栅格数据

    原文:ArcGIS Engine开发之旅07---文件地理数据库.个人地理数据库和 ArcSDE 地理数据库中的栅格存储加以比较 .打开栅格数据 对文件地理数据库.个人地理数据库和 ArcSDE 地理 ...

  9. 彻底理解android中的内部存储与外部存储

    我们先来考虑这样一个问题: 打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的 ...

随机推荐

  1. echarts的地图点击事件

    1.echarts的地图展示,有时候展示出的数据,虽然鼠标点击上去某个省份或者某个地方会有数据显示,但是点击一下地图没有任何动态效果,如何添加地图点击效果呢,这里自己也是坐下笔记,方便以后使用. 参考 ...

  2. CF121E Lucky Array

    题解: 这个题好像暴力+线段树就能过 就是对修改操作暴力,线段树维护查询 为啥呢 因为保证了数$<=1e4$,于是这样复杂度$n*1e4=1e9$ 那么特殊数只有30个 又因为操作是只加不减的, ...

  3. MSB4064 错误

    把项目从vs2008转成vs 2012 后,受用msbuild 编译出错 错误Code:MSB4064 修改 把msbuild 的路径从 %windir%\Microsoft.NET\Framewor ...

  4. Redis数据结构之quicklist

    本文及后续文章,Redis版本均是v3.2.8 我们在使用Redis对外暴露的list数据结构时,给我们带来极大的便利性.其底层实现所依赖的内部数据结构就是quicklist. 我们先来回忆下list ...

  5. CodeForces 630G Challenge Pennants (组合数学)

    <题目链接> 题目大意: 有两种旗子,分别有5个和3个,将这些旗子分配给n个人,有多少中方法. 解题分析: 5面A旗子的发放方案为:$[1,1,1,1,1],[1,1,1,2],[1,2, ...

  6. 【C#】时间类型修改

    鉴于前后端分离发展的迅速.前端很多时间控件都会读UTC时间. 安利一个小知识 // // 摘要: // Creates a new System.DateTime object that has th ...

  7. python class属性

    代码一: class A(object): pass a = A() a.name = "class_A" print(a.name) #class_A 代码二:class A(o ...

  8. 机器学习——KNN

    导入类库 import numpy as np from sklearn.neighbors import KNeighborsClassifier from sklearn.model_select ...

  9. 编程菜鸟的日记-初学尝试编程-C++ Primer Plus 第5章编程练习5

    #include <iostream>using namespace std;const MAXSIZE=12;const year=3;int main(){ char *month[M ...

  10. Java 获取当前日期的几种方法

    import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import ja ...