Tomorrow Will Be A Better Day

Published

- 5 min read

MongoDBのShard Key設計を失敗したため、そのリカバリにたいへん手間取ったメモ

img of MongoDBのShard Key設計を失敗したため、そのリカバリにたいへん手間取ったメモ

年末年始の休暇を挟み、MongoDBサーバのディスクが溢れそうになっていたので、 「そろそろShard増やすか」と思ったら、思いの外うまいこといかなかったのでメモ。

【今回のトラブル】 AWS上にある、約1TBのMongoDBサーバ(m2.4xlarge×3台/Shard6個)のディスク容量が残り10%を切ったので、 新しいMongoDBサーバ(m2.4xlarge×3台/Shard6個)を追加しようとしたけど、データが全く移動できなくなった。

【現象】

  1. 新しく追加したShardへ、既存データが入っているChunkを移動さえしようとするも失敗
   mongos> db.adminCommand({moveChunk : "hoge.fuga", find : {hourint : 4}, to : "new_shard"})
   {
	"cause": {
		"chunkTooBig": true,
		"estimatedChunkSize": 14634166876,
		"errmsg": "chunk too big to move",
		"ok": 0
	},
	"ok": 0,
	"errmsg": "move failed"
}
  1. 「おや?」と思い、chunksizeを “estimatedChunkSize”以上に変更。
   mongos>db.settings.update({_id:"chunksize"},{$set:{value:16000}})
mongos>db.settings.find()
   {
	"_id": "chunksize",
	"value": 16000
}
  1. Configとmongosを立ち上げ直して、moveChunkを実行したが途中で失敗
   mongos> db.adminCommand({moveChunk : "hoge.fuga", find : {hourint : 4}, to : "new_shard"})
   {
  "cause" : {
    "cause" : {
      "active" : false,
      "ns" : "hoge.fuga",
      "from" : "old_shard/【ホストA】,【ホストB】,【ホストC】",
      "min" : {
        "hourint" : 4
      },
      "max" : {
        "hourint" : 5
      },
      "state" : "fail",
      "errmsg" : "_migrateClone failed: {
        assertion: \"BufBuilder grow() > 64MB\",
        assertionCode: 13548,
        errmsg: \"db assertion failure\", ok: 0.0
      }",
      "counts" : {
        "cloned" : NumberLong(0),
        "clonedBytes" : NumberLong(0),
        "catchup" : NumberLong(0),
        "steady" : NumberLong(0)
      },
      "ok" : 1
    },
    "errmsg" : "data transfer error",
    "ok" : 0
  },
  "ok" : 0,"errmsg" : "move failed"
}
  1. どうにもこうにもChunkが動かないので、Chunkの分割を試みる。
   mongos> db.adminCommand( { split : “hoge.fuga” , find : { hourint : 4 } } )
{ “cause” : { }, “ok” : 0, “errmsg” : “split failed” }

Sun Jan  8 15:29:34 [conn66] splitting: hoge.fuga  shard: ns:hoge.fuga at: old_shard:old_shard/【ホストA】,【ホストB】,【ホストC】 lastmod: 7|0 min: { hourint: 4.0 } max: { hourint: 5.0 }
Sun Jan  8 15:29:36 [conn66] want to split chunk, but can’t find split point chunk ns:hoge.fuga at: old_shard:old_shard/【ホストA】,【ホストB】,【ホストC】 lastmod: 7|0 min: { hourint: 4.0 } max: { hourint: 5.0 } got:

…….やっぱ駄目。\(^o^)/オワタ

【原因】
MongoDBを触っている勘のいい方なら、ログの時点でわかりそうですが、
今回のShard Keyの設定は、「hourint」つまり、時刻フィールドでShard Keyを設定し、24個のShardで運用しようと試みてしまっていました。

【参考】
昨年の発表資料

そのため、

  • a.ドキュメントが時刻フィールドで偏る(日中のドキュメントが多い)
  • b.MongoDBがChunkを分割しようにも、Chunkを分割できない
    • 1Chunkの中には、ある特定時間帯のドキュメントしかないので、Chunkをsplitできない

【結論】
今回のようなChunkが肥大化してしまう事例は、MongoDBのShardKeyを複合Keyで設定していれば回避できた事例でした。
そのため、「”app”,”userid”,”dateint”,”hourint”」の複合ShardKeyで、コレクションを再作成することにしました。
私の場合、コレクションのIndexは複合Keyで運用していたのですが、
ShardKeyも複合Keyで設定できることを知らなかったのが敗因でした(´Д`)
ということで、mongosからmongodumpを実行し、新年からコレクションの再作成を行うというリカバリを行うハメになりました。
しかも、mongos経由でバックアップを行っても、1MBpsecしか出ないので、ほぼ1週間ダンプ待ちの状態になりました。

MongoDBのShard Keyを設定する際は、Chunkが肥大化しないような設計を心がけましょう!!