前回のファイル圧縮後に、次の 2 つの問題が発生しました。
- 一部のログはボリュームが大きく、1 日あたり 100G を超えるため、ftp を使用してローカルにデータを取得するには時間がかかりすぎるため、この方法はお勧めできません。
- Spark Streaming によりリアルタイムにログが収集されるため、データの分布が均一ではなく、大きなものは 5G、小さなものは数十 MB にすぎず、圧縮後も小さなファイルが多数存在します。 HDFS の読み取りパフォーマンスに大きな影響を与えます。
この状況に対しては、次の解決策が提供されます。
1. アーカイブ
データのこの部分を最初にアーカイブします。アーカイブすると、データ量を変更せずに多数の小さなファイルをマージできます。
元のデータがアーカイブされ
た後、
データは均等に分散されます。
2. 圧縮
データ量が大きいため、ftp 方式は推奨されないため、プログラムを使用して圧縮します。
/**
* Created by wpq on 2019/3/27.
* 压缩测试
*/
public class HdfsCompressTest {
public static void main(String[] args) throws ClassNotFoundException, IOException {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("stattime:" + df.format(new Date()));
Class<?> cal = Class.forName("org.apache.hadoop.io.compress.GzipCodec");
Configuration conf = new Configuration();
conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
FileSystem fs = FileSystem.get(conf);
CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(cal, conf);
//指定压缩和被压缩的文件
String inputfile = "/user/hdfs/rsync";
//String inputfile = "/user/hdfs/wpq/tmp";
RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path(inputfile), true);
while (files.hasNext()) {
LocatedFileStatus next = files.next();
if (next.isFile()) {
Path path = next.getPath();
if (path.toString().endsWith("gz")) {
} else {
//指定压缩输入流
FSDataInputStream in = fs.open(path);
//指定压缩输出流
String outfile = path.toString() + codec.getDefaultExtension();//添加压缩格式为后缀
FSDataOutputStream outputStream = fs.create(new Path(outfile));
CompressionOutputStream out = codec.createOutputStream(outputStream);
IOUtils.copyBytes(in, out, 4096, false);
in.close();
out.close();
fs.delete(path, true);
}
}
}
System.out.println("endtime:" + df.format(new Date()));
}
}
3. 検証
毎月 1 日と 15 日のデータ 100 個とその日のデータの合計数を抽出し、比較して OK を確認し、元のデータを削除します。