こんにちは。Sansanのサーバサイドエンジニアの荒川です。今回はSansanのアプリに導入されてるフィード機能について、特に中心でもあるDynamoDBについてアーキテクチャを交えながら技術的側面を解説していこうと思います。
Sansanアプリにおけるフィードとは?
登録した名刺に関する人事異動やその会社のニュースなどが流れる機能です。営業先や取引先のニュースが受動的に流れるため、ご活用いただいているユーザも多いかと思います。「隣の部署のAさんの名刺交換した人、面識あるぞ」「数年前お会いしたBさんが部長に昇進されたんだ」とビジネスレベルでの気づきを与えてくれます。
少々イメージしにくいかもしれませんが、SNSでのニュースフィードをイメージしていただくと良いかもしれません。
※2019年05月09日時点での機能のため、今後は機能の改修が入る可能性があります
フィードの全体像
以下がフィード機能のアーキテクチャ図になっています。詳細は割愛しますが、バッチサーバと記述している部分がありますが、実際は内製のメッセージング機構を利用しています。その他にも冗長化されたりしていますが、本題と逸れるので簡略化しています。
- PostgreSQLに格納されたイベント情報をもとに定期的にフィードが作成され、作成したフィードはDynamoDBに格納される
- DynamoDBに格納されたフィードを、別のバッチからAWSのSNSを介してモバイルへプッシュ通知を送る *1
- (リクエストがあれば)APIサーバはDynamoDBとPostgreSQLから返却するデータを作成してレスポンスを返却する
ご覧の通りフィード機能では一部データをAWS上のDynamoDBに保管しています。フィード作成にあたっては、発生した名刺交換のイベント、ニュースソースなどから取得したデータを紐づけます。そして一日に2回(平日の朝と夕方)バッチが起動して作成されたフィードのプッシュ通知を送ります。
さて、フィードを支える技術としてDynamoDBが中心となっていることがお分かりになると思います。 前提の説明はここまでにして、以後はDynamoDBの説明とフィード機能における選定理由を解説します。
DynamoDBについて
AWSのフルマネージドのNoSQLサービスです。特徴としては、NoSQLながらデータのスケールを気にする必要がほとんどないことが挙げられます。データの容量や読み込み/書き込みに(課金💰の壁を除けば!)制限がないため、サービスの規模に応じたパフォーマンスが出てくれます。AWSの公式サイトの説明を引用すると、以下の説明があります。
Amazon DynamoDB は、key-value およびドキュメントデータモデルをサポートする NoSQL データベースで、開発者は、数ペタバイトのデータや、1 秒あたり数千万の読み込みおよび書き込みリクエストをサポートするために、小規模からグローバルまで開始できる最新のサーバーレスアプリケーションを構築できます。DynamoDB は、高性能でインターネット規模のアプリケーションを実行するように設計されており、従来のリレーショナルデータベースに負荷がかかる場合があります。
DynamoDBの選定理由
ストレージ容量の限界が実質存在しない
フィードという機能の性質上、大量のデータが生成され日時で累積していきます。ユーザごとに作成されるため蓄積するデータ量は軽視できません。 DynamoDBでは実質データサイズに制限はありませんし、何よりメインのDBであるPostgreSQLに対して容量の心配をする必要がないのは、大きなメリットです。将来的にユーザ数が急増したときにもデータ量の心配をせず、かつ高いパフォーマンスを維持できます。
負荷軽減ができる
フィード作成バッチは、高頻度で実行されるバッチであること、さらに大量のデータを生成することから、バッチを動かしている間(フィードを作成している間)に負荷が高めになります。特にオンタイムにおいては、メインのDBであるPostgreSQLになるべく負荷をかけたくありません。そこでDynamoDBへの書き込みをすることで、PostgreSQLへの書き込みが抑えられるため、負荷軽減につながります。
データストアをDynamoDBとすることで、バッチによるデータベースへの書き込み負荷のほかにも、プッシュ通知を飛ばしたことによるリクエスト数の急増による読み込み負荷などを軽減できるのは強みです。
フルマネージドであること
やはりフルマネージドサービスのため、自動でスケーリング・レプリケーションされるのは強いメリットです。 課金対象となる以上はサイジングをする必要は当然ありますが、それでも考慮するべき点が比較的少なくなります。 運用面については後述しますが、Cloudwatchを利用した監視ができるのも非常に助かっています。
DynamoDBを選択する際に考慮すべきこと
検索やカウントが不得手
DynamoDB(というよりもNoSQL)は、検索に関しては不得手だと言わざるを得ません。さらにカウントなど集計が苦手だったりもします。 そもそもNoSQLはRDBMSとは異なり、結果整合性という概念で一貫性を担保します。そのためスケールはさせやすい構造ですが、クエリを介した検索・集計は苦手です。
そこでSansanではこれらの類のデータはDynamoDBではなくPostgreSQLを参照することにして、いわゆる「共存」をさせています。 共存することで実装面などが多少厄介になるのですが、データ容量の問題などと勘案したうえでDynamoDBを使うメリットが上回った形です。
課金体系の理解
DynamoDBの課金体系は読み込みキャパシティ(RCU)、書き込みキャパシティ(WCU)といった聞きなれない概念での請求が中心になります。 単純に利用したストレージ容量ではないため、Dynamoに投げるリクエストの構造によっても課金される額が左右されます。詳細な体系は変化する可能性も高いのでここでは詳しくは書きませんが、しっかりと公式ドキュメントを読み込んで設計をするようにしましょう。
フィード機能の運用面について
日時で朝方と夕方にフィードのプッシュ通知を行うため、読み込みキャパシティー(RCU)がその時間帯に集中します。 そのため、その時間帯ではRCUを部分的に上げることで対応しています。
ときにはキャパシティを一時超えてしまうこともありますが、超えた際はSlackチャンネルにアラートを飛ばすようにしています。 そして一時的なデータの流入でなければキャパシティに伴って調整を行います。
上記のようにCloudWatchを利用した可視化・監視が容易に行えるのも非常にありがたいです。
まとめ
Sansanのフィード機能についてアーキテクチャを説明しましたが、いかがだったでしょうか。 SansanがDynamoDBをどのように活用しているかが少しでも伝わればと思います。
今回はDynamoDBの説明を中心に解説しましたが、RDBMSにおけるベストプラクティスが、DynamoDB(NoSQL)ではアンチパターンとなる場合があります。 例えば、複数のテーブルを正規化してスキーマ設計をしますが、DynamoDBでは1テーブルに収まる程度が良いとされています。
互いの性質を正しく理解したうえで、サービスにあったデータベースを選択しましょう!
*1:一日に2回実行され、CloudWatchがトリガーになっています