この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
当エントリは先日投稿したシリーズ『『Amazon Redshiftのパフォーマンスチューニングテクニック Top 10』手順実践』の第9弾です。課題#9の『非効率的なデータロード』について内容を見て行きたいと思います。
データをS3から取り込む際にはCOPYコマンドで所定のファイル、もしくは所定のバケット・フォルダ配下のファイル一式を所定のテーブルに取り込みます。その際に推奨されている手順としては以下のものがある、とエントリでは紹介されています。
- ファイルは圧縮しておく事
- ファイルは分割しておく事(ノード構成からなるスライス数の倍数になるようなファイル数に分割)
手順実践
投入対象のテーブルは下記public.customerを利用します。これはRedshiftのチュートリアルで活用されているものです。
CREATE TABLE public.customer (
c_custkey integer not null sortkey,
c_name varchar(25) not null,
c_address varchar(25) not null,
c_city varchar(10) not null,
c_nation varchar(15) not null,
c_region varchar(12) not null,
c_phone varchar(15) not null,
c_mktsegment varchar(10) not null)
diststyle all;
CREATE
初期投入データもこのチュートリアルから投入。
COPY public.customer FROM 's3://awssampledbuswest2/ssbgz/customer'
CREDENTIALS 'aws_access_key_id=XXXXXXXXXX;aws_secret_access_key=YYYYYYYYYY'
GZIP REGION 'us-west-2';
この投入済みデータを所定のバケットに吐き出したものを使いたいと思います。
# UNLOAD ('SELECT c_custkey,c_name,c_address,c_city,c_nation,c_region,c_phone,c_mktsegment FROM public.customer ORDER BY c_custkey')
TO 's3://xxxxxxx-xxxx-xxxxxx/customer/single-files/redshift-customer'
CREDENTIALS 'aws_access_key_id=XXXXXXXXXX;aws_secret_access_key=YYYYYYYYYY'
PARALLEL OFF;
上記内容のファイルは単一ファイルとして出力させたものです。
$ aws s3 ls 's3://xxxxxxx-xxxx-xxxxxx/customer/single-files/'
2016-09-20 21:11:18 0
2016-09-20 21:12:17 286529327 redshift-customer000
件数はちょうど300万件、中身はこのような形になっています。パイプ区切りのデータです。
$ mv redshift-customer000 redshift-customer.csv
$ wc redshift-customer.csv
3000000 7294613 286529327 redshift-customer.csv
$
$ vi redshift-customer.csv
1|Customer#000000001|IVhzIApeRb|MOROCCO 0|MOROCCO|AFRICA|25-989-741-2988|BUILDING
2|Customer#000000002|XSTf4,NCwDVaWNe6tE|JORDAN 1|JORDAN|MIDDLE EAST|23-768-687-3665|AUTOMOBILE
3|Customer#000000003|MG9kdTD|ARGENTINA7|ARGENTINA|AMERICA|11-719-748-3364|AUTOMOBILE
4|Customer#000000004|XxVSJsL|EGYPT 4|EGYPT|MIDDLE EAST|14-128-190-5944|MACHINERY
5|Customer#000000005|KvpyuHCplrB84WgAi|CANADA 5|CANADA|AMERICA|13-750-942-6364|HOUSEHOLD
6|Customer#000000006|sKZz0CsnMD7mp4Xd0YrBvx|SAUDI ARA2|SAUDI ARABIA|MIDDLE EAST|30-114-968-4951|AUTOMOBILE
7|Customer#000000007|TcGe5gaZNgVePxU5kR|CHINA 0|CHINA|ASIA|28-190-982-9759|AUTOMOBILE
8|Customer#000000008|I0B10bB0AymmC, 0PrRYBC|PERU 6|PERU|AMERICA|27-147-574-9335|BUILDING
9|Customer#000000009|xKiAFTjUsCuxfele|INDIA 6|INDIA|ASIA|18-338-906-3675|FURNITURE
10|Customer#000000010|6LrEaV6KR6PLVcgl2ArL |ETHIOPIA 9|ETHIOPIA|AFRICA|15-741-346-9870|HOUSEHOLD
S3ファイルのCOPY処理検証:単一ファイルの場合
まずは単一ファイルの場合、どれ位時間が掛かるか試してみる事にしましょう。
上記アップロード済の単一ファイルCOPY処理で取り込みます。
COPY public.customer
FROM 's3://xxxxxxx-xxxx-xxxxxx/customer/single-files/'
CREDENTIALS 'aws_access_key_id=XXXXXXXXXX;aws_secret_access_key=YYYYYYYYYY'
CSV DELIMITER AS '|';
都合5回実行してみましたが、およそ20秒近く掛かっていました。ちなみに今回検証に使っているRedshiftクラスタはdc1.large 2ノードと小さめのクラスタです。
# COPY
Time: 20315.496 ms
# TRUNCATE public.customer;
Time: 501.731 ms
# COPY
Time: 19349.804 ms
# TRUNCATE TABLE and COMMIT TRANSACTION
Time: 625.727 ms
# COPY
Time: 19449.845 ms
# TRUNCATE TABLE and COMMIT TRANSACTION
Time: 490.240 ms
# COPY
Time: 19502.525 ms
# TRUNCATE TABLE and COMMIT TRANSACTION
Time: 542.797 ms
# COPY
Time: 19785.045 ms
#
S3ファイルのCOPY処理検証:ファイルを分割した場合
次いで、ファイルを複数個に分割した時の挙動を確認してみたいと思います。
AWSブログの過去エントリにちょうど良さげな『ファイル分割』のサンプルがありましたのでこれを使ってみたいと思います。splitコマンドを使って所定のファイル数ぶん、単一ファイルを分割するというものです。
- Best Practices for Micro-Batch Loading on Amazon Redshift - AWS Big Data Blog
- split コマンド | コマンドの使い方(Linux) | hydroculのメモ
AWSのドキュメントでは、クラスタが備えるスライス数の倍数にファイルを分割すると効率良くロードが出来る、との記述があります。
ノードはいずれも並列クエリ実行に関与し、スライス間でできるだけ均等に分散されたデータを処理します。クラスターに DS1.XL ノードが 2 つある場合、データを 4 つのファイルまたは 4 の倍数のファイルに分割します。Amazon Redshift はワークロードを分割するときにファイルサイズを考慮しません。そのため、ファイルを概ね同じサイズにし、それぞれが圧縮後に 1 MB ~ 1 GB になるようにする必要があります。
上記エントリには以下のような記述でsplitコマンドを実行していましたので、
$ split -l `wc -l bigfile.txt | awk '{print $1/32}'` -v bigfile.txt “part-“
手元の環境ではこの様に実行してみました。(Mac上での実行だったので-dオプション(suffixに数字を付ける)が使えなかった)
$ split -l `wc -l redshift-customer.csv | awk '{print $1/8}'` redshift-customer.csv redshift-customer_
分割出来たファイルを所定のS3バケットにアップしたのが以下。
aws s3 ls 's3://xxxxxxx-xxxx-xxxxxx/customer/multiple-files/'
2016-09-20 21:39:53 0
2016-09-20 21:40:10 35474029 redshift-customer_aa
2016-09-20 21:40:23 35580389 redshift-customer_ab
2016-09-20 21:40:41 35705628 redshift-customer_ac
2016-09-20 21:40:55 35950227 redshift-customer_ad
2016-09-20 21:41:21 35955098 redshift-customer_ae
2016-09-20 21:42:29 35950292 redshift-customer_af
2016-09-20 21:42:47 35954634 redshift-customer_ag
2016-09-20 21:43:02 35959030 redshift-customer_ah
この形で単一ファイル同様にCOPY処理を実行してみます。
COPY public.customer
FROM 's3://xxxxxxx-xxxx-xxxxxx/customer/multiple-files/'
CREDENTIALS 'aws_access_key_id=XXXXXXXXXX;aws_secret_access_key=YYYYYYYYYY'
CSV DELIMITER AS '|';
結果は以下の通り。単一ファイルの20秒に対して、複数ファイルでのCOPY処理はおよそ12秒となり、早くなっています。
INFO: Load into table 'customer' completed, 3000000 record(s) loaded successfully.
COPY
Time: 13013.339 ms
# TRUNCATE TABLE and COMMIT TRANSACTION
Time: 626.829 ms
# COPY
Time: 12738.892 ms
# TRUNCATE TABLE and COMMIT TRANSACTION
Time: 550.695 ms
# COPY
Time: 12444.918 ms
# TRUNCATE TABLE and COMMIT TRANSACTION
Time: 586.002 ms
# COPY
Time: 13029.853 ms
# TRUNCATE TABLE and COMMIT TRANSACTION
Time: 790.610 ms
# COPY
Time: 12755.876 ms
#
まとめ
以上、『Amazon Redshiftのパフォーマンスチューニングテクニック Top 10』トピック9つめ、"非効率的なデータロード"に関する対処方法のご紹介でした。ファイルのCOPY処理(ロード)に時間が掛かっているという場合、『ファイルの圧縮』及び『ファイルをスライス数の倍数に分割』して取り込む事でロード時間の短縮が図れるかと思いますので是非お試しください。次はいよいよ最終トピックです。