以前のブログ「MongoDBデータモデリングを使用してスループット操作を改善する方法」では、埋め込みと参照という2つの主要なデータモデリング関係アプローチについて説明しました。 MongoDBのスケーラビリティは、そのアーキテクチャに大きく依存しており、具体的には、データモデリングに依存しています。 NoSQL DBMを設計する際の主な考慮事項は、メンテナンスを容易にするために、少数のコレクションに加えてスキーマのないドキュメントを確保することです。良好なデータ整合性。ストレージが推奨される前に、いくつかの定義されたルールによるデータ検証を採用します。データベースのアーキテクチャと設計は、データの繰り返しを避け、データの整合性を向上させ、検索パターンを容易にする方法として、正規化して複数の小さなコレクションに分解する必要があります。これにより、データベースのデータの一貫性、原子性、耐久性、整合性を向上させることができます。
データモデリングは、アプリケーション開発フェーズで後から付け加えた作業ではなく、データモデリング段階で実際に多くのアプリケーションファセットが実現されるため、最初の考慮事項です。この記事では、データモデリング中に考慮する必要のある要因について説明し、それらがデータベースのパフォーマンスにどのように影響するかを確認します。
多くの場合、データの可用性を高める1つの方法として、データベースのクラスターをデプロイする必要があります。適切に設計されたデータモデルを使用すると、シャーディングされたクラスターにアクティビティをより効果的に分散できるため、単一のmongodインスタンスを対象としたスループット操作を削減できます。データモデリングで考慮すべき主な要因は次のとおりです。
- スケーラビリティ
- アトミシティ
- パフォーマンスとデータ使用量
- シャーディング
- インデックス作成
- ストレージの最適化
- ドキュメントの構造と成長
- データライフサイクル
1。スケーラビリティ
これは、トラフィックの増加によって引き起こされるアプリケーションのワークロードの増加です。多くのアプリケーションは、常にユーザー数の増加を期待しています。単一のデータベースインスタンスによってサービスが提供されるユーザーが非常に多い場合、パフォーマンスは必ずしも期待に応えるとは限りません。したがって、データベース・マネージャーとして、コレクションとデータ・エンティティーがアプリケーションの現在および将来の要求に基づいてモデル化されるように、このDBMを設計する権限があります。データベース構造は、レプリケーションとシャーディングのプロセスを容易にするために、一般的に見栄えがよいものでなければなりません。より多くのシャードがある場合、書き込み操作はこのシャード間で分散されるため、データの更新では、単一の大きなデータセットを検索して更新するのではなく、そのデータを含むシャード内で実行されます。
2。アトミシティ
これは、単一のユニットとしての操作の成功または失敗を指します。たとえば、結果をフェッチした後のソート操作を含む読み取り操作があるとします。したがって、ソート操作が適切に処理されない場合、操作全体が次の段階に進むことはありません。
アトミックトランザクションは、分割も縮小もできない一連の操作であるため、単一のエンティティとして発生するか、単一の操作として失敗します。 4.0より前のMongoDBバージョンは、単一のドキュメントレベルでのアトミックプロセスとしての書き込み操作をサポートしています。バージョン4.0では、マルチドキュメントトランザクションを実装できるようになりました。アトミック操作を強化するデータモデルは、レイテンシーの点で優れたパフォーマンスを発揮する傾向があります。レイテンシーとは、単に操作要求が送信され、データベースから応答が返される時間のことです。秘密にするために、参照されているドキュメントではなく、単一のドキュメントに埋め込まれているデータを更新するのは簡単です。
たとえば、以下のデータセットについて考えてみましょう
{
childId : "535523",
studentName : "James Karanja",
parentPhone : 704251068,
age : 12,
settings : {
location : "Embassy",
address : "420 01",
bus : "KAZ 450G",
distance : "4"
}
}
年齢を1増やして更新し、場所をロンドンに変更したい場合は、次のようにします。
db.getCollection(‘students’).update({childId: 535523},{$set:{'settings.location':'London'}, $inc:{age:1}}).
たとえば、$ set操作が失敗した場合、自動的に$ inc操作は実装されず、通常、操作全体が失敗します。
一方、参照データについて考えてみましょう。たとえば、学生用と設定用の2つのコレクションがあります。
学生コレクション
{
childId : "535523",
studentName : "James Karanja",
parentPhone : 704251068,
age : 12
}
設定コレクション
{
childId : "535523",
location : "Embassy",
address : "420 01",
bus : "KAZ 450G",
distance : "4"
}
この場合、個別の書き込み操作で年齢と場所の値を更新できます。つまり
db.getCollection(‘students’).update({childId: 535523},{$inc:{age:1}})
db.getCollection('settings’).update({childId: 535523 } , {$set: { 'settings.location':'London'}})
操作の1つが失敗しても、それらは異なるエンティティとして実行されるため、必ずしも他の操作に影響を与えるとは限りません。
複数のドキュメントのトランザクション
MongoDBバージョン4.0では、レプリカセットに対して複数のドキュメントトランザクションを実行できるようになりました。これにより、高速処理のために操作が多数のコレクション、データベース、およびドキュメントに発行されるため、パフォーマンスが向上します。トランザクションがコミットされるとデータが保存されますが、問題が発生してトランザクションが失敗した場合、行われた変更は破棄され、トランザクションは通常中止されます。トランザクションが完全にコミットされた場合にのみ操作が外部に表示されるため、トランザクション中にレプリカセットが更新されることはありません。
複数のトランザクションで複数のドキュメントを更新できる限り、単一のドキュメントの書き込みと比較してパフォーマンスが低下するという欠点があります。さらに、このアプローチはWiredTigerストレージエンジンでのみサポートされているため、インメモリおよびMMAPv1ストレージエンジンには不利です。
3。パフォーマンスとデータ使用量
アプリケーションは、さまざまな目的に合わせてさまざまに設計されています。天気ニュースアプリケーションのように、現在のデータにのみ役立つものもあります。アプリケーションの構造に応じて、必要なユースケースを提供するための対応する最適なデータベースを設計できる必要があります。たとえば、データベースから最新のデータをフェッチするアプリケーションを開発する場合は、上限付きのコレクションを使用するのが最適なオプションです。上限付きコレクションは、割り当てられたスペースが利用されると、最も古いドキュメントが上書きされ、挿入された順序でドキュメントをフェッチできるように、バッファーと同じように高スループットの操作を強化します。挿入順序の取得を考慮すると、インデックスを使用する必要はなく、インデックスのオーバーヘッドがないため、書き込みスループットも同様に向上します。上限付きのコレクションでは、関連付けられたデータは非常に小さく、RAM内でしばらくの間維持できます。この場合の一時データはキャッシュに格納され、キャッシュには書き込まれるよりもかなり読み取られるため、読み取り操作が非常に高速になります。ただし、上限付きコレクションには、コレクション全体を削除しないとドキュメントを削除できない、ドキュメントのサイズを変更すると操作が失敗する、最後に上限付きコレクションをシャーディングできないなどの欠点があります。
>使用ニーズに応じて、さまざまなファセットがデータベースのデータモデリングに統合されます。ご覧のとおり、レポートアプリケーションは読み取りが集中する傾向があるため、読み取りスループットを向上させる方法で設計する必要があります。
4。シャーディング
読み取りと書き込みのワークロードがクラスターメンバー間で分散されるため、シャーディングによって水平スケーリングによるパフォーマンスを向上させることができます。シャードのクラスターをデプロイすると、一部のシャードキーに応じて、データベースが分散ドキュメントを含む複数の小さなコレクションに分割される傾向があります。書き込み容量を増やすだけでなく、クエリの分離を防ぐことができる適切なシャードキーを選択する必要があります。より適切な選択には、通常、対象のコレクション内のすべてのドキュメントに存在するフィールドが含まれます。シャーディングを使用すると、データが大きくなるにつれて、このクラスターのサブセットを保持するためにより多くのシャードが確立されるため、ストレージが増加します。
5。インデックス作成
インデックス作成は、特にすべてのドキュメントでフィールドが発生している場合に、書き込みワークロードを改善するための最良のアプローチの1つです。インデックス作成を行うときは、各インデックスに8KBのデータスペースが必要になることを考慮する必要があります。さらに、インデックスがアクティブな場合、ディスクスペースとメモリを消費するため、容量計画のために追跡する必要があります。
SomeninesがMongoDBDBAになる-MongoDBを本番環境に導入MongoDBDownloadを無料でデプロイ、監視、管理、スケーリングするために知っておくべきことを学びましょう6。ストレージの最適化
コレクション内の多くの小さなドキュメントは、サブ埋め込みドキュメントを含むいくつかのドキュメントがある場合よりも多くのスペースを占める傾向があります。したがって、モデリングするときは、保存する前に関連データをグループ化する必要があります。ドキュメントが少ないと、データベース操作を少ないクエリで実行できるため、ランダムなディスクアクセスが減り、対応するインデックスに関連付けられているキーエントリが少なくなります。したがって、この場合の考慮事項は次のとおりです。埋め込みを使用してドキュメントを少なくし、ドキュメントごとのオーバーヘッドを削減します。ドキュメントのオーバーヘッドが大きくならないように、コレクションに含まれるフィールドが少ない場合は、フィールド名を短くしてください。フィールド名を短くすると、表現力が低下します。つまり、
{ Lname : "Briston", score : 5.9 }
使用するのではなく、ドキュメントごとに9バイト節約できます
{ last_name : "Briston", high_score: 5.9 }
_idフィールドを明示的に使用します。デフォルトでは、MongoDBクライアントは、このフィールドに一意の12バイトのObjectIdを割り当てることにより、各ドキュメントに_idフィールドを追加します。さらに、_idフィールドにインデックスが付けられます。ドキュメントがかなり小さい場合、このシナリオでは、ドキュメント全体の数にかなりのスペースが必要になります。ストレージを最適化するために、ドキュメントをコレクションに挿入するときに_idフィールドの値を明示的に指定できます。ただし、コレクション内のドキュメントの主キーとして機能するため、値が一意に識別されるようにしてください。
7。ドキュメントの構造と成長
これは、サブドキュメントが配列フィールドにプッシュされるプッシュ操作の結果として、または新しいフィールドが既存のドキュメントに追加されるときに発生します。ドキュメントの増加にはいくつかの欠点があります。つまり、上限のあるコレクションの場合、サイズが変更されると、操作は自動的に失敗します。 MMAPv1ストレージエンジンの場合、3.0より前のバージョンでは、ドキュメントサイズを超えると、ドキュメントがディスクに再配置されます。ただし、3.0以降のバージョンでは、Power of 2 Sized Allocationsの概念があり、このような再割り当ての可能性を減らし、解放されたレコードスペースを効果的に再利用できます。データの増加が予想される場合は、データモデルをリファクタリングして、非正規化データモデルを使用するのではなく、個別のドキュメント内のデータ間の参照を使用することをお勧めします。ドキュメントの増加を回避するために、事前割り当て戦略の使用を検討することもできます。
8。データライフサイクル
最近挿入されたドキュメントのみを使用するアプリケーションの場合は、機能について上記で説明した上限付きコレクションの使用を検討してください。
コレクションの存続時間機能を設定することもできます。これは、アプリケーションのパスワードリセット機能のアクセストークンに非常に当てはまります。
存続時間(TTL)
これは、mongodが指定された期間の後にデータを自動的に削除できるようにするコレクション設定です。デフォルトでは、この概念は、限られた期間持続する必要があるマシン生成のイベントデータ、ログ、およびセッション情報に適用されます。
例:
db.log_events.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )
インデックスcreatedAtを作成し、作成後1時間のexpireAfterSeconds値3600を指定しました。ここで、次のようなドキュメントを挿入すると、次のようになります。
db.log_events.insert( {
"createdAt": new Date(),
"logEvent": 2,
"logMessage": "This message was recorded."
} )
このドキュメントは、挿入時から1時間後に削除されます。
ドキュメントを削除する時刻を特定の時刻に設定することもできます。これを行うには、最初にインデックスを作成します。例:
db.log_events.createIndex( { "expireAt": 1 }, { expireAfterSeconds: 0 } )
これで、ドキュメントを挿入して、削除する時刻を指定できます。
db.log_events.insert( {
"expireAt": new Date(December 12, 2018 18:00:00'),
"logEvent": 2,
"logMessage": "Success!"
} )
このドキュメントは、expireAt値がexpireAfterSecondsで指定された秒数(この場合は0)よりも古い場合に自動的に削除されます。
結論
データモデリングは、データベースのパフォーマンスを向上させるために、あらゆるアプリケーション設計にとって広々とした取り組みです。データベースにデータを挿入する前に、アプリケーションのニーズと、実装する必要のある最適なデータモデルパターンを検討してください。さらに、アプリケーションの重要な側面は、適切なデータモデルを実装するまで実現できません。