技術者としてとても浅い知識と解決方法だったと今思うと恥ずかしいことがとても多い。
勉強をすればするほど自分の無知の知が広がり、自分がまだまだだったということを思い知る。無知の無知をどれだけ減らせるかがこれからは重要だと思っている。
今思ったらこれはこういうふうに解決するべきだったと思うことはいっぱいあるので筆頭を書きたい。特に職務経歴書には良いことしか書いていないからなんか本当はもっといっぱい書くことあるんだけどなと思ってここに書いておく。
メモリリーク+長時間ジョブを保持しサーバーのリソース食われている問題
→これをEC2インスタンスのスケールアップで対処するという解決方法。
そもそもサーバーの性能を上げるというのは最終手段としてその前にやることはいっぱいあった。
原因はSidekiqのワーカープロセスのメモリリークと、Redisへの長期間ジョブ保持の設計が重なってリソースを食っていた。(Sidekiqというのはジョブキューのワーカープロセッサ。例えばAWS SQSと代替性がある。)
Sidekiqメモリリーク問題はそのコードの書き方や処理の仕方に問題がある。
加えて最大7日間Redisにスケジュールを保持して7日後にジョブを実行するというワーカーなど長時間Redisにジョブを保持させるような仕組みが数あった。
このような長期間スケジュールが必要なジョブは、Sidekiq ではなくバッチサーバーや専用のスケジューラーで実行する方が適切だった。ずっと使われているものに疑問を持ち、問題の原因を見極める目を持つのが本当の技術者だったと思う。
ユーザーがイベント操作をした後がやたら重い
メルカリでいう"出品ボタン"を押した後や"購入した後"、やたら待機時間があり裏で処理が完了するのを待たされるという問題。
社長やプロダクトオーナーはこういうところをよく見ていて、指摘されてすぐ解決しようとして開発者たちは浅い解決をしてしまうんじゃないかなと思う。
これはおそらく原因は出品イベントを実施した後に全ての大量の処理を同期的に処理していたから。(例えば商品のバックグラウンド配信処理やポイント計算など)
関心の分離がそもそもできておらず、"出品"という関心ごと以上のことを全て同期処理をしていたためにその処理たちが終了するまでユーザーが画面待機しているということが実際の問題だった。
それを『CDNを設置したら解決する』とか『一部リファクタリングをしたら解決する』などという間違えた方法で解決しようとしていた。(ていうか解決していない)
本質的には出品が完了したらさっさとユーザーは体感的にはすぐ終了し、その後の処理はイベント駆動型アーキテクチャでメッセージキューに非同期的に送るということで根本的には解決していたはずだ。(実はメール通知やその他些末な部分についてはSidekiqで最低限非同期化はされていた。)
パフォーマンス改善は何かツールを立てればいいと浅い経験者だと思いがちだけど、アーキテクチャにまで考えを巡らせることが大切だった。
冗長化、分散化検討の不十分さ
管理者画面からは大量のデータを参照したりCSVダウンロードしたりする。その際にアプリケーション全体の処理が重くなっているという問題を我々はWebサーバーを分けて解消した。
それ自体はまだ一歩前進だったなと思う。
これから管理者サービスとしてマイクロサービス化させるとかして好きに別言語で書き換えても良いだろう。
問題はそのあとで、すべての処理は単一のデータベースを見ており、DBのI/O処理は変わらずリソースを食い合っていたという問題がある。その辺りの問題を見ていなかった。
データベースはレプリケートし、管理者画面からの参照系のクエリはリードレプリカを読み取るように設計をしなければならなかった。
書き込み系トランザクションと読み込み系のトランザクションを分離することで、ユーザー向け処理のパフォーマンスを守ることができたはず。
なんだったら、管理者画面を操作するのは平日の昼(とか月曜日)にアクセスがバーストするのでEC2で常時動かすのではなくてコード上のモジュールを分離してコンテナ化した後、ECS+Fargateなどで使用量に応じた従量課金制の方が多分コストもより最適化されていただろう。
大層なツールを使うのはまだ早かった
要するにElasticsearchとかCloudFlareとかそこまでビジネスがスケールしていないうちからツールを使って解決しようとするもの。実はもっとビジネスがスケールしてから検討を開始するべきだっただろう。
最近のXで質問箱という単純なシステムなのにk8sを使っている形跡があったりして話題となっていた。
技術者の幼稚さというかなぜそれを使ったというような感じで、コストも嵩んでおり、履歴書駆動開発という揶揄があったりした。
ツールや最新技術を使うというのはそれが目的となってはいけないと思った。まあ検討材料として幅広く知る必要はあるが、大切なのは問題の本質を見極めるイシューだなと思っている。
サービス・関心事を分離していない
せめてBユーザーとCユーザーのログイン画面くらいは分離をしないといけなかったけど、そのログインが一緒だった。つまり、ユーザーのjobだかroleだかのカラムでBかCを判断しているというものだった。(まあ最初のスタートアップの立ち上げ期が過ぎてからここを変えようというのが最初の開発者たちの考えだったんだろうけど、、そのもうちょっと余裕ができるステージが全然来なかった。)
これはサブドメインでサービスを完全に区別するなどして内部のバックエンドやチームをうまく分担することが今思うと大切な取り組みだったなと思う。
ドキュメントを整備すれば良かったけど全然自分たちも整備していなかった
以前の担当者たちが全員辞めてしまって新しく入った開発者メンバーたちで担当をしたけどドキュメントが古いという問題があった。それは自分たちでまた最初から作り直すなどしてスタートは遅くなるがそうする時間は必要だったなと思った。
なぜならその後に入ってくる開発者たちにも同じように口頭で説明をしたり、自分たちでリバースエンジニアリングをして同じ道を辿ってもらわなければならないからだ。
ADR(Architecture Decision Record)→アーキテクチャがなぜそのようになっているかを知るした仕様書を書く。
ドメイン仕様書→主要な機能やドメインの仕様書は自分たちのリバースエンジニアリングをした結果としても記したい。
手順書→多分これはせめて書いている人やチームは多いと思う。気にせず、変わった部分があれば常に最新にしておくのがよい。