僕はサーバーサイドのビジネスロジックの書き方について、メモリに全データを載せておいたほうがいいのでは、と考えています。
理由
クエリを書いたりキャッシュを設計したりするのがめんどくさいからです。もちろん僕は、SQLを書いたりキャッシュを設計したりすることができます。おそらくどちらかといえば上手な方だと思います。しかし、自分がやらなければいけない仕事がたくさんある中で、あまりそれに時間を使いたくないということがあります。
とりわけ、最近はパフォーマンスのためにKVSを組み合わせることが多くなりました。キャッシュ目的のKVSを設計するのは大変です。
- そのデータがどう使われるのか
- どのタイミングで更新されうるのか
- マイグレーションはどうするのか
を考えぬいて正確に設計しなければいけません。
パフォーマンスのために開発時間が余計にかかることはよくあります。素朴に実装していいなら30分で終わるけどパフォーマンスのために色々キャッシュを設計して書いたので2時間かかったりします。
それであれば、お金はかかるもののメモリをいっぱい積んでいるインスタンスを借りて、ビジネスロジックに必要なデータは全部インメモリに載せておくのが一番ラクなのではと思いました。
文脈
オンラインゲームではそれをやってるらしいです。
DBにはライトスルー方式で書き込んでいるそうです。
https://www.amazon.co.jp/dp/4774145807
これを見てWebアプリケーションもそうすればいいのではないかと思いました。
メリット
- DBからデータを取ってくる部分のコードを減らせる
- パフォーマンスのために複雑なコードを書かなくて良くなる
- テストコードを簡単に書ける
デメリット
- メモリがたくさん必要でお金がかかる
- そもそも一定以上の大規模サービスでは不可能
- 本番環境のインスタンスの立ち上げに時間がかかる
実現方法
複数インスタンスをどうやって同期するか
RDBのレプリケーションのプロトコルを喋れればいいかなと思います。
バイナリログをListenするのがもっと簡単かもしれません。
Firebaseという手もあると思います。
どんなコードになるのか
サーバーのAPIは純粋関数になります。
引数はHTTPリクエストとRDB上の全データです。
このデータはImmutableです。
戻り値はHTTPレスポンスとRDBへの更新命令です。
フレームワークはDBへの変更を監視し、常に手元の変数を更新します。
HTTPリクエストが来たら関数を適用し、戻り値を得ます。
まずはDBに対して更新を試みます。
成功したらHTTPレスポンスをブラウザに返します。
パフォーマンスは大丈夫なのか
メモリ量については、大半のWebアプリにとっては大丈夫だと思います。
大半のWebアプリは数十GB以内で済むのではないかと思います。
CPUもそこそこ大丈夫ではないかと思います。
Go言語で100万件の中からFor文で条件に合う数件を抽出するコードは、だいたい数十msくらいだと思います。
将来はいろんな自動最適化が出来るようになると思っています。
更に
フロントエンドプログラミングとされているものも、サーバーに置けるかもしれません。
RDBのデータを全部インメモリで持っておくなら、フロントエンドのステートもサーバーのメモリに持っていてもいい気がします。
うまいこと楽観的UIを透過的に扱う方法があれば、これが一番ラクだと思います。
DOMベースでUIをサーバーから更新するのか、あるいはブラウザのCanvasに映像を流すのか、どちらも可能だと思います。後者は楽観的UIと相性が悪そうな気がなんとなくするのと、ドキュメントののセマンティクスが失われるので、あまり気分は良くないです。
いつからやるの?
僕は、趣味の開発を除けば、そういうのがベストプラクティスとして確立するまではやらないです。
でも、そのうちそういうフレームワークが出てきてこなれてくると思います。そうしたら始めます。