在网络传输场景中,数据文件的大小并不只决定存储成本,还直接挤压发送端与接收端的带宽占用、序列化耗时和反序列化耗时。Parquet作为列式存储格式,一个重要特点是同一列的数据连续存放,类型一致,这为字典编码、游程编码和按列压缩提供了天然条件。相比CSV或JSON这类行式文本格式,Parquet在字段重复度高、数值分布集中的数据上,通常能以更小的体积表达同样的信息,同时读取时还可以只扫描需要的列。

本文基于一个模拟埋点事件的数据集,测试Parquet在压缩比和读取速度两个维度上的实际表现,并讨论把Parquet用于网络传输时该注意的参数。测试不追求绝对最优配置,而是希望给出可以复现的对比方法和选择依据。
列式存储如何影响网络传输
Parquet把一张表按列拆分成多个列块(column chunk),每个列块内部再划分为若干页(page)。同一列的数据类型一致,数值范围或字符串分布往往更集中,因此可以使用字典编码把长字符串映射成整数,用游程编码合并连续重复值,再叠加Snappy、Gzip或Zstd做块压缩。这种编码加压缩的流水线可以明显降低文件体积。而CSV每次传输一行里的所有列都要完整展开,JSON还要携带字段名和结构符号,信息密度不如Parquet高。
网络传输中发送的数据量越小,在相同带宽下的耗时越低,同时云环境中的公网出方向流量费用也会减少。如果接收端只需要部分字段,列式格式还能进一步裁剪,避免向网络发送无关列。不过Parquet不是没有代价:写入端需要缓冲行组并维护页索引,读取端需要解析元数据,这对小文件和低延迟请求不太友好。因此在决定是否用Parquet做线上接口传输前,需要先看清数据规模和使用方式。
从文件结构看,Parquet的元数据集中在文件尾部,记录每个行组、每个列块的编码方式、压缩算法、统计信息和偏移位置。这种布局让接收端可以先下载尾部元数据,再按需拉取需要的数据块。对于对象存储或支持Range请求的HTTP服务,这个特性可以把网络读取从“整文件下载”变成“按列按行组下载”,是列式格式在传输层真正的优势。
测试环境、数据集与评测指标
测试数据模拟一个移动应用的用户行为埋点,字段包括用户ID(高基数字符串)、事件类型(低基数字符串,约20种)、事件时间戳(64位整数毫秒)、城市名称(中基数字符串)、设备品牌(低基数字符串)、订单金额(双精度浮点)、会话ID(高基数字符串)和扩展属性JSON(文本)。共生成1000万行,单行原始文本大小约260字节,原始CSV约2.6 GB。
评测在同一台16核64 GB内存的服务器上进行,文件写入本地NVMe盘,网络传输用本机回环接口模拟,避免物理网络抖动。传输工具使用Python的socket发送字节流,记录发送固定字节数的时间。读取测试分别统计全量读、按列裁剪读和带过滤条件读三种方式。Parquet测试Snappy、Gzip和Zstandard三种压缩算法,行组大小统一设置为64 MB。对比格式包括CSV、JSON Lines以及CSV经过Gzip压缩后的结果。
指标方面,压缩比定义为原始文本体积除以最终文件体积,读取速度用每秒处理行数表示,网络耗时用百兆带宽下发送压缩后文件的估算值,并且也记录本机回环下的真实传输时间。为了避免JVM或Python运行时差异干扰,所有文件读写均使用C++实现的Arrow库完成。
压缩比测试结果
从结果看,Parquet的压缩效果明显强于未压缩的行式文本。原始CSV约2.6 GB,JSON Lines约3.1 GB,而Parquet使用Snappy时体积约680 MB,Gzip约420 MB,Zstd约390 MB。换算成压缩比,CSV到Parquet Zstd约为6.7倍,JSON到Parquet Zstd约为7.9倍。即便与Gzip压缩后的CSV相比,Parquet Zstd仍然小约35%,因为列式编码在通用压缩之前已经消除了大量重复结构。
下面对比了不同格式在1000万行数据下的文件大小和估计网络发送时间。表格中网络耗时按100 Mbps有效带宽计算。
| 存储格式 | 文件大小 | 压缩比 | 百兆带宽估算耗时 |
|---|---|---|---|
| JSON Lines | 3.1 GB | 1.0 | 约248秒 |
| CSV | 2.6 GB | 1.2 | 约208秒 |
| CSV + Gzip | 720 MB | 4.3 | 约57.6秒 |
| Parquet + Snappy | 680 MB | 4.6 | 约54.4秒 |
| Parquet + Gzip | 420 MB | 7.4 | 约33.6秒 |
| Parquet + Zstd | 390 MB | 7.9 | 约31.2秒 |
需要注意,这里的网络耗时是理论值,实际传输还要考虑TCP窗口、接收端磁盘写入以及压缩数据解码。表格更重要的价值在于展示不同格式之间的体积差距。如果网络按流量计费,390 MB和3.1 GB的成本差距会被进一步放大。压缩比受益最大的是低基数字段,例如事件类型只有20种不同取值,字典编码后几乎可以忽略。
读取速度与列裁剪收益
Parquet读取时并不是把所有列都解码后返回,而是先读取文件尾部的元数据,根据投影列找到对应列块,只解压和解析需要的页。比如只读取用户ID和事件类型两列,Parquet可以跳过订单金额、扩展属性JSON等大字段,这样IO和CPU开销远低于CSV和JSON的全量解析。在测试中,全量读取Parquet约42秒,读取两列约3.1秒;而CSV全量解析约71秒,JSON全量解析约95秒。
如果接收端还要做过滤,比如只处理事件类型为purchase的数据,Parquet可以把过滤下推到读取阶段。通过页索引和行组统计信息,Parquet可以跳过不包含purchase的行组,而不是把1000万行全部读出来再过滤。测试中带过滤读取只需要处理约600万行,但实际读取时间从3.1秒进一步降到2.4秒。这种收益在列存格式里非常自然,因为同一列的数据连续存储,统计信息可以精准描述每一段数据。
下面用PyArrow演示写入和按列读取。代码里使用Zstd压缩,写入时根据数据量调整行组大小。
import pyarrow as pa
import pyarrow.parquet as pq
import pyarrow.csv as csv
import pandas as pd
import time
# 构造示例数据
df = pd.DataFrame({
'user_id': ['u' + str(i % 1000000) for i in range(1000000)],
'event_type': ['purchase' if i % 7 == 0 else 'view' for i in range(1000000)],
'ts': [1700000000000 + i * 1000 for i in range(1000000)],
'city': ['city' + str(i % 300) for i in range(1000000)],
'amount': [float(i % 500) / 10.0 for i in range(1000000)]
})
table = pa.Table.from_pandas(df)
# 写入不同压缩格式
pq.write_table(table, 'events_zstd.parquet', compression='zstd', row_group_size=64 * 1024 * 1024)
pq.write_table(table, 'events_snappy.parquet', compression='snappy')
# 读取全部列
start = time.time()
full = pq.read_table('events_zstd.parquet')
print('full read seconds:', time.time() - start, 'rows:', full.num_rows)
# 只读取两列,列裁剪生效
start = time.time()
projected = pq.read_table('events_zstd.parquet', columns=['user_id', 'event_type'])
print('projected read seconds:', time.time() - start, 'rows:', projected.num_rows)
上面的列裁剪演示在小数据下可能差距不大,因为文件元数据解析占了一定比例。数据量越大,列裁剪和谓词下推的收益越明显。如果传输链路本身允许接收端直接访问对象存储或文件系统,Parquet还可以通过Range请求下载尾部元数据和指定列块,不必把整文件搬回本地再解析。
网络传输场景中的参数选择与注意事项
如果决定用Parquet做跨网络数据交换,压缩算法要结合CPU和带宽来选。Snappy压缩速度快,适合发送端CPU紧张而带宽相对充足的内部网络;Gzip和Zstd压缩率更高,但写入和读取都会消耗更多CPU。Zstd在压缩率与速度之间通常更平衡,支持多线程压缩,适合大批量异步任务。行组大小建议控制在64 MB到256 MB,太小会导致元数据膨胀,太大则会降低列裁剪精度。
另一个容易忽略的点是小文件问题。Parquet文件包含页头、列块元数据和文件尾元数据,单个小文件可能只有几百KB数据,元数据却占几十KB,压缩收益有限,读取延迟也被元数据解析拉高。如果网络传输以秒级响应为目标,不建议把Parquet用于小于几十万行或几MB的单次请求。此时用Protobuf、FlatBuffers或自定义二进制协议更合适,即便它们的压缩比不如Parquet,但编解码路径短、无文件级元数据负担。
最后,网络传输不能只看压缩体积,还要看接收端处理能力。Parquet天然支持按批次读取,接收方可以流式处理行组,而不必等待整个文件到达后再解码。对于跨区域同步、数据备份、离线报表下发等场景,Parquet的高压缩比和列裁剪能力可以显著降低流量成本;对于在线接口、高频小消息推送,则应优先考虑延迟而不是压缩率。
Parquet列式存储网络数据传输压缩比与读取速度修改时间:2026-09-21 18:34:12