のぴぴのメモ

自分用のLinuxとかの技術メモ

S3クロスリージョンレプリケーションのレプリ時間を計測してみた

はじめに

あるシステムで東京リージョンとシンガポールリージョンで、S3のクロスリージョンレプリケーション構成を組んだディザスターリカバリーを検討しているのですが、DR計画のRPOの話の延長でレプリケーションの遅延時間てどれぐらいなんだろうねぇ〜という話があって、そんなにかからないだろうなという感覚はありつつ、確認したことがなかったので試しに測定してみました。

検証結果

(1)オブジェクトサイズとレプリケーション時間の関係

f:id:nopipi:20181112234614p:plain

  • オブジェクトサイズとレプリケーションの転送時間は比例関係であることを確認(リージョン間のネットワーク帯域に依存するということですね。当然ですが)
  • 1GBのオブジェクトで20秒〜1分程度、10GBのオブジェクトで3〜4分、80GBのオブジェクトになると15〜30分程度
(2)測定結果から見えるインスタンスからのPUTとレプリケーションの挙動

測定結果を見ると、インスタンスのPUT完了時間と、レプリケーションの状態がPENDINGになるのがほぼ同時刻になっていました。そのことから、インスタンスからS3バケットへのPUT処理が完了し、バケット上で新しいオブジェクトにアクセスできるようになったタイミングからレプリケーション処理が始まっているように見えます。

f:id:nopipi:20181112235946p:plain:w500

構成概要

検証構成は以下の通りです。(新しいシンプルアイコンで書いてみました)

f:id:nopipi:20181112223110p:plain:w450

検証手順

VPCに作成したインスタンスから検証用のファイルをS3バケットにPUTします。クロスリージョンレプリケーションの転送処理は、オブジェクトのレプリケーション状態をチェックしてPENDIG状態になっていた時間を測定し、その時間をレプリケーションの転送時間と皆しています。

(1)S3クロスリージョンレプリケーションの設定

下記のドキュメントなどを参考にS3バケット作成&バージョニング有効化と、クロスリージョンレプリケーションの設定をします。下記の手順ではIAMロールを手動作成するようになっていますが、マネージメントコンソールで設定する場合、IAMロース選択で「Create new role」を選ぶと必要なIAMロールを自動作成してくれます。

(2)インスタンスの準備

(a)インスタンスの選択

今回はインスタンスのネットワーク帯域やディスクIOネックならないようにするため、m5d.24xlargeを選択しています。

  • m5d.24xlargeの特徴
    • ネットワーク帯域: 25Gbps*1
    • ディスク:SSD インスタンスストアボリュームによる高IO性能

またcrr-source-bucket-xxバケットへのフルアクセスを行うIAMロールをこのインスタンスに付与しています。

(b)jqのインストール

jqをインストールします。(検証用ツール(シェルスクリプト)の中でjq コマンドを使っているので)

sudo yum -y install jq
(c)作業用インスタンスストアボリュームのフォーマット

インスタンスストアボリュームはインスタンス起動時に初期化しなければならないため、初期化します。

sudo mkfs -t xfs /dev/nvme1n1
mkdir a
sudo mount /dev/nvme1n1 ./a
sudo chown -R ec2-user:ec2-user a

(3)検証用ダミーファイル(S3へのPut用)の準備

10MBから2倍づつサイズを増やし80GBまでのS3へのPut用ファイルを作成します。ファイルはOSやVP内部の何らかの圧縮処理による影響(があった場合)を排除するために、urandomデバイスかの乱数データから作成しています。(乱数は情報のエントロピーが高く圧縮率が低くなるため、圧縮効果を極力排除することができます。逆にゼロが連続するようなデータは情報エントロピーが低くく圧縮効率が高いため、検証結果に圧縮効果の影響が出る可能性が高くなります)

cd a && mkdir data && cd data
nohup dd if=/dev/urandom  of=test_data-10M bs=1048576 count=10 &
nohup dd if=/dev/urandom  of=test_data-20M bs=1048576 count=20 &
nohup dd if=/dev/urandom  of=test_data-40M bs=1048576 count=40 &
nohup dd if=/dev/urandom  of=test_data-80M bs=1048576 count=80 &
nohup dd if=/dev/urandom  of=test_data-160M bs=1048576 count=160 &
nohup dd if=/dev/urandom  of=test_data-320M bs=1048576 count=320 &
nohup dd if=/dev/urandom  of=test_data-640M bs=1048576 count=640 &
nohup dd if=/dev/urandom  of=test_data-1.3G bs=1048576 count=1280 &
nohup dd if=/dev/urandom  of=test_data-2.5G bs=1048576 count=2560 &
nohup dd if=/dev/urandom  of=test_data-5G bs=1048576 count=5120 &
nohup dd if=/dev/urandom  of=test_data-10G bs=1048576 count=10240 &
nohup dd if=/dev/urandom  of=test_data-20G bs=1048576 count=20480 &
nohup dd if=/dev/urandom  of=test_data-40G bs=1048576 count=40960 &
nohup dd if=/dev/urandom  of=test_data-80G bs=1048576 count=81920 &
cd ..

