当前位置: 首页 > news >正文

大数据中的数据压缩原理

image.png

问题

遇到一个情况,IOT设备每秒上报10万条数据,每条数据2.5k大小,算下来一天的有2T的数据,然而存储到HDFS后数据大小仅为400G,压缩率为1:5是如何产生的,想从原理的角度来了解下大数据的压缩这方面的知识。

原理

主要有两个主要原理:列式存储、压缩方式,两者互为补充。

列式存储

想象一下原始数据(假设是 JSON 或 CSV 格式):

{"timestamp": 1723456789123, "device_id": "SN-12345", "temp": 25.6, "humidity": 65.2, "vibration": 0.012, ... (其他字段)}
{"timestamp": 1723456789124, "device_id": "SN-67890", "temp": 26.1, "humidity": 63.8, "vibration": 0.008, ...}
{"timestamp": 1723456789125, "device_id": "SN-12345", "temp": 25.8, "humidity": 65.5, "vibration": 0.015, ...}
...(每秒10万条)
  1. 行式存储 (如原始文本、传统数据库行存储):

    • 数据按行组织:每一行数据的所有字段值紧挨着存储在一起。

    • 写入快:追加新行很方便。

    • 读取整行快:一次 I/O 就能拿到一行的所有数据。

    • 压缩劣势: 同一行内的不同字段数据类型差异巨大(时间戳是长整数,设备 ID 是字符串,温度/湿度是浮点数,振动可能是浮点或整数)。通用压缩算法(如 gzip, Snappy, LZ4)在处理这种“混合沙拉”式的数据时,很难找到长的、重复的模式,压缩效率相对较低。压缩比通常在 2:1 到 4:1 之间,达到 5:1 比较困难。

  2. 列式存储 (如 HDFS 上常用的 Parquet, ORC):

    • 数据按列组织: 文件被分成多个列块。一个文件块内,所有行的 timestamp 值存储在一起,接着是所有行的 device_id 值存储在一起,然后是所有 temp 值,依此类推。

    • 写入稍慢:需要按列重组数据。

    • 读取整行慢:需要从多个地方读取不同列的数据再拼成行。

    • 压缩的巨大优势: 这是关键!同一列内的数据具有极高的相似性、规律性和重复性! 这使得针对特定列数据类型的、高度优化的压缩技术得以大显身手,显著提升压缩比:

      • 相同数据类型: 一列里的所有值都是同一种基本类型(全是整数、全是浮点数、全是字符串等)。压缩算法可以针对性地优化。

      • 高重复性:

        • device_id : 同一个设备会在短时间内连续上报多次。列存储后, SN-12345 , SN-12345 , SN-12345 … 会连续出现很多次。

        • timestamp : 通常是单调递增的毫秒或微秒时间戳。相邻时间戳之间的差值 ( delta ) 通常很小且非常规律(接近上报间隔)。

        • 传感器值 ( temp , humidity , vibration ): 物理世界的测量值通常变化缓慢。相邻数据点之间的值 ( delta ) 通常很小,或者在一个有限的范围内波动。

      • 低基数 (Low Cardinality): 某些列(如状态码、错误码、设备类型)可能只有少数几种取值,重复性极高。

压缩方式

针对列特性的“组合拳”

列式存储格式(如 Parquet, ORC)内部采用了多种高效的编码和压缩技术,充分利用了上述列数据的特性:

  1. 编码 (Encoding):在压缩前对数据进行转换,使其更易压缩或占用空间更小。

    • 字典编码 (Dictionary Encoding): 针对高重复性、低基数列(如 device_id )。为列中所有不重复的值建立一个字典( SN-12345 -> 0 , SN-67890 -> 1 ),然后将实际数据替换成字典中的短整数编码。字符串变短整数,压缩率极高!这是压缩 device_id 这类列的主力。

    • 游程编码 (Run-Length Encoding - RLE): 针对连续重复值。例如,如果 status 列连续 1000 次都是 OK ,RLE 会存储为 (OK, 1000) 而不是重复写 1000 次 OK 。对重复性极高的列非常有效。

    • 增量编码 (Delta Encoding): 针对单调递增或变化平缓的数值列(如 timestamp , 缓慢变化的传感器值)。存储第一个值,然后存储后续值与前一值的差值( delta )。这些 delta 通常是非常小的整数(时间差)或非常小的浮点数(传感器变化量),本身占位就小,更容易被后续压缩。 timestamp 列压缩的核心。

    • 位图编码 (Bit-Packing): 针对数值较小的整数。如果一个整数可以用 4 位表示(0-15),就不会浪费整个字节(8位)去存储它。将多个小整数打包进一个字节/字中。常与 delta 或 frame of reference 结合使用。

    • 帧偏移编码 (Frame of Reference - FOR): 针对数值范围有限的列。存储该列(或块)的最小值,然后存储每个值与这个最小值的差值。这些差值通常比原始值小得多,更容易位打包和压缩。

  2. 通用压缩 (Compression): 在应用了高效的编码之后,再对整个列块(或页)应用标准的、快速的通用无损压缩算法,进一步消除冗余:

    • Snappy: Google 开发,速度极快,压缩比适中。非常流行,适合追求速度的场景。

    • LZ4 / LZO: 类似 Snappy,高速,压缩比略好于或接近 Snappy。

    • Gzip (Deflate): 压缩比较好,速度比 Snappy/LZ4 慢。经典选择。

    • Zstandard (Zstd): Facebook 开发,在速度和压缩比之间取得了非常好的平衡,通常优于 Gzip 和 Snappy/LZ4。越来越流行。

    • Brotli: Google 开发,压缩比非常高,但速度较慢。适合对存储空间极度敏感,对写入/读取速度要求不高的场景。

    • LZ77 / Huffman (Deflate 基础): Gzip 等算法的基础,通过查找重复字符串和用更短的编码表示高频字符来压缩。

