Spark SQL - gzip、snappy 和 lzo 压缩格式之间的区别
Spark SQL - difference between gzip vs snappy vs lzo compression formats
我正在尝试使用 Spark SQL 编写 parquet
文件。
默认情况下,Spark SQL 支持 gzip
,但它也支持其他压缩格式,如 snappy
和 lzo
。
这些压缩格式有什么区别?
只需在您的数据上试用它们即可。
lzo 和 snappy 是快速压缩器和非常快的解压缩器,但压缩率较低,与 gzip 相比压缩效果更好,但速度稍慢。
如果您可以处理更高的磁盘使用率以获得性能优势(更低的 CPU + Splittable),请使用 Snappy。
当 Spark 默认从 GZIP 切换到 Snappy 时,原因如下:
Based on our tests, gzip decompression is very slow (< 100MB/s),
making queries decompression bound. Snappy can decompress at ~ 500MB/s
on a single core.
活泼:
- 存储空间Space:高
- CPU 用法:低
- 可拆分:是 (1)
GZIP:
- 存储空间Space:中等
- CPU 用法:中
- 可拆分:否
1) http://boristyukin.com/is-snappy-compressed-parquet-file-splittable/
我同意第一个答案(@Mark Adler) 并有一些研究信息[1],但我不同意第二个答案(@Garren S)[2]。也许加伦误解了这个问题,因为:
[2] Parquet 可与所有支持的编解码器拆分:Is gzipped Parquet file splittable in HDFS for Spark?,Tom White 的 Hadoop:权威指南,第 4 版,第 5 章:Hadoop I/O,第 106 页。
[1] 我的研究:
源数据 - 205 GB。文本(分隔字段),未压缩。
输出数据:
<!DOCTYPE html>
<html>
<head>
<style>
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
</style>
</head>
<body>
<table style="width:100%">
<tr>
<th></th>
<th>time of computing, hours</th>
<th>volume, GB</th>
</tr>
<tr>
<td>ORC with default codec</td>
<td>3-3,5</td>
<td>12.3</td>
</tr>
<tr>
<td>Parquet with GZIP</td>
<td>3,5-3,7</td>
<td>12.9</td>
</tr>
<tr>
<td>Parquet with SNAPPY</td>
<td>2,5-3,0</td>
<td>60.4</td>
</tr>
</table>
</body>
</html>
在由 2 m4.16xlarge 组成的 EMR 上使用 Hive 执行转换。
转换 - select 所有字段按多个字段排序。
当然,这项研究并不标准,但至少有一点显示了真实的比较。与其他数据集和计算结果可能不同。
压缩比:
GZIP 压缩比 Snappy 或 LZO 使用更多 CPU 资源,但提供更高的压缩率。
一般用法:
GZip 通常是 冷 数据的不错选择,这些数据很少被访问。
对于经常访问的 hot 数据,Snappy 或 LZO 是更好的选择。
Snappy 的性能通常优于 LZO。值得进行 运行 测试,看看您是否发现显着差异。
可拆分性:
如果你需要你的压缩数据是可拆分的,BZip2、LZO 和 Snappy 格式是可拆分的,但 GZip 不是。
与 Snappy 相比,GZIP 压缩数据多 30%,与使用 Snappy 数据相比,读取 GZIP 数据时 CPU 多 2 倍。
LZO 专注于低 CPU 使用率下的解压缩速度和更高的压缩率,但代价是更多 CPU。
对于更长的term/static存储,GZip压缩还是比较好。
根据下面的数据,我认为 gzip
在流媒体等场景之外获胜,其中 write-time 延迟很重要。
请务必牢记,速度本质上就是计算成本。但是,云计算是一项 one-time 成本,而云存储是一项经常性成本。取舍取决于数据的保留期限。
让我们在 Python.
中测试大小 parquet
文件的速度和大小
结果(大文件,117 MB):
+----------+----------+--------------------------+
| snappy | gzip | snappy/gzip |
+-------+----------+----------+--------------------------+
| write | 1.62 ms | 7.65 ms | 4.7x faster |
+-------+----------+----------+--------------------------+
| size | 35484122 | 17269656 | 2x larger |
+-------+----------+----------+--------------------------+
| read | 973 ms | 1140 ms | 1.2x faster |
+-------+----------+----------+--------------------------+
结果(小文件,4 KB,Iris 数据集):
+---------+---------+--------------------------+
| snappy | gzip | snapp/gzip |
+-------+---------+---------+--------------------------+
| write | 1.56 ms | 2.09 ms | 1.3x faster |
+-------+---------+---------+--------------------------+
| size | 6990 | 6647 | 5.2% smaller |
+-------+---------+---------+--------------------------+
| read | 3.22 ms | 3.44 ms | 6.8% slower |
+-------+---------+---------+--------------------------+
small_file.ipynb
import os, sys
import pyarrow
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
iris = load_iris()
df = pd.DataFrame(
data= np.c_[iris['data'], iris['target']],
columns= iris['feature_names'] + ['target']
)
# ========= WRITE =========
%timeit df.to_parquet(path='iris.parquet.snappy', compression='snappy', engine='pyarrow', index=True)
# 1.56 ms
%timeit df.to_parquet(path='iris.parquet.gzip', compression='snappy', engine='pyarrow', index=True)
# 2.09 ms
# ========= SIZE =========
os.stat('iris.parquet.snappy').st_size
# 6990
os.stat('iris.parquet.gzip').st_size
# 6647
# ========= READ =========
%timeit pd.read_parquet(path='iris.parquet.snappy', engine='pyarrow')
# 3.22 ms
%timeit pd.read_parquet(path='iris.parquet.gzip', engine='pyarrow')
# 3.44 ms
large_file.ipynb
import os, sys
import pyarrow
import pandas as pd
df = pd.read_csv('file.csv')
# ========= WRITE =========
%timeit df.to_parquet(path='file.parquet.snappy', compression='snappy', engine='pyarrow', index=True)
# 1.62 s
%timeit df.to_parquet(path='file.parquet.gzip', compression='gzip', engine='pyarrow', index=True)
# 7.65 s
# ========= SIZE =========
os.stat('file.parquet.snappy').st_size
# 35484122
os.stat('file.parquet.gzip').st_size
# 17269656
# ========= READ =========
%timeit pd.read_parquet(path='file.parquet.snappy', engine='pyarrow')
# 973 ms
%timeit pd.read_parquet(path='file.parquet.gzip', engine='pyarrow')
# 1.14 s
我正在尝试使用 Spark SQL 编写 parquet
文件。
默认情况下,Spark SQL 支持 gzip
,但它也支持其他压缩格式,如 snappy
和 lzo
。
这些压缩格式有什么区别?
只需在您的数据上试用它们即可。
lzo 和 snappy 是快速压缩器和非常快的解压缩器,但压缩率较低,与 gzip 相比压缩效果更好,但速度稍慢。
如果您可以处理更高的磁盘使用率以获得性能优势(更低的 CPU + Splittable),请使用 Snappy。
当 Spark 默认从 GZIP 切换到 Snappy 时,原因如下:
Based on our tests, gzip decompression is very slow (< 100MB/s), making queries decompression bound. Snappy can decompress at ~ 500MB/s on a single core.
活泼:
- 存储空间Space:高
- CPU 用法:低
- 可拆分:是 (1)
GZIP:
- 存储空间Space:中等
- CPU 用法:中
- 可拆分:否
1) http://boristyukin.com/is-snappy-compressed-parquet-file-splittable/
我同意第一个答案(@Mark Adler) 并有一些研究信息[1],但我不同意第二个答案(@Garren S)[2]。也许加伦误解了这个问题,因为: [2] Parquet 可与所有支持的编解码器拆分:Is gzipped Parquet file splittable in HDFS for Spark?,Tom White 的 Hadoop:权威指南,第 4 版,第 5 章:Hadoop I/O,第 106 页。 [1] 我的研究: 源数据 - 205 GB。文本(分隔字段),未压缩。 输出数据:
<!DOCTYPE html>
<html>
<head>
<style>
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
</style>
</head>
<body>
<table style="width:100%">
<tr>
<th></th>
<th>time of computing, hours</th>
<th>volume, GB</th>
</tr>
<tr>
<td>ORC with default codec</td>
<td>3-3,5</td>
<td>12.3</td>
</tr>
<tr>
<td>Parquet with GZIP</td>
<td>3,5-3,7</td>
<td>12.9</td>
</tr>
<tr>
<td>Parquet with SNAPPY</td>
<td>2,5-3,0</td>
<td>60.4</td>
</tr>
</table>
</body>
</html>
在由 2 m4.16xlarge 组成的 EMR 上使用 Hive 执行转换。 转换 - select 所有字段按多个字段排序。 当然,这项研究并不标准,但至少有一点显示了真实的比较。与其他数据集和计算结果可能不同。
压缩比: GZIP 压缩比 Snappy 或 LZO 使用更多 CPU 资源,但提供更高的压缩率。
一般用法: GZip 通常是 冷 数据的不错选择,这些数据很少被访问。 对于经常访问的 hot 数据,Snappy 或 LZO 是更好的选择。
Snappy 的性能通常优于 LZO。值得进行 运行 测试,看看您是否发现显着差异。
可拆分性: 如果你需要你的压缩数据是可拆分的,BZip2、LZO 和 Snappy 格式是可拆分的,但 GZip 不是。
与 Snappy 相比,GZIP 压缩数据多 30%,与使用 Snappy 数据相比,读取 GZIP 数据时 CPU 多 2 倍。
LZO 专注于低 CPU 使用率下的解压缩速度和更高的压缩率,但代价是更多 CPU。
对于更长的term/static存储,GZip压缩还是比较好。
根据下面的数据,我认为 gzip
在流媒体等场景之外获胜,其中 write-time 延迟很重要。
请务必牢记,速度本质上就是计算成本。但是,云计算是一项 one-time 成本,而云存储是一项经常性成本。取舍取决于数据的保留期限。
让我们在 Python.
中测试大小parquet
文件的速度和大小
结果(大文件,117 MB):
+----------+----------+--------------------------+
| snappy | gzip | snappy/gzip |
+-------+----------+----------+--------------------------+
| write | 1.62 ms | 7.65 ms | 4.7x faster |
+-------+----------+----------+--------------------------+
| size | 35484122 | 17269656 | 2x larger |
+-------+----------+----------+--------------------------+
| read | 973 ms | 1140 ms | 1.2x faster |
+-------+----------+----------+--------------------------+
结果(小文件,4 KB,Iris 数据集):
+---------+---------+--------------------------+
| snappy | gzip | snapp/gzip |
+-------+---------+---------+--------------------------+
| write | 1.56 ms | 2.09 ms | 1.3x faster |
+-------+---------+---------+--------------------------+
| size | 6990 | 6647 | 5.2% smaller |
+-------+---------+---------+--------------------------+
| read | 3.22 ms | 3.44 ms | 6.8% slower |
+-------+---------+---------+--------------------------+
small_file.ipynb
import os, sys
import pyarrow
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
iris = load_iris()
df = pd.DataFrame(
data= np.c_[iris['data'], iris['target']],
columns= iris['feature_names'] + ['target']
)
# ========= WRITE =========
%timeit df.to_parquet(path='iris.parquet.snappy', compression='snappy', engine='pyarrow', index=True)
# 1.56 ms
%timeit df.to_parquet(path='iris.parquet.gzip', compression='snappy', engine='pyarrow', index=True)
# 2.09 ms
# ========= SIZE =========
os.stat('iris.parquet.snappy').st_size
# 6990
os.stat('iris.parquet.gzip').st_size
# 6647
# ========= READ =========
%timeit pd.read_parquet(path='iris.parquet.snappy', engine='pyarrow')
# 3.22 ms
%timeit pd.read_parquet(path='iris.parquet.gzip', engine='pyarrow')
# 3.44 ms
large_file.ipynb
import os, sys
import pyarrow
import pandas as pd
df = pd.read_csv('file.csv')
# ========= WRITE =========
%timeit df.to_parquet(path='file.parquet.snappy', compression='snappy', engine='pyarrow', index=True)
# 1.62 s
%timeit df.to_parquet(path='file.parquet.gzip', compression='gzip', engine='pyarrow', index=True)
# 7.65 s
# ========= SIZE =========
os.stat('file.parquet.snappy').st_size
# 35484122
os.stat('file.parquet.gzip').st_size
# 17269656
# ========= READ =========
%timeit pd.read_parquet(path='file.parquet.snappy', engine='pyarrow')
# 973 ms
%timeit pd.read_parquet(path='file.parquet.gzip', engine='pyarrow')
# 1.14 s