Posts for: #Mongodb

一日中リファクタリング

0時に寝て7時に起きた。昨日は夜にホテルで作業しようと思いながらテレビをみているうちに寝落ちしてた。朝から夜までずっとリファクタリングのためにコードを書いたり、コンテナ環境の設定を変更したりしていた。

mongodb のコネクションプール

MongoDB Drivers の Connection Example に次のようなことが書いてある。

Reuse Your Client

We recommend that you reuse your client across sessions and operations. You can use the same Client instance to perform multiple tasks, instead of creating a new one each time. The Client type is safe for concurrent use by multiple goroutines. To learn more about how connection pools work in the driver, see the FAQ page.

mongodb drivers の client は goroutine safe なので再利用することを推奨している。内部的にはコネクションプールをもっていて mongodb とのコネクションを再利用できる。具体的にはライブラリ内部に次のようなコードがみつかる。context にセッション情報があればそれを使い、なければクライアントの sessionPool (コネクションプール) を使ってセッションを取得して mongodb にアクセスする関数の終わりで終了処理を行う。

sess := sessionFromContext(ctx)
if sess == nil && coll.client.sessionPool != nil {
	sess = session.NewImplicitClientSession(coll.client.sessionPool, coll.client.id)
	defer sess.EndSession()
}

既存のコードはコネクションプールのことを考慮していないコードになっていたので大きくリファクタリングして効率化した。

docker hub の pull 制限

午前中はリファクタリング、午後は docker compose 環境の変更と再構築、午後はバグ修正と一日中 docker image を取得する作業をしていた。gitlab ci/cd が動くとテストと docker image 生成の処理が動くのでその過程で関連する docker image を pull する。夕方になって gitlab ci/cd で初めて次のエラーが発生することに気付いた。前にお手伝いしていた職場でもそういう現象が起こると聞いて、docker login するコードを github actions のスクリプトに追加していたので、rate limit がかかることは知っていた。

You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits.

Understanding Your Docker Hub Rate Limit によると、6時間あたり匿名アクセスは100、 free ユーザーは200を上限としているらしい。匿名アクセスは ip アドレスでカウントしているのだろうから場合によっては会社内からのアクセスをすべてカウントされたりするかもしれない。課金するとこの上限が24時間あたり5000になる。docker hub のプライベートリポジトリを利用する意図で team プランの課金を検討していたが、docker hub のアクセス制限を緩和するために課金する必要があるかもしれない。

mongodb のトランザクションの考え方

1時に寝て8時に起きた。3時頃に気分悪くて起きて少し吐いてそれからまた寝た。丸1日機能拡張とリファクタリングのために go のコードを書いていた。

mongodb のトランザクション管理

2つの web api から同じコレクションの異なるフィールドを更新したい。mongodb で厳密なトランザクションを管理するようなアプリケーションではないけど、なるべく整合性を維持できるように努めることはやっておきたい。mongodb でトランザクションに近いことを実現する方法として次の記事が参考になった。

この記事では findOneAndUpdate() という api を使って、更新時に必ず変更されるフィールドを含めることで find したときのそのフィールドの値が変わっていればエラーになってくれることでトランザクション相当の機能が提供されると書いてある。必ず変更されるフィールドとして ObjectId を使えば他の更新処理を検出するのに役立つだろうとある。いま私が開発しているアプリケーションでは同じフィールドを複数の web api から更新するわけではないのでここまで厳密なトランザクション管理は必要にない。

既存の処理が Replace を使って実装されていたのを Update を使うように変更する。Replace と Update の違いはドキュメント全体を更新するのか、一部のフィールドのみを更新するのかの違いになる。具体的には go のドライバーにおいて次のメソッドの使い分けになる。

これらのメソッドを使うことで find と replace/update の操作を1回の処理でできるから効率もよいらしい。

mongodb の view 調査

4時半に寝て11時に起きた。午後から go のコードをリファクタリングしてた。平日はメンバーの issue を監視して困ってたらコメントしたり、マージリクエストをレビューしたり、管理画面の振る舞いを検証したりと、コードを書いていても途中で作業がちょくちょく中断する。休日にコードを書くとその中断がない分、いつもよりかなり捗った。リファクタリングに思いの外、時間を取られている気がしたのはそのせいもあるか。

mongodb の view 作成

実はこれまで mongodb を扱ったことがなくて今回初めて触っている。とくに難しくもないのだけど、ドキュメントを探してやりたいことを調べたり、デバッグや開発のためのツールとしてどういうものがあるかといった知見がない。ないものは仕方ないので1からドキュメントを読みながら開発というか、リファクタリングをしている。mongodb そのものの知見はなくても、様々なデータベースを操作する開発をしてきたのでやりたいことに対して実装方法はいくつか検討がつくし、その実装を支援するための機能もあるはずだと予測がつくので探すのも早い。

ある collection から複数のデータ構造のレスポンスを返すような処理がある。こういったものは view を使うとうまく整理できると知っているので調べると mongodb view が提供されていることがわかる。3.4 から追加されたらしい。いまクエリの中で aggregation pipeline を書いている処理のいくつかは、あらかじめ view を定義してクエリすることでインフラ層を堅牢にした上で実装もシンプルにできる。さらに 4.2 から on-demand materialized view が追加されていて、標準の view と比較して aggregation pipeline の計算結果をディスクに保持するのでパフォーマンス上のメリットがある。元データの更新が頻繁でなければ on-demand を使った方がよいのだろうと推測する。

またこれまで mongodb の管理画面に mongo-express を使っている。view の振る舞いを確認しようとしたところ、どうも view には対応していないようにみえる。web ベースの管理画面を他にも探してみたが、どうも他に適当なものがない。mongodb が公式に compass というデスクトップアプリケーションの gui クライアントを提供している。macos なら brew からインストールできた。

> brew install mongodb-compass

このツールは collection も view も両方扱えるし、クエリやパイプラインも実行できて機能も充実している。web ベースじゃないとインフラとして共有はできないところだけが残念なところ。それでも開発する上ではとても強力なツールにみえる。適当にデータをインポートしたり、テストで aggregation pipeline を作成してみて、それをエクスポートして view を生成するときのスキーマ定義も作ることができた。ui も洗練していて、こんな優れたデスクトップアプリケーションは久しぶりにみたと思うぐらい感心した。