Database JUNKY

MySQL,MariaDBを中心としたブログです

AWS S3のデータをリージョン間転送する方法

世界中で利用される画像/動画アプリにて、日本リージョンのS3から画像/動画を参照しているが、アメリカからのアクセスが異様に遅いという話があり。いろいろ調べてCDNを高速化した内容をここに書いていきたいと思います

f:id:hit10231023:20180309123622p:plain

なんで遅いの?

ふつうに考えれば、アメリカから、日本にアクセスしてデータを取得するんだから、そりゃ遅いです汗 ちなみに、日本リージョンにあるS3ファイルを日本とアメリカから取得した場合、これくらい差があります。 公平性を出すため、AWSのEC2からアクセスしているわけではなく、conohaのVPSから計測しております。 計測は簡易的ではありますが、wgetを利用して78MBくらいのファイルを取得して時間を計測しております

結果はどうだったでしょうか?

日本からのアクセス

# wget -O /dev/null --no-proxy https://s3-ap-northeast-1.amazonaws.com/xxxxxx/yyyyyyy/test_video.mp4.mp4 > /dev/null            

100%[=================================>] 81,999,254  21.6M/s   in 3.6s    

2017-01-11 08:42:15 (21.6 MB/s) - "/dev/null" saved [81999254/81999254]

アメリカからアクセス

# wget -O /dev/null --no-proxy https://s3-ap-northeast-1.amazonaws.com/xxxxxx/yyyyyyy/test_video.mp4.mp4 > /dev/null


100%[=================================>] 81,999,254  13.2M/s   in 10s     

2017-01-11 00:42:04 (7.76 MB/s) - "/dev/null" saved [81999254/81999254]

驚きなのかな?普通なのかもしれませんが、おおよそアメリカから日本のS3にアクセスする転送量は、日本から日本のS3にアクセスする転送量の3分の1になります。時間的にも、日本からのアクセスより3倍時間かかっていますよね、そりゃ遅いわ。。

ここから考えられるものは一つで、じゃあ、海外にもバケットを作ろうって話になりますよね

が、しかし。日本のs3バケットと、アメリカのs3バケットは同期してくれるのってあたりが課題になってきます

いまさらだけど、S3はレプリケーションができる!?

クロスリージョンレプリケーションという機能があり、MySQLレプリケーションを想像してもらえばわかるかと思うのですが、リージョン間のバケットを非同期でレプリケーションしてくれる機能です。これはすごい

詳細は、こちらを確認してください

docs.aws.amazon.com

設定手順

f:id:hit10231023:20170111182921j:plain

jpバケットのプロパティから、クロスリージョンレプリケーションを選択します

f:id:hit10231023:20170111185619j:plain

  • バージョニングの有効化をクリックします

f:id:hit10231023:20170111185705j:plain

f:id:hit10231023:20170111195632j:plain

f:id:hit10231023:20170111185931j:plain

  • 結果、以下のような状態になりました

f:id:hit10231023:20170111190022j:plain

  • これでリージョンの異なるバケットが作成できたのが確認できたかと思います

f:id:hit10231023:20170111183555j:plain

以上でレプリケーションの設定は完了ですが、一転注意があります。

レプリケーションソース内にある既存のオブジェクトに関しては、レプリケーションはされません。レプリケーション設定後のオブジェクトのみが同期されます!

なので、既存のオブジェクトに関してはあらかじめ、コピーしておきましょう。コピーペーストに関しては、s3の管理コンソールから行うことができます。

オブジェクトがものすごい数でものすごいでかい場合は、ブラウザのセッションが切れて失敗する可能性が高いので

コンソールでやるのが無難だと思います、以下ディレクトリコピーの一例ですが、再帰的な取り込みをする--recursiveオプションを入れております

  • リージョン間コピーをコマンドで実施
aws s3 cp s3://backet-jp-qazwsx s3://backet-us-qazwsx --recursive
  • こんな方法もあります(同期)
aws s3 sync s3://backet-jp-qazwsx s3://backet-us-qazwsx

f:id:hit10231023:20170112122102j:plain

設定後、パフォーマンス測定

では設定後、どのようにパフォーマンスが変わったでしょうか?

アメリカからアメリカのS3にアクセス

wget -O /dev/null --no-proxy https://s3.amazonaws.com/xxxxxx/yyyyy/test_video.mp4.mp4 > /dev/null

100%[========================================================================>] 81,999,254  21.8M/s   in 4.4s

それと比較して

アメリカから日本のS3にアクセス

wget -O /dev/null --no-proxy https://s3-ap-northeast-1.amazonaws.com/xxxxxx/yyyyy/test_video.mp4.mp4 > /dev/null


100%[========================================================================>] 81,999,254  10.1M/s   in 15s

どうでしょうか?一目瞭然ですよね?

つまり、リクエスト元の国と同じリージョンにs3バケットがあるとこんなに速度の差が出るのです!!

余談ですがnginx の設定例

たとえばですが、上記をnginxでリバースプロキシしちゃおうと考えた場合、以下のような設定になるかな?と思います

    location / {

        root   /xxxx/yyyyyy;

        rewrite ^/yyyyyyy/(.*)$  /yyyyyyy-us/$1 break;

        if ($request_uri ~* "server-status") {
           access_log  off;
        }

        index  index.html index.htm;
        limit_rate_after 3m;
        limit_rate 2m;

        try_files $uri $uri/ @s3 @s3jp;
    }

    location @s3 {
        resolver        8.8.8.8; # OpenDNS
        resolver_timeout 5s;
        proxy_pass https://s3.amazonaws.com:443;
    }

    location @s3jp {
        resolver        8.8.8.8; # OpenDNS
        resolver_timeout 5s;
        rewrite ^/yyyyyyy-us/(.*)$  /yyyyyyy/$1 break;
        proxy_pass https://s3-ap-northeast-1.amazonaws.com:443;
    }

try_files

上記で、nginxで設定できるtry_filesを利用しております。何をしているかというと

try_files $uri $uri/ @s3 @s3jp;
  • ローカルにデータがない場合、@s3 に飛ぶ(USリージョンのs3にリバースプロキシ)
  • USリージョンにもデータがない場合は、@s3jpに飛ぶ(JPリージョンのS3にリバースプロキシ)

このような設定をすることで、タイミングで、jp s3にあるか? us s3にあるか特に気にせずデータを取得することができますよね??ね!???