データベースにRDBを選択するときの注意事項について考える（追記あり）

2019年6月20日追記：
この度は、本ブログにて技術的に誤った記事を掲載したことをお詫び申し上げます。具体的には以下の通りです。

* 一方的にRDBがスケールしないという技術的根拠が薄い内容となっていました。
* RDBとAmazon DynamoDB（以下、DynamoDB）/NoSQLデータベースを要件に応じて適切に選択するという内容になっていませんでした。また、本来考慮すべきアプリケーションの設計やデータアクセスパターンに言及しておらず、RDBのデメリットの部分にのみ焦点を当てる内容となっていました。
* DynamoDBの具体的な活用やDynamoDBを使う上での注意点についても触れられていない不明瞭な記載でした。

当初の記事の目的としましては、特定のユースケースをサンプルとして、最適なデータベースを選択頂くことでした。近日中に正確な技術記事を掲載させて頂きます。

以下の内容は修正前の内容となります。

***

AWS社員Qiitaブログシリーズは、アマゾン ウェブ サービスジャパンで働く社員が執筆するQiitaの個人ブログ記事です。今回はSA舟崎によるデータベースにRDB(リレーショナルデータベース)を選択するときの注意事項について執筆します。

※本記事は、あくまで個人の見解に基づいて記載しております。定量的なパフォーマンス測定結果に基づいたものではありませんので、ご注意ください。


##RDB（リレーショナルデータベース）について

みなさん、RDBをご利用されていますか？

RDBは、リレーショナルデータモデルにもとづいて設計、開発されるデータベースです。そのデータ項目は列と行を持つテーブルのセットとして構成されます。AWSでもAmazon Relational Database Service(RDS) (MySQL, PostgreSQL, Oracle, Microsoft SQL Server, MariaDB)、Amazon Aurora(MySQL, PostgreSQL)などが提供されています。開発者の方で、**今までRDBのご利用経験がある方であれば、特に何も気にせずにRDBを選択される方もいるかもしれません。ですが、果たしてそれで良いのでしょうか？**今回は主にB2C系の新規システムにおいてRDBを選択する場合の注意事項の一例について考えてみます。

![RDS.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66106/49abbc5b-15d3-0f0d-cac4-a775b0bbfded.png)


##スケーリングが困難
###リリース直後は速度面で問題なかったのに・・・
今回は仮に大量のメッセージを扱うチャットシステムのデータベースにRDBを採用した例で考えてみます。そのメッセージを格納するテーブルのカラムには、例えばMESSAGE_ID, ROOM_ID (チャットルームのID), SENDER_ID（メッセージ送信者ID）,  TIMESTAMP, MESSAGE_BODYなどが考えられるでしょう。

こちらのテーブルに複数ユーザーのチャットメッセージを今回のチャット用のWebアプリケーションサーバから書き込みしていくとします。勿論扱うテーブルはこれのみならず、他にもユーザー属性情報やチャットメッセージに付加するタグ情報を管理するテーブルなどもあるかもしれません。さらには、チャットメッセージのみならず、ユーザーのアクセスログもRDBにリアルタイムで書き込むなどして、そのRDB上のユーザーアクセスログをユーザーの行動分析のために収集・集計するといったケースもあるかもしれません。**（ユーザーアクセスログデータは是非RDB以外のAmazon S3などのデータストアにまずは格納するのが良いと思います）**

これらの一連の処理は、リリースした直後では、ユーザー数が少なく、これらのテーブルへの読み書きの速度に全く問題を感じていなかったとします。ですが、水面下では次のようなスケーリングを困難にする要因が潜んでいるのに気づいていなかったかもしれません。

###リリースしてから数年が経過、データ増に伴いRDBのキャッシュにデータが載り切らずにディスクアクセスが発生して速度劣化してしまう

