連載
» 2015年01月15日 16時00分 公開

大量データ処理時に知っておきたいAmazon DynamoDB活用テクニック4選大規模プッシュ通知基盤大解剖(2)(2/3 ページ)

[相野谷直樹,リクルートテクノロジーズ]

【2】「全件走査用テーブル」を用意して処理を効率化する

 プッシュ通知のために使用しているDynamoDBのテーブルは、デバイス情報テーブルとプッシュトークンテーブルの2つがあり、それぞれ次のような設計になっています。

  • デバイス情報を持つテーブル。主に次のカラムを持つ
    • デバイスID(プライマリキー):クライアントアプリが内部で払い出す端末識別用のID
    • デバイストークン:GCM/APNsへのプッシュ通知リクエスト用のトークンです
    • アプリ付加情報:クライアントアプリが独自に付与したデバイス別のメタデータを格納します
  • デバイスID逆引き用テーブル。主に次のカラムを持つ
    • デバイストークン(プライマリキー)
    • デバイスID

 テーブル設計で特徴的なのは、デバイストークンの全走査用テーブルを用意している点です。このテーブルは、アプリに登録されたデバイスを全対象とするプッシュ通知配信機能などにおいて、GCM/APNsを介したプッシュ通知に必要なデバイストークンを全デバイス分取得するために利用しています。テーブルからトークンを全て取得する際には、後述する「Scan API」を利用しています。

 Scan APIはデータサイズが大きくなるほど読み出し速度のパフォーマンスが低下するため、テーブルを分けることにより全件走査のパフォーマンスを効率化しているのです。

【3】Amazon SQSやAWS CloudWatchと連携して「スループット超過エラー」を防ぐ

 DynamoDBでは、読み書き性能をプロビジョンドスループットとして設定できるため、その設定値を大きくした分だけ高い性能を得ることができます。一方で、予測しない負荷集中が起きたときなどに読み書きの速度がプロビジョンドスループットを超える場合、DynamoDBはAPIリクエストにおいて「スループット超過エラー」を返却するようになります。エラー発生時のリクエストで行うはずだったデータの読み書きは、当然ながら実行されません。

 プッシュ通知を行うシステムの特性上、スマートデバイスからのシステムへのデバイス情報更新リクエストは、各端末へのプッシュ通知を行った直後に集中し、DynamoDBのデバイス情報テーブルへの負荷も急増します。このとき、負荷がスループット設定値を超えることで発生する大量のスループット超過エラーへの対策を考える上で、以下のような問題があります。

  • スパイク的に発生する消費スループットの最大値に合わせてプロビジョンドスループットを高くするのはコスト的に無駄になってしまう
  • スループット消費に合わせて動的にスループットを変更する仕組みも考えられるが、スループットを落とす設定リクエストが1日4回に制限されており、1日複数回発生する負荷のスパイクに追随しきれない

 そこでPusna-RSでは、「Amazon SQS」(以下、SQS)のメッセージキューシステムを活用し、DynamoDBへの書き込みを非同期化することでスループット超過エラーの大量発生を防いでいます。具体例として、スマートデバイスからシステムへのデバイス情報登録処理を行う“デバイス登録API”周りの構成を下に示します。

リクエスト負荷がDynamoDBのスループットを超える場合も安定稼働

 具体的な動作イメージは下のような順になります。SQSを使うことで、DynamoDBへの書き込み負荷を設定スループットに沿った形での平滑化を実現できています。

  1. スマートデバイスからのデバイス情報登録リクエストをデバイス登録APIが受信
  2. 登録APIはリクエストからDynamoDBへ書き込みたいメッセージをSQSに登録
  3. SQSに登録されたメッセージをデバイス登録Workerが取得
  4. デバイス登録Workerがテーブルの設定スループットを超えない速度でメッセージをDynamoDBに書き込み

 この構成では、スループット超過エラーによるDynamoDBへ読み書き失敗を防ぐことができますが、スループット値を超える負荷が続いた場合は、書き込みリクエストに対し処理が追いつかないのでSQSにメッセージがたまり続けてしまう状況になってしまいます。

 このように、SQSへメッセージが滞留するのを防ぐために、キューにたまったメッセージ数が一定を超えるとアラートとなる監視設定を「AWS CloudWatch」で行っています。アラートの頻度や傾向に応じてスループット値の設定を見直すことで、データ登録が遅延し過ぎることによってプッシュ通知システム全体に影響が出ることのないよう安定した運用ができています。

 前述の通り、DynamoDBでデバイス情報を登録するテーブルは、Pusna-RSを利用するクライアントアプリごとにそれぞれ存在しています。初めは複数テーブルに対し、処理用のキューは1本しか用意しておらず、サービス開始時、Pusna-RSの利用頻度がそれほど高くない時期は複数アプリテーブルに対する書き込み処理でも1つのキューで処理を十分に平滑化できていました。

 ところが、Pusna-RSの利用頻度が高くなってくると、処理が詰まってしまう問題が起き始めました。キューが1本しかないために、書き込み処理が遅延しているアプリ別情報テーブルが1つでもあると、キューに滞留したメッセージの詰まりが他のアプリ情報テーブルへの書き込み処理に波及し、雪だるま式にキューが詰まってしまうためです。

 1つのアプリへの負荷がシステム全体の処理を遅延させてしまう状況は絶対に避けなければならないので、キューをアプリケーションごとに用意するようにして、アプリ単体の負荷が局所的になるように対策しました。この教訓から言えることとして、処理時間や負荷の異なる処理は1つのメッセージキューにまとめず、複数のメッセージキューに分けるようにするのがSQSで処理を平滑化するためのコツだと思いました。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。