IoT 场景分析压缩过程

  1. 原始数据 (2TB):

    • 包含所有字段(时间戳、设备ID、多个传感器值、可能的状态/元数据)。

    • 每条数据包含大量结构信息(字段名、分隔符、引号、逗号等)。

    • 数据以行为单位混合存储,不同类型数据交织,压缩效率不高。

  2. 写入 HDFS (列式存储格式如 Parquet):

    • 数据重组: 系统将接收到的数据按列拆分开。

    • 列块编码: 对每一列应用最适合的编码:

    • timestamp : Delta Encoding (存储时间差) + Bit-Packing (压缩小整数差值)。

    • device_id : Dictionary Encoding (用短整数代替长字符串) + 可能结合 RLE (如果同一设备连续上报)。

    • temp , humidity 等数值: Delta Encoding (存储变化量) 或 FOR (存储与最小值的差) + Bit-Packing。如果精度允许,可能先转换为整数(如 temp * 10 存储为整数)再应用上述编码。

    • 低基数列(如 status ): Dictionary Encoding + RLE

    • 压缩: 对经过编码的每个列数据块(或页)应用选定的通用压缩算法(如 Snappy, Zstd)。

    • 元数据存储: 文件头存储一次表结构(Schema)、字典信息、列块统计信息(最小值、最大值、空值数等),避免了每条记录重复存储字段名等结构信息。

    • 文件结构优化: Parquet/ORC 文件内部有精心设计的结构(Row Group, Column Chunk, Page),便于分块处理、谓词下推和高效压缩。

  3. 结果 (400GB):

    • 消除结构冗余: 字段名、分隔符等只在元数据中存一次。

    • 利用列内相似性: 字典编码消灭了字符串重复;增量/游程编码大幅减少了数值和ID的存储量;位打包节省了整数存储空间。

    • 高效压缩算法: 通用压缩算法在已经高度冗余(经编码后)的数据上进一步压缩。

    • 数据局部性: 列式存储本身让相似数据聚集,提高了压缩算法的效率。

总结关键点

  1. 列式存储是基础: 它通过将同类型、高相似性的数据物理上聚集在一起,为后续高效的、针对特定数据类型的编码和压缩创造了必要条件。没有列式存储,后续的优化压缩效果会大打折扣。

  2. 编码是关键: 字典编码、增量编码、游程编码、位打包等技术,直接利用了IoT数据中普遍存在的重复性、时间局部性、低基数、小范围变化等特性,在压缩前就将数据体积大幅缩减。它们是实现高压缩比(如5:1)的核心功臣。

  3. 通用压缩是最后一步: 在编码大幅减少冗余后,通用的无损压缩算法(Snappy, Zstd等)再进一步消除剩余的位级冗余,锦上添花。

  4. 元数据优化: 列式格式避免了行式格式中每条记录的结构信息冗余。

  5. IoT数据特性是内因: 设备ID重复、时间戳规律递增、传感器值缓慢变化、存在低基数列,这些天然特性是能够被高效压缩的根本原因

因此,从2TB 原始数据压缩到 400GB 的 HDFS 存储,正是列式存储(Parquet/ORC等)巧妙地利用了 IoT 数据的强规律性和重复性,通过一系列针对性的编码和高效的通用压缩算法,层层“瘦身”后的必然结果。这不仅节省了巨大的存储成本(5倍!),也极大地提高了后续大数据分析(如Spark, Hive, Presto)的查询效率(只需读取相关列)。

http://www.lryc.cn/news/619125.html

相关文章:

  • QT第五讲-控件QLineEdit、QSpinBox、QSlider、QScrollBar、QDial、QProgressBar、QLCDNumber
  • 计算机网络摘星题库800题笔记 第4章 网络层
  • 前端最新Vue2+Vue3基础入门到实战项目全套教程,自学前端vue就选黑马程序员,一套全通关!笔记
  • MCU中的液晶显示屏LCD(Liquid Crystal Display)控制器
  • VUE的8个生命周期
  • C++list(2)
  • 【JavaEE】多线程之线程安全(上)
  • 串口通信学习
  • 【PyTorch学习笔记 - 03】 Transforms
  • Spring-Cache 缓存数据
  • Dubbo 3.x源码(33)—Dubbo Consumer接收服务调用响应
  • 赛灵思ZYNQ官方文档UG585自学翻译笔记:UART Controller,通用异步收发传输器控制器
  • I2C 接收与发送数据的流程
  • 成都影像产业园实训考察:重庆五一职院关注技能就业
  • 【DL】深层神经网络
  • 《疯狂Java讲义(第3版)》学习笔记ch1
  • 力扣 hot100 Day71
  • 【1】Transformers快速入门:自然语言处理(NLP)是啥?
  • 机器学习第十课之TF-IDF算法(红楼梦文本分析)
  • LangChain SQLChatMessageHistory:SQL数据库存储聊天历史详解
  • 混合精度加快前向传播的速度
  • 计算机视觉(8)-纯视觉方案实现端到端轨迹规划(模型训练+代码)
  • MDD-Net:通过相互Transformer进行多模态抑郁症检测
  • 【沧海拾昧】使用LibUsbDotNet进行Windows/Ubuntu跨平台串口管理
  • XGBoost 的适用场景以及与 CNN、LSTM 的区别
  • 循环神经网络(RNN)全面解析
  • 文件IO(1)
  • 【doris基础与进阶】3-Doris安装与部署
  • UE5多人MOBA+GAS 42、提高头像画质
  • 方格网法土方计算不规则堆体