(4)検証用スクリプトの準備

下記のスクリプトを "a"フォルダに格納し、実行権限を付与(chmod +x *.sh)します

(a)検証用コード
  • test.sh
#!/bin/sh

DATADIR="./data"
LOGGINGSH="./logging.sh"
SRCBUCKET="crr-source-bucket-xx"
SRCBUCKETURI="s3://${SRCBUCKET}"


for t in $(seq 1 10)
do
    for size in 10M 20M 40M 80M 160M 320M 640M 1.3G 2.5G 5G 10G 20G 40G 80G
    #for size in 10M 20M
    do
        TFILE="test_data-${size}-${t}"
        REPLILOG="replicate-${TFILE}.log"
        PUTLOG="put-${TFILE}.log"
        nohup ${LOGGINGSH} ${SRCBUCKET} ${TFILE} > replicate-${TFILE}.log &

        # put object
        date > ${PUTLOG}
        echo aws s3 cp "${DATADIR}/test_data-${size}" ${SRCBUCKETURI}/${TFILE}
        echo aws s3 cp "${DATADIR}/test_data-${size}" ${SRCBUCKETURI}/${TFILE} >> ${PUTLOG}
        aws s3 cp "${DATADIR}/test_data-${size}" ${SRCBUCKETURI}/${TFILE} 
        date >> ${PUTLOG}
    done
done
(b)検証コードから呼び出されるレプリケーション状態をロギングするコード
  • logging.sh
#!/bin/sh

bucket=$1
file=$2
stat=NULL

while true;
do
    A=$(date); 
    B=$(aws s3api head-object --bucket ${bucket} --key ${file} |jq '.ReplicationStatus')
    if [ "A${stat}" = "ANULL" -a "A${B}" = "A\"PENDING\"" ]; then stat="PENDING";fi

    echo ${A} ${B} ${file}

    if [ "A${stat}" = "APENDING" -a "A${B}" = "A\"COMPLETED\"" ]; then break; fi
done
(c)検証事前準備
  • put_zerofiles.sh
#!/bin/sh

DATADIR="./data"
LOGGINGSH="./logging.sh"
SRCBUCKET="s3://crr-source-bucket-xx"
ZEROFILE="dummy.dat"

touch dummy.dat

for t in $(seq 1 10)
do
    for size in 10M 20M 40M 80M 160M 320M 640M 1.3G 2.5G 5G 10G 20G 40G 80G
    do
        TFILE="test_data-${size}-${t}"
        REPLILOG="replicate-${TFILE}.log"
        PUTLOG="put-${TFILE}.log"

        # put object
        aws s3 cp ${ZEROFILE} ${SRCBUCKET}/${TFILE} 
        date >> ${PUTLOG}
    done
done

(5)ファイルの設置

測定の関係で同名称のファイルをcrr-source-bucket-xxバケットに事前配置します。

./put_zerofiles.sh

(6)測定

測定します。2〜3時間がかかるので寝かせておきます。

nohup ./test.sh

(7)結果の集計

測定が終わったら、下記の分析シェルで実行ログを分析します。

(a) インスタンスからS3へのオブジェクトput時間の分析シェル
  • analysis1.sh
#!/bin/sh

for size in 10M 20M 40M 80M 160M 320M 640M 1.3G 2.5G 5G 10G 20G 40G 80G
#for size in 10M 20M
do
    for t in $(seq 1 10)
    do
        TFILE="test_data-${size}-${t}"
        REPLILOG="replicate-${TFILE}.log"
        PUTLOG="put-${TFILE}.log"

        S=$(head -1 ${PUTLOG})
        E=$(tail -1 ${PUTLOG}) 
        echo "${TFILE}, $S, $E"
    done
done
(b) レプリケーションPENDIG時間の分析
  • analysis2.sh
#!/bin/sh

for size in 10M 20M 40M 80M 160M 320M 640M 1.3G 2.5G 5G 10G 20G 40G 80G
#for size in 10M 20M
do
    for t in $(seq 1 10)
    do
        TFILE="test_data-${size}-${t}"
        REPLILOG="replicate-${TFILE}.log"
        PUTLOG="put-${TFILE}.log"

        grep PENDING $REPLILOG > /tmp/xxx
        S=$(head -1 /tmp/xxx)
        E=$(tail -1 /tmp/xxx) 
        echo "${TFILE}, $S, $E"

    done
done