リリース当初はRDB上で扱うデータの量が少なかったため、キャッシュに割り当てるメモリが少なくても済んでいたかもしれません。ですが、リリースしてから数年が経過、RDB上で扱うデータの量や種類、アクセスユーザー数が増えてくると、RDBアクセス時におけるRDB内のキャッシュヒット率が下がり、その結果、ディスクアクセスが生じてしまいます。**今まではメモリ上のキャッシュにあるデータでレスポンスを返すことができていたものが、そのキャッシュにデータが載り切らずにディスクアクセスが生じた途端に、RDBのレスポンスが遅くなることが考えられます。**

このような状況を短期的に回避するのであれば、メモリの量を増加させるためにRDBのスペックを上げる、つまりスケールアップをする手法が考えられます。あるいはRDBマスターのデータを読み込み専用のリードレプリカにレプリケーションして、RDBへの読み込みをリードレプリカに向けて負荷分散、スケールアウトさせる手法もあるでしょう。いずれにしても、RDBにかかるコストは飛躍的に増加することが考えられます。

**そのようなスケールアップまたはスケールアウトを繰り返して、あるタイミングでその施策がコスト面で厳しくなったとしましょう。**そのような状況になると、どういうことが考えられるでしょうか？

* 書き込みや読み込みのレスポンス遅延による**ユーザーの満足度低下**
* 新規ユーザー数を増やすべくキャンペーンを打ちたい。けれどもで**RDBがボトルネックでキャンペーンを打つことができない。**
* データベースの変更を検討しても、RDB以外のデータベースとなると、その性質の違いを考えると、**アプリケーションの刷新の必要性に迫られてしまう**

## RDBサーバのフェイルオーバー、メンテナンス
RDSであればMulti-AZ構成にすることで、RDSマスターが何らかの理由でダウンした場合には、自動的にフェイルオーバーされます。そのフェイルオーバーにかかる時間は分単位で必要となることもあります。さらに、パッチ適用に伴うメンテナンスウィンドウは必要です。リリース当初は問題ありませんでしたが、ビジネス拡大に伴い、これらの挙動が許されない厳しい要件のもとに提供する必要性が出てくるケースもあると考えます。

では、どのような選択を検討すべきだったのでしょうか？

##最適なデータベースの選択
###新規システムのアーキテクチャ検討当初から顧客体験の改善を意識したデータベース選定を行う
RDB以外のNoSQLのデータベースも選択肢として検討すべきです。NoSQLのデータベースは世の中にさまざまな種類のものが提供されていますが、私は**管理不要で容量無制限のAmazon DynamoDBを推したい**と思います。DynamoDBであれば、書き込み用と読み込み用のスループットの量（キャパシティユニット）を指定することができます。こちらにより、例えばユーザーアクセスの多い時間帯は書き込み用のスループットを増やし、アクセスの少ない時間帯はスループットを減らします。このスループットの値が大きいほど1時間当たりの課金が高くなり、低い値に設定することで課金を少なくすることができます。読み込みも同様です。このように**アクセスするユーザー数の増加に合わせて書きこみ・読み込みのスループットを増減させることで料金を最適化、スケールができます。**

他にもAWSではAmazon ElastiCache（マネージド型RedisまたはMemcached互換のインメモリデータストア）、Amazon Neptune（完全マネージド型グラフデータベース） Amazon Redshift（データウェアハウスサービス）, Amazon DocumentDB（MongoDB互換のドキュメントデータベース）, Amazon QLDB（フルマネージド型台帳データベース）などがあります。

![Database.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66106/299ff030-eb03-cf7f-0017-ac166babffb4.png)

どのデータベースを選べばよいか悩まれる部分もあると思いますが、一つの観点としては、**開発されるアプリケーションの顧客体験に寄り添うことが重要**だと考えます。今回のケースで考えると、ユーザー数が増加しても、顧客体験が損なわれない、スケーラビリティのあるシステムにすべきです。その観点で、是非安易にRDBを選択するのではなく、**他のデータベースも併用するなどご検討頂くのが良い**と思います。

##最後に

AWS社員Qiitaブログシリーズ第一弾の記事はいかがでしたでしょうか？

今後も少なくとも週に1回ペースでAWS社員によるブログ記事執筆を行っていく予定です。乞うご期待ください！