MongoDBとGo言語で開発してみた結果と振り返り
- MongoDBを使おうとしたきっかけ
- update repleaceができない
- サブクエリができない
- isodate 難しい
- sequenceテーブルを作成する必要あり
- ちょっと便利なUpSert
- GoとMongoのDate型について
- GoとMongoのバリデーションについて
- schema validation 必須
- MongoDBのコメント機能
- インデックスサイズの検証
- インジェクションされにくい
- 処理速度VS開発速度
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を導入している現場があれば面白そうだなと思いました。
登録日:
更新日: