用于存储视频帧的 HBase 模式设计:行 vs 列,行作为列
HBase schema design to store video frames: rows vs columns, rows as columns
有朋友问我如何在HBase中逐帧存储原始视频。典型的访问模式是在一段时间内检索帧。每帧大约。 7MB,素材以每秒约 30 帧的速度捕获。例如,一段 20 分钟的视频将占用大约 250GB 的存储空间。
我看过 HBase: the definitive guide, titled HBase Schema Design: things you need to know 的作者 Lars George 的精彩视频,他在视频中谈到了存储视频 "chunks"(他谈论视频的片段从 1:07:12 开始并结束在 1:08:52),所以 HBase 似乎可能适合这个用例。
我创建了几个行键选项:
场景0:rowkey=视频ID+时间戳;单列中的帧(高、瘦 table),例如
key col
video1|1497567476.123 image=[image BLOB]
video1|1497567476.156 image=[image BLOB]
...
video1|1497567536.014 image=[image BLOB]
优点:
- 简单
缺点:
- 因为键是连续的所以读取时的热点
场景一:rowkey = hash(video ID + round(timestamp, 1 minute)) + timestamp;单列中的帧,例如
key col
18ba6892ce0933ece7282b1f2971b3fd|1497567536.014 image=[image BLOB]
...
2ea8ce843615408fb19f8d6e44df32c7|1497567476.123 image=[image BLOB]
2ea8ce843615408fb19f8d6e44df32c7|1497567476.156 image=[image BLOB]
rowkey 有一个前缀,确保一分钟的块分布在集群中,并且在一分钟的块内,帧是连续的时间顺序。
优点:
- 块分布在各个区域,并且在每个块内,读取将是顺序的。这是一种折衷方案,允许顺序读取 并且 跨 HBase 区域分布数据。
缺点:
- 有点死板;不确定最佳块时间 window 应该是多少,一旦设置,就很难更改
场景二:rowkey = hash(video ID + round(timestamp, 1 minute));列中的帧偏移 'base' 时间(列类似于 OpenTSDB):
key col:base_time + (0 * x millis) col:base_time + (1 * x millis) col:base_time + (2 * x millis)
18ba6892ce0933ece7282b1f2971b3fd image=[image BLOB] ... ...
2ea8ce843615408fb19f8d6e44df32c7 image=[image BLOB] image=[image BLOB] [image BLOB]
优点:
- 模式已被 OpenTSDB 证明适用于时间序列指标(请参阅 this presentation 中的幻灯片 13)
缺点:
- 非常大的行,这对于 HBase 通常不是一个好主意
有人对视频帧的最佳 rowkey 设计有任何建议或见解吗?
注意:我知道有几个类似的例子,它们不是使用 HBase 来存储视频片段,而是使用序列文件或具有单独索引的 .har 文件来捕获元数据允许随机访问。现在,我想专注于 HBase:特别是行键设计。
我喜欢你的方法,但我建议使用 (videoID % number_of_regions) + videoID + timestamp。这样您就不会被限制在 1 分钟的限制内,但读取是有影响的,并且整个视频都存储在同一区域。
视频每秒有 200MB 的数据(每帧 7MB * 30 fps)。
当单元很小时,数据局部性是一件好事,从一台机器读取所有内容比等待所有机器获得 return 结果更快。即使加载 5 秒的视频(1GB)对于单机磁盘 IO 来说已经是一个巨大的负载,因此数据局部性无济于事。
我相信salting/prefixing密钥是这里最好的解决方案
key = hash(video_id, timestamp) + video_id + timestamp
您将在整个集群中均匀分布数据并分散负载。您可以将帧存储在单独的列中的单行中,或者将 frame_id 添加到键中,这无关紧要。
要获得更好的性能,您还需要设置正确的 CF 大小设置以适合您的数据。
有朋友问我如何在HBase中逐帧存储原始视频。典型的访问模式是在一段时间内检索帧。每帧大约。 7MB,素材以每秒约 30 帧的速度捕获。例如,一段 20 分钟的视频将占用大约 250GB 的存储空间。
我看过 HBase: the definitive guide, titled HBase Schema Design: things you need to know 的作者 Lars George 的精彩视频,他在视频中谈到了存储视频 "chunks"(他谈论视频的片段从 1:07:12 开始并结束在 1:08:52),所以 HBase 似乎可能适合这个用例。
我创建了几个行键选项:
场景0:rowkey=视频ID+时间戳;单列中的帧(高、瘦 table),例如
key col
video1|1497567476.123 image=[image BLOB]
video1|1497567476.156 image=[image BLOB]
...
video1|1497567536.014 image=[image BLOB]
优点:
- 简单
缺点:
- 因为键是连续的所以读取时的热点
场景一:rowkey = hash(video ID + round(timestamp, 1 minute)) + timestamp;单列中的帧,例如
key col
18ba6892ce0933ece7282b1f2971b3fd|1497567536.014 image=[image BLOB]
...
2ea8ce843615408fb19f8d6e44df32c7|1497567476.123 image=[image BLOB]
2ea8ce843615408fb19f8d6e44df32c7|1497567476.156 image=[image BLOB]
rowkey 有一个前缀,确保一分钟的块分布在集群中,并且在一分钟的块内,帧是连续的时间顺序。
优点:
- 块分布在各个区域,并且在每个块内,读取将是顺序的。这是一种折衷方案,允许顺序读取 并且 跨 HBase 区域分布数据。
缺点:
- 有点死板;不确定最佳块时间 window 应该是多少,一旦设置,就很难更改
场景二:rowkey = hash(video ID + round(timestamp, 1 minute));列中的帧偏移 'base' 时间(列类似于 OpenTSDB):
key col:base_time + (0 * x millis) col:base_time + (1 * x millis) col:base_time + (2 * x millis)
18ba6892ce0933ece7282b1f2971b3fd image=[image BLOB] ... ...
2ea8ce843615408fb19f8d6e44df32c7 image=[image BLOB] image=[image BLOB] [image BLOB]
优点:
- 模式已被 OpenTSDB 证明适用于时间序列指标(请参阅 this presentation 中的幻灯片 13)
缺点:
- 非常大的行,这对于 HBase 通常不是一个好主意
有人对视频帧的最佳 rowkey 设计有任何建议或见解吗?
注意:我知道有几个类似的例子,它们不是使用 HBase 来存储视频片段,而是使用序列文件或具有单独索引的 .har 文件来捕获元数据允许随机访问。现在,我想专注于 HBase:特别是行键设计。
我喜欢你的方法,但我建议使用 (videoID % number_of_regions) + videoID + timestamp。这样您就不会被限制在 1 分钟的限制内,但读取是有影响的,并且整个视频都存储在同一区域。
视频每秒有 200MB 的数据(每帧 7MB * 30 fps)。
当单元很小时,数据局部性是一件好事,从一台机器读取所有内容比等待所有机器获得 return 结果更快。即使加载 5 秒的视频(1GB)对于单机磁盘 IO 来说已经是一个巨大的负载,因此数据局部性无济于事。
我相信salting/prefixing密钥是这里最好的解决方案
key = hash(video_id, timestamp) + video_id + timestamp
您将在整个集群中均匀分布数据并分散负载。您可以将帧存储在单独的列中的单行中,或者将 frame_id 添加到键中,这无关紧要。
要获得更好的性能,您还需要设置正确的 CF 大小设置以适合您的数据。