SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

EnterpriseZine(エンタープライズジン)編集部では、情報システム担当、セキュリティ担当の方々向けに、EnterpriseZine Day、Security Online Day、DataTechという、3つのイベントを開催しております。それぞれ編集部独自の切り口で、業界トレンドや最新事例を網羅。最新の動向を知ることができる場として、好評を得ています。

最新イベントはこちら!

Data Tech 2024

2024年11月21日(木)オンライン開催

EnterpriseZine(エンタープライズジン)編集部では、情報システム担当、セキュリティ担当の方々向けの講座「EnterpriseZine Academy」や、すべてのITパーソンに向けた「新エバンジェリスト養成講座」などの講座を企画しています。EnterpriseZine編集部ならではの切り口・企画・講師セレクトで、明日を担うIT人材の育成をミッションに展開しております。

お申し込み受付中!

EnterpriseZine(エンタープライズジン)

EnterpriseZine編集部が最旬ITトピックの深層に迫る。ここでしか読めない、エンタープライズITの最新トピックをお届けします。

『EnterpriseZine Press』

2024年秋号(EnterpriseZine Press 2024 Autumn)特集「生成AI時代に考える“真のDX人材育成”──『スキル策定』『実践』2つの観点で紐解く」

脱初心者!MongoDB中級編

MongoDBの高可用構成(後編)

 本連載では、前回と今回の二回にわたって高可用構成について説明します。前回は、どのように高可用構成を組めばよいか説明しました。今回はレプリケーションでよくある問題ということで、レプリケーション遅延が発生する理由と、遅延から発生する「oplog溢れによるレプリケーション不能」および「プライマリ故障によるデータ不整合」という二つの問題について説明します。

 レプリケーションの動作やoplogがよく理解できていない方は、本連載のレプリケーションにおける読み取り負荷分散の性能を先に読むことをお勧めします。

レプリケーション遅延

 MongoDBのレプリケーションにおいて最もよくある問題はレプリケーションの遅延でしょう。通常セカンダリはロングポーリングという手法を使い、プライマリのoplogが更新されると即座に自身にoplogを適用します。しかし、何かの理由によりoplogを即座に適用できないと、レプリケーション遅延(Replication Lag)になります。

 レプリケーション遅延が発生すると、以下のような問題が発生する可能性があるため、放っておくのはよくありません。

  •  セカンダリ読み込みにより読み込んだデータが古い
  •  プライマリ故障時に新しいプライマリの選出が遅くなり、書き込み停止時間が延びる
  •  プライマリ故障時にデータの不整合が発生する
  •  oplogが溢れるとレプリケーションが停止し、システムの可用性が低下する

 レプリケーション遅延が発生する理由として、分かりやすいものは「ネットワークが輻輳し始めた」、「リクエストが増えた」、「セカンダリが稼働しているサーバで、MongoDB以外のプロセスがリソースを消費し始めた」などの外的要因でしょう。これはシステムの状況を観測していれば検知できますし、対策も簡単でしょう。

 一方、外的要因は無いのに突如レプリケーション遅延が発生する場合があります。多くの場合、これはoplogの容量が想定より大きくなって処理しきれなくなっていることが原因です。実はクエリの量は必ずしもoplogの量とは一致しないのです。

oplogの肥大化

 oplogが肥大化するメカニズムについて説明していきましょう。通常、クエリの内容とoplogの内容は一致しています。例えばMongoDBで以下のinsertを実行したとします。

db.mycol.insert({a:1})

 するとoplogには以下のようにaの値を1にするように記載されます。

{ "ts" .... "o" : { "_id" : ObjectId("xxe8"), "a" : 1 } }

 次にupdateはどうでしょうか?

db.hoge.updateMany({},{$set : {a:1}})

 すると、クエリの数は一つですが、以下の様にoplogにはコレクション内の全ドキュメントに対する更新が1件ずつ記録されました。

{ "ts" ... "o2" : { "_id" : ObjectId("xxe9") }, "o" : { "$set" : { "a" : 1 } } }
{ "ts" ... "o2" : { "_id" : ObjectId("xxe1") }, "o" : { "$set" : { "a" : 1 } } }
{ "ts" ... "o2" : { "_id" : ObjectId("xxf8") }, "o" : { "$set" : { "a" : 1 } } }
・・・

 これは、MongoDBが複数のドキュメントを整合性をもって更新するトランザクションを提供していないためです。一回のクエリで更新できるのは一つのドキュメントですので、一つの更新クエリは、コレクション内の全てのドキュメントに対する更新クエリに変換されます。これはremoveでも同じことが起きます。このように、単純にクエリの量だけを考えているとoplogの数とは合わないため注意が必要です。

 更新や削除は少し考えれば肥大化することがわかりますが、意外なクエリもあります。例えば、配列の先頭を取り出す$popや、配列の要素を検索して削除する$pull等です。これらのクエリは、更新するデータの量とは関係なく配列の全データをoplogに記録します。配列が10MByteあれば10MByte分oplogに記録されます。

 実際に動作を見てみましょう。例えば、以下の例では配列から3を検索して削除しています。

db.hoge.insert({ary:[1,2,3,4,5]})
db.hoge.updateMany({},{$pull:{ary:3}})

 すると、以下の様にoplogには新しい配列全て([1,2,4,5])が記録されてしまいます。

{ "ts" ... "o2" : { "_id" : ObjectId("xxxx") }, "o" : { "$set" : { "ary" : [ 1, 2, 4, 5 ] } } }

 こうなってしまう理由は、oplogが何度適用しても結果が変わらない性質(冪等性)を備えているためです。配列の$popや$pullは複数回実行すると結果が異なってしまうため、冪等な操作にするため新しい配列で上書きするクエリに書き換えています。これを知らずに巨大な配列に対して$popや$pullを利用すると、oplogが予想以上に肥大化し、レプリケーションの遅延を招きます。ただし、配列の末尾に要素を追加する$pushはoplogの肥大化を引き起こしません。$pushは配列の長さと新しい要素だけが記録されます。

次のページ
oplog溢れによるレプリケーションの停止

この記事は参考になりましたか?

  • Facebook
  • X
  • Pocket
  • note
脱初心者!MongoDB中級編連載記事一覧

もっと読む

この記事の著者

渡部徹太郎(ワタナベテツタロウ)

 日本MongoDBユーザ会所属 2012年からMongoDB勉強会開催、記事執筆、セミナ講演を精力的に実施。仕事でもMongoDBのトレーニングやコンサルティングを実施。日本で一番MongoDBを情報発信していると自負している。現在はWeb企業でビッグデータ基盤のエンジニアをしている。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

EnterpriseZine(エンタープライズジン)
https://enterprisezine.jp/article/detail/8095 2016/06/02 06:00

Job Board

AD

おすすめ

アクセスランキング

アクセスランキング

イベント

EnterpriseZine(エンタープライズジン)編集部では、情報システム担当、セキュリティ担当の方々向けに、EnterpriseZine Day、Security Online Day、DataTechという、3つのイベントを開催しております。それぞれ編集部独自の切り口で、業界トレンドや最新事例を網羅。最新の動向を知ることができる場として、好評を得ています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング