🏠 ホーム
プログラミング
インフラ
フリーランスCTO
DB
完全無料ツールまとめ
マーケティング

MongoDBとGo言語で開発してみた結果と振り返り

  DB >  

MongoDBを使おうとしたきっかけ

elasticSearch, Dynamodbなどをキャッシュ代わりに利用している現場は多かったです。

それらの全文検索系のDBよりも高機能なMongoDBであればキャッシュ代わりではなくそのままメインDBとして使えるのではと思いました。

その上、キャッシュ並みのパフォーマンスを実現できれば、運用コストを抑えながらシンプルなシステム構成が実現できるのではと思いました。

なので、PostgresからMongoDBにメインDBを思い切って切り替える事にしました

他のDBのパフォーマンスがどれくらいかググってた時にMongoDBが意外にパフォーマンスが良かった事を思い出した事もきっかけの一つです。

その事もあり、MongoDBはもしかして最強?って期待をしていました。

改めて、今MongoDBのパフォーマンスを比較すると

1千万件の検証でMySQLで17秒、MongoDBで2秒

この差は魅力的かと思います。

[Python]MongoDBとMySQL比較検証 | pixelbeat sandbox

インデックスがメモリ上にあるので、高速検索が実現できるみたいです。

solr, elasticSearchもインデックスがメモリ上保存されるみたいです。

しかし、MongoDBはsolr, elasticSearchに比べれば高機能, CRUDという所がメリットです。

memcached, redisはインデックスだけじゃなくてデータ全てをメモリに保存するのでMongoDBなどよりも高速

しかし、メモリ消費の効率が悪く、消費が大きいので、コストも高くなってきます。

こういう前提の知識からMongoDBへの移行を始めました。

実際に移行するにあたっての開発でのハマりどころや、デメリットと感じる所、メリットと感じる些細な部分を取り上げました。

update repleaceができない

RDBのSQLのUpdate repleaceができない
 ⇨ replaceOneがあるのでこれを利用してバッチを作るしかない

JOINが出来ないとか、SQLで出来てMongoでできない事は多いと思ってました。

ブログのテキストの置換を一括でと思ってましたが、SQLみたいに簡単には無理でした。

これがその中の一つです。

こういう場合はバッチを作ってデータ修正するしかなさそうです。

とほほ。


サブクエリができない

純粋な代替手段はないです。

Aggregateを利用して、実現は可能かもですが、バッチを作りました。

 

isodate 難しい

DateTime型で保存する場合、UTCが前提

どうせならUTCとかのタイムゾーンがなければやりやすいのに

タイムゾーンなしもできないですし、UTCのタイムゾーンの設定も変更が難しい。

運用を考えて、常にイギリスの時間帯でデータが保存されるのでMongoでの時間確認や日を跨ぐような検索方法だとバグりやすくなるなぁっと思いました。

 

sequenceテーブルを作成する必要あり

これはPostgresにあってMySQLにない部分でもあります。

ラッキーな事にCounterの機能がMongoにはあったので、それでカウントアップの更新はできます。

 

ちょっと便利なUpSert

UpSertはあれば更新、なければ登録の便利なクエリ。

まぁ、ORMっぽいのでそこまで感動はないけども

ちょっと便利くらいで使える場面で使っていくというだけの話

 

GoとMongoのDate型について

Date型はtime.now()だけでmongoに登録可能。

(YYYY-MM-DD H:i:s)のフォーマットにして文字列にしなくてもいいのでGoプログラミングとの相性は良さげ

フォーマットされた文字列をmongoに入れると当然string型になってしまった。

なので、ググったらprimitiveを使えって記載がありそれを信じてprimitive使うところだった。

嘘を信じずにtime.now()だけで登録試していてよかった〜。

また、ググった情報の偽情報。。。とほほ。。

 

GoとMongoのバリデーションについて

Date型に関してもgoとmongoは相性がいいという話でしたけど、バリデーションに関しても相性がいいかと思います。

coll := client.Database("db").Collection("books")
doc := Book{Title: "Atonement", Author: "Ian McEwan"}

result, err := coll.InsertOne(context.TODO(), doc)

fmt.Printf("Inserted document with _id: %v\n", result.InsertedID)

このように登録する時も型付けしないと登録できないため、必然的にGoの静的型付けの構造化が型チェックなどのバリデーションをしてくれます

しかし、文字数などのバリデーション機能がGoの構造化にはないです。

型チェックのみなので、構造化をバリデーションとして使うという分には少し物足りないです。

後述するschema validationが絶対必要という理由を一つ潰した事にはなります

schema validationを作るとなると面倒なので、ケースバイケースかなぁ。。

 

schema validation 必須

RDBでは型を決めてそれに合わないデータが登録されればエラーになるという当たり前の事です

しかし、MongoDBはスキーマレスなのでそもそもスキーマを定義する必要がないままあらゆるデータの登録が可能です

一見メリットのように感じますが、これもバグりやすい要因になり得るかと思います。

例としては、int型で入れるつもりの項目に'9'とかと数字の9を入れたつもりが文字列としての9で登録されるって事でバグりそうです。

前述のMongoとGoは相性がいいのセクションで説明している通りInsertは型を決めないと登録できないので、Goの型付けがschema validationの代わりを担ってくれています。

しかし、InsertのみでUpSertとかは型を決めなくてもできてしまうので、Goの静的型付けが100%カバーできるようにはなってないです。

なので、ちゃんとした運用をする場合はschema validationは必須かと思います。

 

MongoDBのコメント機能

コレクション(テーブル)、フィールド(カラム)に対してのコメントの記載がしづらい、もしくはできない

これは大きなデメリットです。

NoSQLなのでフィールドに対してコメントできないのは理解できますが、コレクションへのコメントができないとなると、リポジトリでヴァージョン管理するとかしないです。

ドキュメントで管理するとどうしても本番で運用しているものとの乖離が出てくるので、できればDBと近い部分でのコメントがあればと思います。

これもどこかの記事ではschema validationにコメントしていると回答している人がいました。

やはり、ちゃんとした運用をしようとした場合schema validationを作成して、そこにコメントも記載するという事がベストかな

 

インデックスサイズの検証

前提として、question_idは5桁ぐらいの数字です。

件数は10万件もいってないです。

shikaku> db.answer.totalIndexSize()
430080
shikaku> db.answer.createIndex(
      {
          "question_id": 1
      },
      {
          name: "question_id"
      }
    )
question_id
shikaku> db.answer.totalIndexSize()
704512

インデックス追加して、増えましたよってだけの話です。

件数も少ないので、300KB増えたぐらいです。

ググった情報よりもメモリがガンガン消費されるって程でもなさそう。

もちろんケースバイケースだと思いますが。

MongoDBでは複合主キーが使えないので、使わない_idにもメモリを消費してしまう事が判明。

10億件で最低でも32GB消費するらしい。

 

インジェクションされにくい

$where — MongoDB Manualのオペレータを使うとインジェクションされるとの事ですが、あまりこのオペレータを使う事はなかったので、RDBMSに比べればインジェクションされにくいのではと思います。

とはいえ100%防いでるわけではないのでコードレビューや規則を作る事を省いてもいいって事にはならないですね。

処理速度VS開発速度

RDBMSと比べて開発速度はMongoDBの方が圧倒的に遅い

使えるエンジニアの人数が少なくて、ドキュメントの量も多くないのでほとんどのエンジニアが慣れていないので取り掛かりにどうしても時間がかかってしまいます。

使っていくうちに慣れて来たとしても、どうしてもSQLほど高機能ではないので、開発中のデータ更新なども結構時間がかかってしまいます。

MongoDBにだいぶ慣れたとしてもRDBMSと比べると2、3割は開発スピードは遅くなるんじゃないかという肌感です。

改めてSQLって高機能なんだなって思いさせられます。

しかしながら、それでもMongoDBがいいという理由は冒頭の比較検証ページの速度に優位性があるというこの1点

DBの処理の速度が早ければもちろんページ表示の速度も上がり、負荷も軽減できます。

負荷も軽減できれば、それだけサーバー費用も抑えられるという事になります。

OLTP環境では処理の速度はそれだけ大事かなと思います。

多くのデメリットやリスクを抱えているのに、処理速度が速いというただ1点でMongoDBを導入している現場があれば面白そうだなと思いました。

 

登録日:

更新日:

by

コメント         tweetでコメント