オンラインサービスは、発生したエラー、トリガーされたアラート、ユーザーの行動に関する情報を含む多数の操作ログとアクセスログを生成します。 ほとんどの場合、ログは読み取り可能なテキストファイルに保存され、ルーチンのO&Mで問題をすばやく特定するために使用できます。しかし、サービスが大量のログを生成した後、ログデータから価値のある情報を導出するために、より高度な方法でログを保存し分析する必要があります。
このトピックでは、ApsaraDB for MongoDBを使用してwebサービスのアクセスログを保存および分析し、ログの値を最大化する方法について説明します。 このトピックで説明する方法と操作は、他の種類のログストレージサービスにも適用されます。
webサーバのアクセスログ
webサーバーのアクセスログエントリの例を次に示します。 アクセスソース、ユーザー名、アクセスされたリソースのURL、アクセス結果、使用されたオペレーティングシステム、およびブラウザの種類に関する情報が含まれています。
127.0.0.1-フランク [10/Oct /2000:00:13:55:36-0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "[http://www.example.com/start.html](http://www.example.com/start.html)" "Mozilla/4.08 [en] (Win98; I ;Nav)"
ApsaraDB for MongoDBを使用して、各アクセスログを1つのドキュメントに次の形式で保存できます。
{
_id: ObjectId('4f442120eb03305789000000') 、
行: '127.0.0.1-フランク [10/Oct /2000:00:13:55:36-0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "[http://www.example.com/start.html](http://www.example.com/start.html)" "Mozilla/4.08 [en] (Win98; I ;Nav)"'
}
上記の形式は簡単に設定できます。 しかし、このフォーマットは、ログデータの分析に不便をもたらす可能性がある。 ApsaraDB for MongoDBは、テキスト分析を対象としたサービスではありません。 ログをApsaraDB for MongoDBにドキュメントとして保存する前に、ログの形式を変換して各フィールドとその値をログから抽出することをお勧めします。 次のサンプルコードは、上記のログを別のフィールドと値に変換する方法を示しています。
{
_id: ObjectId('4f442120eb03305789000000') 、
ホスト: "127.0.0.1" 、
logname: null、
ユーザー: 'frank' 、
time: ISODate("2000-10-10T20:55:36Z") 、
パス: "/apache_pb.gif" 、
リクエスト: "GET /apache_pb.gif HTTP/1.0" 、
status: 200,
response_size: 2326、
リファラー: "[http://www.example.com/start.html](http://www.example.com/start.html)" 、
user_agent: "Mozilla/4.08 [en] (Win98; I ;Nav)"
}
ログの形式を変換するときに、データ分析に関係のないフィールドを削除して、ストレージ容量を節約できます。 上記のドキュメントでは、ユーザー、リクエスト、ステータスフィールドなど、いくつかの無関係なフィールドを削除する必要があります。 _idフィールドにはアクセス時間に関する情報が含まれているため、時間フィールドを削除することもできます。 時間フィールドを保持することもできます。 このフィールドは、リクエストが送信された時刻を示し、SQL文の記述を容易にします。 必要なストレージ容量が少ないデータ型を選択することを推奨します。 上記の考慮事項に基づいて、次の更新されたコンテンツが最終的にドキュメントに保存される可能性があります。
{
_id: ObjectId('4f442120eb03305789000000') 、
ホスト: "127.0.0.1" 、
time: ISODate("2000-10-10T20:55:36Z") 、
パス: "/apache_pb.gif" 、
リファラー: "[http://www.example.com/start.html](http://www.example.com/start.html)" 、
user_agent: "Mozilla/4.08 [en] (Win98; I ;Nav)"
}
ApsaraDB for MongoDBへのログの書き込み
一度に大量のログを収集するには、ログストレージサービスが必要です。 この要件を満たすには、ApsaraDB for MongoDBの書き込みに関する懸念
を指定して書き込み操作を管理します。 たとえば、次の書き込み懸念を指定できます。
db.events.insert({
ホスト: "127.0.0.1" 、
time: ISODate("2000-10-10T20:55:36Z") 、
パス: "/apache_pb.gif" 、
リファラー: "[http://www.example.com/start.html](http://www.example.com/start.html)" 、
user_agent: "Mozilla/4.08 [en] (Win98; I ;Nav)"
},
{
writeConcern:{w: 0}
}
)
最も高い書き込みスループットが必要な場合は、
書き込み関連
のwオプションを{w: 0}
に設定できます。ログにサービス課金の資格情報などの重要な情報が含まれている場合、
書き込み懸念
のwオプションを{w: 1}
または{w: "majority"}
に設定できます。これは {w: 0} よりも安全です。
書き込み操作の効率を向上させるために、1回のリクエストで複数のログをApsaraDB for MongoDBに書き込むことができます。 リクエストの形式は次のとおりです。
db.events.insert([doc1, doc2, ...])
ApsaraDB for MongoDBのクエリログ
上記の方法を使用してApsaraDB for MongoDBにログを保存した後、要件に基づいてログをクエリできます。
すべてのリクエストのログを照会して /apache_pb.gifにアクセスします。
q_events = db.events.find({'path': '/apache_pb.gif'})
説明このクエリを頻繁に実行する場合は、パスフィールドにインデックスを作成して、クエリの効率を向上させることができます。 例:
db.events.createIndex({path: 1})
1日以内のすべてのリクエストのログを照会します。
q_events = db.events.find({'time': { '$gte': ISODate("2016-12-19T00:00:00.00Z")) 、'$lt': ISODate("2016-12-20T00:00:00.00Z")})
説明時間フィールドにインデックスを作成して、クエリの効率を向上させることができます。 例:
db.events.createIndex({time: 1})
指定された期間にサーバーに送信されたすべてのリクエストのログを照会します。
q_events = db.events.find({ 'host': '127.0.0.1 '、 'time': {'$gte': ISODate("2016-12-19T00:00:00.00Z") 、'$lt': ISODate("2016-12-20T00:00:00.00Z"} })
同様に、ApsaraDB for MongoDBが提供する集計パイプラインまたはMapReduceフレームワークを使用して、データ分析のためのより複雑なクエリを開始できます。 クエリ効率を向上させるために、フィールドにインデックスを適切に作成することを推奨します。
データシャーディング
ログを生成するサービスノードの数が増加するにつれて、ログストレージサービスの書き込みおよびストレージ機能に問題が生じ、より高いレベルの機能が必要とされる。 この場合、ApsaraDB for MongoDBのシャーディング方法を使用して、ログデータを複数のシャードに分散できます。 シャーディング方法を使用するときは、シャードキーの選択に集中する必要があります。
タイムスタンプを示すフィールドをシャードキーとして使用します。たとえば、_idまたはtimeフィールドをシャードキーとして使用します。 ただし、このタイプのシャーディングでは次の問題が発生する可能性があります。
タイムスタンプが順番に増えると、新しく収集されたログデータは同じシャードに分散されます。 したがって、ApsaraDB for MongoDBの書き込み機能は強化されません。
多くのクエリは、少数のシャードにのみ配布される最新のログデータを対象としています。 この場合、これらのシャードに関連する統計のみがこれらのクエリに対して返されます。
ハッシュシャーディングメソッドを使用する: ハッシュシャーディングのデフォルトのシャードキーは_idフィールドに設定されます。 このシャーディングメソッドは、ログデータを各シャードに均等に分散します。 したがって、ApsaraDB for MongoDBの書き込み機能は、シャードとともに線形に成長します。 ただし、ハッシュシャーディングはデータをランダムに分散します。 これにより、ApsaraDB for MongoDBが特定のレンジドクエリ (通常はデータ分析用) のリクエストを効率的に処理できないという問題が発生します。 このようなリクエストを処理するには、ApsaraDB for MongoDBはすべてのシャードをトラバースし、クエリされたデータをマージして最終結果を返す必要があります。
たとえば、前の例のパスフィールドの値は均等に分散され、パスフィールドに基づいて多くのクエリが実行されます。 この場合、データを連続した範囲に分割するためのシャードキーとしてパスフィールドを指定できます。 この方法には次のような利点があります:
書き込み要求は各シャードに均等に分散されます。
パスフィールドに基づくクエリ要求は、1つ以上のシャードに密に分散され、クエリの効率が向上します。
ただし、この方法には次の欠点があります。
pathフィールドの値が頻繁にアクセスされる場合、同じシャードキー値を持つログは同じチャンクまたはシャードに格納される可能性があります。 値は高頻度でアクセスされ、チャンクのサイズは大きい可能性があります。
パスフィールドの値が少ない場合、シャード間でデータが不均一に分散する可能性があります。
上記の問題を修正するには、シャードキーにフィールドを追加します。 たとえば、元のシャードキーの値は {path: 1} です。 この場合、sskフィールドをシャードキーに追加できます。 新しいシャードキー値は
{path: 1, ssk: 1}
です。_idフィールドのハッシュ値など、
ssk
フィールドにランダムな値を割り当てることができます。 sskフィールドにタイムスタンプを割り当てることもできます。 この場合、同じパス値を持つシャードキー値は時間でソートされます。したがって、シャードキーには偶数の頻度で複数の値があります。 シャードキー値が極端に高い頻度ではありません。 前述の各シャーディング方法には、独自の利点とトレードオフがあります。 ビジネス要件に基づいて方法を設定できます。
データ成長のためのソリューション
ApsaraDB for MongoDBは、大量のデータを保存するシャーディング機能を提供します。 ただし、データ量が増えるとストレージコストが増加します。 ほとんどの場合、ログデータの値は時間の経過とともに減少します。 1年前または3か月前に生成された、分析には価値のないデータは、ストレージコストを削減するためにクリアする必要があります。 ApsaraDB for MongoDBでは、次のソリューションを使用してこのような要件を満たすことができます。
TTLインデックスの使用: Time to live (TTL) インデックスは、ApsaraDB for MongoDBが指定された期間後にコレクションからドキュメントを自動的に削除するために使用できる特別な単一フィールドインデックスです。 上記の例では、timeフィールドはリクエストが送信された時刻を示します。 次のコマンドを実行して、timeフィールドにTTLインデックスを作成し、ApsaraDB for MongoDBが30時間後にドキュメントを削除するように指定できます:
db.events.createIndex( { time: 1 }, { expireAfterSeconds: 108000 } )
。説明デフォルトでは、TTLインデックスを作成した後、シングルスレッドモードで記述された期限切れのドキュメントを削除するバックグラウンドタスクが60秒ごとに実行されます。 大量のログデータがApsaraDB for MongoDBに書き込まれた場合、ApsaraDB for MongoDBの多くのドキュメントは時間の経過とともに期限切れになります。 削除されない期限切れのドキュメントは、大きなストレージスペースを占有します。
上限付きコレクションの使用: 保存期間に厳密な制限がなく、保存領域を制限する場合は、上限付きコレクションを使用してログデータを保存できます。 上限付きコレクションは、上限付きコレクションの最大ストレージ容量または最大保存ドキュメント数を指定し、指定された制限のいずれかに達すると、ApsaraDB for MongoDBはコレクション内の最も古いドキュメントを自動的に削除します。 たとえば、次のコマンドを実行して、キャップ付きコレクションを作成および構成できます。db.createCollection("event", {capped: true, size: 104857600000} 。
コレクションまたはデータベースごとに定期的にドキュメントをアーカイブする: 月末に、その月のドキュメントを保存するコレクションの名前を変更し、翌月のドキュメントを保存する別のコレクションを作成できます。 年と月に関する情報をコレクション名に追加することを推奨します。 次の例は、2016の各月に書き込まれたドキュメントを格納する12のコレクションの名前を示しています。
イベント-201601 events-201602 events-201603 events-201604 .... events-201612
特定の月のドキュメントを消去する必要がある場合は、次のコマンドを実行して、対応するコレクションを直接削除できます。
db["events-201601"].drop() db["events-201602"].drop()
複数の月のドキュメントをクエリする場合、ApsaraDB for MongoDBは複数のコレクションのクエリされたデータをマージして最終結果を返す必要があるため、クエリステートメントが複雑になる場合があります。