最初の1億人のユーザーにスケーリングするシステム設計方法【後編】　RDBのスケーリング、使うべきDB、高度なコンセプト

本記事は、[Anh Dang](https://dangtrunganh.medium.com/)氏による「[How to design a system to scale to your first 100 million users](https://levelup.gitconnected.com/how-to-design-a-system-to-scale-to-your-first-100-million-users-4450a2f9703d)」（2021年6月28日公開）の和訳を、著者の許可を得て掲載しているものです。

#最初の1億人のユーザーにスケーリングするシステム設計方法【後編】
>大きく考え、小さく行い、速く学ぶ

###

>新技術に対応するため、この記事は1年を通して更新したいと思います。
>最終更新日：2021年6月28日

![](https://miro.medium.com/max/700/0*z3gY0E6tUsDOue7Q)
>Photo by [Kirill Sh](https://unsplash.com/@kirill2020?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com/?utm_source=medium&utm_medium=referral)

##はじめに

何億人ものユーザーをサポートするシステムの設計は、容易なことではありません。ソフトウェアアーキテクトにとっては、常に大きな挑戦です（でも、私の記事を読めば、今日から簡単になります🤣）。

この記事で取り上げたトピックは次の通りです。

[【前編】](https://qiita.com/baby-degu/items/3b45df9693c9a01ee646)
-   最も単純なものから始める：オールインワン
-   スケーラビリティの技術：スケールアウトとスケールアップ

【後編】
-   リレーショナルデータベースのスケーリング：Master-Slaveレプリケーション、Master-Masterレプリケーション、フェデレーション、シャーディング、非正規化、SQLチューニング
-   使うべきデータベース：NoSQLかSQLか
-   高度なコンセプト：キャッシング、CDN、geoDNSなど

>今日は、フォールトトレランス、信頼性、高可用性など、ハイパフォーマンスコンピューティングの一般的な用語については触れません。

落ち着いて、さあ始めましょう！

>今回は後編です。[前編はこちら。](https://qiita.com/baby-degu/items/3b45df9693c9a01ee646)

##リレーショナルデータベースのスケーリング

単純なシステムで、OracleやMySQLなどのRDBMSを使用してデータ項目を保存できます。しかし、リレーショナルデータベースシステムには、特にスケーリングが必要な場合に課題が出てきます。

リレーショナルデータベースのスケーリングには、**Master-Slaveレプリケーション**、**Master-Masterレプリケーション**、**フェデレーション**、**シャーディング**、**非正規化**、**SQLチューニング**など、多くの手法があります。

-   **レプリケーション**：通常、同じデータの複数のコピーを異なるマシンに保存する技術を指す。
-   **フェデレーション（または機能分割）**：データベースを機能ごとに分割する。
-   **シャーディング**：分割に関連するデータベースアーキテクチャパターン。データのさまざまな部分を複数のサーバーに配置し、複数のユーザーがデータセットのさまざまな部分にアクセスする。
-   **非正規化**：**コストのかかる結合を回避するため、複数テーブルにデータを書き込むことで、書き込みパフォーマンスを犠牲にする代わりに読み取りパフォーマンスを向上させようとする。**
-   **SQLチューニング**

###Master-Slaveレプリケーション

Master-Slaveレプリケーション技術を使用して、下の図のように、1つのデータベースサーバー（Master）のデータを、1つ以上の他のデータベースサーバー（Slave）に複製できます。

![](https://miro.medium.com/max/700/1*jqwAdhsKz2cQXCD5p3aM_g.png)
>Masterに対するすべての更新

-   クライアントはMasterに接続してデータを更新する。
-   データは、すべてのデータがサーバー間で一貫性を持つまでSlaveに波及する。

実際には、ここにはまだ少しボトルネックがあります。

-   Masterサーバーが何らかの理由でダウンした場合、データはSlave経由で利用できるが、新たな書き込みはできない。
-   SlaveをMasterに昇格させるには、追加のアルゴリズムを必要とする。

1つのサーバーだけで更新リクエストを処理するためのソリューションは次の通りです。

-   **同期ソリューション**：データを変更するトランザクションは、すべてのサーバーに受け入れられるまでコミットされないため（分散トランザクション）、フェイルオーバー時にデータが失われることはない。
-   **非同期ソリューション**：コミット→遅延→クラスター内の他のサーバーに伝搬されるため、フェイルオーバー時にデータ更新が失われる可能性がある。

同期ソリューションが遅すぎる場合は、非同期ソリューションに変更することを覚えておいてください。

###Master-Masterレプリケーション

各データベースサーバーは、他のMasterサーバーが存在していても、各データベースサーバーがMasterとして機能できます。ある時点で、すべてのMasterが同期して、正しい最新データを保持していることを確認します。

![](https://miro.medium.com/max/700/1*ZxE-GuE2V8D1CPgrt3aCyg.png)
>すべてのノードがすべてのデータを読み書きする

Master-Masterレプリケーションの利点は次の通りです。

-   1つのMasterに障害が発生しても、他のデータベースサーバーは正常に動作し、不足分を補うことができる。データベースサーバーがオンラインに戻ると、レプリケーションを使用して回復する。
-   Masterは複数の物理サイトに配置できるため、ネットワーク全体に分散できる。
-   Masterは更新の処理能力により制限される。

###フェデレーション

フェデレーション（または機能分割）は、データベースを機能別に分割します。例えば、1つの巨大なデータベースの代わりに、フォーラム、ユーザー、製品の3つのデータベースを使用すると、各データベースへの読み書きのトラフィックが減るため、レプリケーションの遅延が減ります。

![](https://miro.medium.com/max/700/1*ISy_gtwkY9CWCFKQuf3bHA.png)
>フェデレーションによるデータベースの機能分割

データベースが小さくなると、メモリに収まるデータが増え、キャッシュの局所性が向上するため、キャッシュのヒット数が増加します。書き込みを直列化する中央のMasterがいなければ、並行して書き込むことができ、スループットが向上します。

###シャーディング

シャーディング（データ分割とも呼ばれる）とは、大きなデータベースをいくつかの小さな部分に分割し、各データベースがデータのサブセットのみを管理できるようにする技術です。

理想的なケースでは、複数のユーザーが各データベースノードに接続しています。システムの管理性、パフォーマンス、可用性、負荷分散を向上できます。

-   各ユーザーは1つのサーバーとだけ通信するため、そのサーバーから迅速な応答を取得する。
-   サーバー間で適切に負荷分散される。例えば、5つのサーバーがある場合、各サーバーは負荷の20％を処理するだけで済む。

実際には、データベースを複数の小さな部分に分割する多くの手法があります。

###水平分割

この手法では、複数の行を複数のテーブルに分割します。例えば、ユーザーのプロファイルをテーブルに格納する場合、IDが1000未満のユーザーをあるテーブルに格納し、IDが1001以上2000未満のユーザーを別のテーブルに格納することができます。

![](https://miro.medium.com/max/700/1*toqrsVPKK_oQ_oOVoEuEUg.png)
>複数の行を複数のテーブルに格納する

###垂直分割

この場合、データを分割して、特定の機能に関連するテーブルをそれぞれのサーバーに格納します。例えば、Instagramのようなシステムを構築する場合、ユーザー、ユーザーがアップロードする写真、ユーザーがフォローしているユーザーに関連するデータを保存する必要がありますが、1つ目のデータベースサーバーにユーザーのプロファイル情報、2つ目のサーバーに友達リスト、3つ目のサーバーに写真を格納することができます。

![](https://miro.medium.com/max/700/1*D-965B3oT0gECnn8I7mjXg.png)
>データを分割して、特定の機能に関連するテーブルをそれぞれのサーバーに格納する

###ディレクトリベースの分割

この問題に対する疎結合のアプローチは、現在の分割スキーマを認識し、各エンティティのマップとそれが格納されているデータベースシャードを保持するルックアップサービスを作成することです。

この方法は、データストアが1つのストレージノードで利用可能なリソースを超えてスケーリングする必要がある場合や、データストアでの競合を減らしてパフォーマンスを向上させる必要がある場合に使用できます。ただし、シャーディング技術には次のような一般的な問題があることに注意してください。

-   データベース**結合**は、よりコストがかかり、場合によっては実行不可能になる。
-   シャーディングは、データベースの参照**整合性**を損なう可能性がある。
-   データベース**スキーマ**の変更は、非常にコストがかかる可能性がある。
-   データ**分散**が均一ではなく、シャーディングに大きな負荷がかかる。

###非正規化

非正規化は、書き込みパフォーマンスを犠牲にして、読み取りパフォーマンスを向上しようとします。データの冗長コピーを複数のテーブルに書き込み、コストのかかる結合を回避します。

>フェデレーションやシャーディングなどの技術でデータが分散されると、データセンター間で結合を管理することでさらに複雑になります。非正規化によって、このような複雑な結合の必要性を回避できるかもしれません。

ほとんどのシステムでは、読み取りが書き込みを100:1または1000:1よりも大幅に上回る可能性があります。複雑なデータベース結合をもたらす読み取りは、ディスク操作に膨大な時間を費やし、非常にコストがかかる可能性があります。

PostgreSQLやOracleなどの一部のRDBMSでは、冗長な情報を格納し、冗長コピーの一貫性を維持する作業を行うマテリアライズドビューをサポートします。

FacebookのRyan Mack氏は、「Building Timeline: Scaling up to hold your life story⁶ by using the power of Denormalization（タイムラインの構築：非正規化の力で、ライフストーリー⁶保持のためにスケールアップする）」と言う素晴らしい記事の中で、たくさんのタイムライン実装エピソードについて話しています。

##使うべきデータベース

データベースの世界には、SQLとNoSQLと言う2つの主要な種類のソリューションがあります。どちらも、構築方法、保存する情報の種類、格納方法が異なります。

###SQL

リレーショナルデータベースは、データを行と列に格納します。各行には1つのエンティティに関するすべての情報が含まれ、各列にはすべての個別データポイントを含みます。

最も人気のあるリレーショナルデータベースには、MySQL、Oracle、MS SQL Server、SQLite、Postgres、MariaDBなどがあります。

###NoSQL

非リレーショナルデータベースとも呼ばれます。通常、主要な5つのカテゴリー（キーバリュー型、グラフ型、カラム型、ドキュメント型、Blob型）に分類されます。

###キーバリュー型データベース

データは、キーバリューペアの配列に格納されます。**キー**は**バリュー**にリンクされた属性名です。

有名なキーバリュー型データベースには、Redis、Voldemort、Dynamoなどがあります。

###ドキュメント型データベース

データは（テーブルの行や列ではなく）ドキュメントに格納され、ドキュメントはコレクションにグループ化されます。各ドキュメントは、まったく異なる構造を持つことができます。

ドキュメント型データベースには、CouchDBやMongoDBなどがあります。

###ワイドカラム型データベース

カラム型データベースには、「テーブル」の代わりに、行のコンテナであるカラムファミリーがあります。リレーショナルデータベースとは異なり、すべての列を事前に把握する必要はなく、各行に同じ数の列を持つ必要もありません。

カラム型データベースは、大規模なデータセットの分析に最適です。有名なカラム型データベースには、CassandraやHBaseなどがあります。

###グラフ型データベース

グラフで関係を最も良く表現できるデータを格納するためのデータベースです。データは、ノード（エンティティ）、プロパティ（エンティティ情報）、ライン（エンティティ間の接続）のグラフ構造で格納されます。

グラフ型データベースには、Neo4JやInfiniteGraphなどがあります。

###Blob型データベース

Blob型はファイルのキーバリュー型に似ていて、Amazon S3、Windows Azure
Blob Storage、Google Cloud Storage、Rackspace Cloud Files、OpenStack
SwiftなどのAPIを介してアクセスします。

###使うべきデータベースの選び方

>データベース技術に関しては、万能のソリューションはありません。そのため、多くの企業ではニーズに合わせてSQLデータベースとNosQLデータベースを使い分けています。

次のガイダンスを見てください！

![](https://miro.medium.com/max/700/1*Mj2LqJrr-Xh3lyl3UskHQA.png)
>使うべきデータベース

###Web層を水平スケーリングする

データ層をスケーリングしたので、次はWeb層をスケーリングする必要があります。そのため、ユーザーセッション（状態）のデータをリレーショナルデータベースやNoSQLのデータベースに格納して、Web層から移動する必要があります。これはステートレスアーキテクチャとも呼ばれます。

![](https://miro.medium.com/max/700/1*DPmfJe9lPPaix6uC_EqD8Q.png)
>ステートレスシステムは単純

###

>ステートフルアーキテクチャを使用しないでください。
>ステートが実装されていると、スケーラビリティが制限され、可用性が低下し、コストも増大するため、可能な限りステートレスアーキテクチャを選択する必要があります。

上の場合、ロードバランサーは、最適なリクエスト処理のために任意のサーバーを選択できるため、最大の効率を達成できます。

##高度なコンセプト

###キャッシング

負荷分散は、増え続けるサーバー間での水平スケーリングに役立ちますが、キャッシングを使用すると、既存リソースを大幅に有効活用し、次のリクエストでデータをより高速に提供できます。

![](https://miro.medium.com/max/700/1*Ua7DootBbkjh8dKm3lxrhg.png)
>データがキャッシュにない場合、データベースから取得し、キャッシュに保存してから読み取る

サーバーにキャッシュを追加することで、サーバーから直接Webページやデータを読み取らずに済むため、応答時間とサーバーの負荷の両方を軽減できます。これにより、アプリケーションのスケーラビリティが向上します。

キャッシングは、データベース層、Webサーバー層、ネットワーク層など、さまざまな層で適用できます。

###コンテンツデリバリーネットワーク（CDN）

CDNサーバーは、コンテンツ（画像、Webページなど）のキャッシュされたコピーを保持し、最も近い場所から提供します。

CDNを使用すると、データを最も近い場所で取得するため、ユーザーのページ読み取り時間が短縮されます。コンテンツを複数の場所に保存するため、コンテンツの可用性を高めることにもつながります。

![](https://miro.medium.com/max/700/1*YdWdRmUOAT6uN7Gs2gsfGw.png)
>CDNを使用すると、データを最も近い場所から取得されるため、ユーザーのページ読み取り時間が短縮される

CDNサーバーは、キャッシュされているコンテンツを検証し、必要に応じて更新するようにWebサーバーにリクエストします。キャッシュされるコンテンツは、通常、HTMLページ、画像、JavaScriptファイル、CSSファイルなどの静的なものです。

###グローバル化

アプリケーションがグローバル化すると、世界中にデータセンターを所有および運営して、製品を24時間365日稼働させ続けられます。受信リクエストは、GeoDNSに基づいて「最適な」データセンターにルーティングされます。

![](https://miro.medium.com/max/700/1*xCizub9BeG41cbsRqIzqHw.png)
>アプリのグローバル化

GeoDNSは、クライアントの所在地に基づいてドメイン名をIPアドレスに解決できるDNSサービスです。アジアから接続しているクライアントは、ヨーロッパから接続しているクライアントとは異なるIPアドレスを取得する可能性があります。

##まとめ

これらすべての技術を繰り返し適用することで、1億人以上のユーザーにシステムを簡単にスケーリングできます（ステートレスアーキテクチャ、ロードバランサーの適用、キャッシュデータの最大限の活用、複数のデータセンターのサポート、CDNでの静的資産のホスティング、シャーディングによるデータ層のスケーリングなど）。

![](https://miro.medium.com/max/700/1*1kk4onc-nalDvx-LRjGhZw.png)
>スケーリングは反復プロセス

##次に議論すべきテーマ

スケーラビリティと性能を向上させる方法は、次のようにたくさんあります。

-   シャーディングとレプリケーションの技術の組み合わせ
-   ロングポーリング対Websocket対サーバー送信イベント
-   インデックスとプロキシ
-   SQLチューニング
-   エラスティックコンピューティング

簡単、ですよね？

##参考文献

[1] [https://httpd.apache.org](https://httpd.apache.org/)
[2] [http://tomcat.apache.org](http://tomcat.apache.org/)
[3] <https://www.oracle.com/database/>
[4] [https://www.mysql.com](https://www.mysql.com/)
[5] <https://en.wikipedia.org/wiki/Domain_Name_System>
[6] <https://www.facebook.com/note.php?note_id=10150468255628920>

##翻訳協力

この記事は以下の方々のご協力により公開する事ができました。改めて感謝致します。

Original Author: [Anh Dang](https://dangtrunganh.medium.com/) (<http://junryo.xyz>)
Original Article: [How to design a system to scale to your first 100 million users](https://levelup.gitconnected.com/how-to-design-a-system-to-scale-to-your-first-100-million-users-4450a2f9703d)
Thank you for letting us share your knowledge!

選定担当: @gracen
翻訳担当: @gracen
監査担当: -
公開担当: @gracen

##ご意見・ご感想をお待ちしております
今回の記事はいかがでしたか？
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
頂いたお声は、今後の記事の質向上に役立たせて頂きますので、お気軽に
コメント欄にてご投稿ください。[Twitter](https://twitter.com/BabyDegu?lang=ja)でもご意見を受け付けております。
皆様のメッセージをお待ちしております。