AWS の API を利用するときに気をつけたい 3 つのポイント
Posted on
- #aws
AWS の魅力は API を使ってインフラをコントロールできる点です。インフラだけでなく SQS や DynamoDB といったサービスも API で操作します。ほぼすべてのサービスに API が用意されているので、AWS を使いこなせば使いこなすほど API の利用頻度も上がります。
今回は AWS の API を利用するときに気をつけたいポイントをまとめてみました。
リトライ処理を入れる
AWS に限ったことではありませんが、API リクエストはさまざまな理由で一時的に失敗する可能性があります。クライアント側のネットワークエラーの可能性もありますし、大量のリクエストを送ってサーバ側でスロットリングされているかもしれません。
なので、API リクエストは 一時的な失敗を前提 にリトライ処理を入れましょう(AWS SDK を利用しているのであればリトライ処理は自動的に行われます)。一度失敗しただけで例外を投げるようなソースコードはそもそもの設計が悪いです。
AWS を使う上で Exponential backoff という考え方は非常に重要です。簡単に説明すると、失敗回数が増えるに連れてリトライするまでの待ち時間を 1, 2, 4, 8, ... と指数関数的に増やす仕組みです。ドキュメントにも記載があります。
AWS のような大規模システムでは部分的かつ一時的な障害が常に発生しているはずです。瞬間的にリクエストが集中することもあるでしょう。アプリケーションの可用性を高めるためにリトライ処理は必須です。
「一時的なエラーでも障害報告書を出せ!」という人はそもそもクラウドに向いていないので、オンプレミスで好きなようにやってください。
ネットワーク帯域を意識する
あまり知られていないような気がするのですが、EC2 インスタンスのネットワーク帯域は EBS と共有されています(EBS はネットワーク接続型のストレージ)。
わかりやすく言えば、大量の I/O リクエストが発生するとネットワーク帯域に影響が出るということです。当然ですが、不安定なネットワークでは API リクエストが失敗する可能性が上がります。
安定したネットワーク帯域を手に入れるには EBS 最適化オプションを設定します(M4, C4, D2 はデフォルトで有効。また T2 には設定できません)。このオプションを有効にすることで 通常のネットワークと I/O ネットワークが独立 します。
AWS Black Belt Tech シリーズのこのスライドがわかりやすいです。
高負荷時に API リクエストが失敗するような場合はネットワーク帯域に問題があるかもしれません。 EBS 最適化オプションを有効にして改善するか確認しましょう。
カーネルパラメータを調整する
AWS API は SDK や CLI を問わず HTTPS 通信で行われます。 TCP/IP を経由するので、高頻度に実行するときは OS のチューニングが必要です。
「DynamoDB や SQS といった API を高頻度に使うときに忘れずにセットしておきたいカーネルパラメータ」を参考に、自分でもカーネルパラメータを見直してみました。重要になってくるのは、この 4 つのカーネルパラメータです。
- net.ipv4.ip_local_port_range: ローカルポートに割り当てるポート番号の範囲。枯渇すると新規コネクションが確立できなくなる。
- net.ipv4.tcp_tw_recycle: TIME_WAIT 状態のソケットを再利用するかどうか。相手からの接続に有効。
- net.ipv4.tcp_tw_reuse: TIME_WAIT 状態のソケットを再利用するかどうか。自分からの接続に有効。
- net.ipv4.tcp_fin_timeout: ソケットを強制的にクローズする前に、最後の FIN パケットを待つ時間。 DoS 攻撃の対策に有効。
これらのパラメータを /etc/sysctl.conf
に設定して sysctl -p
で反映させます。
net.ipv4.ip_local_port_range = 10000 65535 # 10000 未満は他のアプリケーションが使うかもしれないので念のため
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30 # サーバの役割によって調整が必要
本題から逸れますが、DB サーバやログ集約サーバなど(要するに接続を受け付けるサーバ)では次のパラメータもチューニングが必要です。たとえば Fluentd でいったんログを集約して、そこから S3 や DynamoDB に送っている場合などが当てはまります。
- net.core.somaxconn: TCP ソケットが受け付けた接続要求を格納するキューの数。
- net.core.netdev_max_backlog: キューにつなぐことのできるパケットの最大数。
net.core.somaxconn = 1024
net.core.netdev_max_backlog = 1024
まとめ
AWS の API を利用するときに気をつけたいポイントは 3 つです。 API ユーザーが少し気をつけるだけでアプリケーションの可用性はぐっと上がるはずです。
- リトライ処理を入れる
- ネットワーク帯域を意識する
- カーネルパラメータを調整する
他にも気をつけるべき点があれば、ぜひ教えてください :-)