はじめに
こんにちは!enechainでプロダクト開発部の部長を務める長谷川です。 enechainは2024年10月9日にeSquare Liveという電力卸取引のオンライン取引マーケットプレイスをローンチしました。
eSquare Liveは、簡単に言うと株取引で利用するような板画面上で電力の卸取引ができるプラットフォームです。 電力のトレーダーは、このプラットフォームを使って現物も先物もリアルタイムに取引ができます。
ビジネスの詳細はプレスリリースに譲るとして、この記事ではeSquare Liveの開発について紹介します。 eSquare Liveはenechainが今まで培ってきたアセットを活かし、株取引では考えられないくらい小さいチーム、期間で開発されました。 そんなeSquare Liveのオープンまでの約1年間の開発の裏側を、技術的な視点からお話しします。
eSquare Liveの特徴
eSquare Liveのビジネス要件には以下のような特徴がありました。
- リアルタイムに全ての取引参加者の画面に注文や約定が反映される
- 自動で約定させるためのマッチングエンジンがある
- トレーダー、ブローカー、市場運営者の3つのユーザーロールがある
リアルタイム取引
株取引に慣れ親しんだ方ならわかるかもしれませんが、流動性がある(= 取引量が多い)商品は毎秒注文が入って画面は目まぐるしく変化します。 電力は株ほど多くの注文が入ることはありませんが、毎秒数件以上の注文が入ることを想定してシステムを設計する必要がありました。
また、株取引では機関投資家はAPI経由でアルゴリズム注文をすることが一般的となっており、電力では今後そのような世界がくるかはわかりませんが、実現した場合は多くのトラフィックをさばかなければなりません。
自動で約定するマッチングエンジン
これも株取引では当たり前のことですが、入れた注文の価格がマッチした場合、自動で約定する必要があります。 簡単なように聞こえるのですが、注文を入れてくれた順番を保証するために、マッチング処理は商品ごとに必ずシングルラインで行う必要があります。 先に注文を入れていたのに、アクセスしたサーバーの混み具合によって追い抜かされてしまうということは防がなければいけません。
このマッチングエンジンは最もボトルネックになりやすい部分であり、どんな責務を持たせるのか、何を非同期で処理できるのかをビジネス面・技術面の両面から検討する必要がありました。
3種類の画面を作る必要性
マーケットに直接注文を入れる「トレーダー」、トレーダーから注文を預かって取引の仲介をする「ブローカー」、マーケットを運営する「市場運営者」の3つのユーザーロールがあります。 トレーダーとブローカーはほとんど同じ画面を使いますが、色々な箇所やデータ構造が微妙に異なってきます。 3つの画面を作るというのは非常に大変です。
これらの条件を踏まえて、eSquare Liveの開発に取り組みました。
爆速開発スピードと品質を両立したeSquare Liveのエンジニアリング
eSquare Liveは、2023年12月開発開始し、2024年10月リリースする必要があり、その達成にはenechain全体の総力戦となりました。 各チームの協力がなければ、短期間で高品質なサービスを提供することはできませんでした。 具体的には、以下のチームが重要な役割を果たしました。
- Application Platform:認証認可の仕組み、ユーザー管理画面
- Platform、SRE:インフラ構築やSLOの仕組み構築
- Data Platform:データの収集、ダッシュボードの構築
- Data Science:電力価格指標の提供
- Design:デザインシステムの提供
- eClear:クリアリング機能の提供
- QA、Security:リリース前の品質、セキュリティチェック
もともと全てが整っていたわけではありません。 このeSquare Liveのリリースに向けて、各チームが同じ目標に向かって突き進んだからこそ、短期間で高い品質かつユーザー満足度の高いプロダクトの提供が可能となりました。
技術的なOverview
ここからは、その中での技術的な挑戦と解決策について紹介します。
主な技術スタック
eSquare Liveで利用されている主な技術スタックは以下のとおりです。
- バックエンド
- Go / gRPC / gorm
- TypeScript / NestJS / Socket.IO
- Google Cloud (GKE, Cloud SQL for PostgreSQLなど)
- フロントエンド
- React / TypeScript
- Tanstack Query / Router
- gRPC-web
- Chakra UI
enechainでは、新しいプロダクトを開発する際には、大きな理由がない限り、バックエンドはGo、フロントエンドはReactを利用するようにしています。 後述しますが、リアルタイム配信のためにSocket.IOを利用しています。
「絶妙に妥協」したアーキテクチャ
eSquare Liveのアーキテクチャは、大まか以下のようになっています。
このアーキテクチャで最も頭を悩ませて決めたことはPub/Subベースにしたことです。 開発当初、株取引やビットコイン取引所のシステムについて調査をしていると、DBやキューにはなるべく書き込まず、オンメモリで実装する事例が多数見られました。 オープンソースでAeronのような高速なトレーディングシステムを構築するためのソフトウェアもあり、様々な事例を見つけられました。
しかし、オンメモリや複雑なアーキテクチャを選択してしまうと高速になる一方で、不整合や頑健性における不安がありました。 電力は株やビットコインとは異なり、流動性が低いという特徴があるため、Pub/Subを経由しても十分に捌ける可能性は高いという見立てはありました。 これは私自身、数百万MAUがいるチャットサービスをRedisをキューとして利用して開発・運用していた経験も大きかったと思います。 もちろん理想を追い求めて高速なアーキテクチャを採用するという選択肢もありますが、それは少なくとも直近は必要ないのではないか、いわゆるオーバーエンジニアリングではないかという議論を経て結論を出しました。
また、ストリーミングはWorkerからイベントを受け取って、それをクライアントに配信するという役割を担っています。 一方向の通信となるため、gRPC Streamingも候補にはあがったのですが、Socket.IOのadapterを使うとほとんど実装せずともやりたいことが実現できたため、最終的にはSocket.IOを採用しています。 Node.js側にロジックを持ってしまうとGoと重複してしまうため、なるべくロジックをもたないシンプルさを意識しています。ここもまた妥協ポイントです。
3種類の画面あるという問題に対しては「トレーダー」と「ブローカー」で同じような画面、ユースケースになるため、gRPCのprotoはわけつつもできる限りロジックを共通化、Reactのコンポーネントもできる限り共通化するように意識しました。
このように開発体制、開発期間において制限がある中で、いくつもの「絶妙に妥協」した意思決定をし、要求を満たしたプロダクトを開発していきました。
monorepo
eSquare Liveではmonorepoを採用しています。monorepoは、バックエンドやフロントエンドなど、システムを構成する複数のコンポーネントの独立性を保ちつつ、全てのコンポーネントをひとつのリポジトリで管理する手法です。
ディレクトリ構成は以下のようになっており、言語毎にビルドしやすいようにわけられています。
eSquare Liveの開発チームはReactもGoも書くメンバーが多かったため、monorepoの恩恵を受けやすかったように思います。また、protoが共有されているのもメリットの1つです。
k6を利用した負荷試験
安定したプロダクトを提供するため、リリース前には負荷試験を実施しました。 JMeterなど他のツールも検討しましたが、JMeterはUIが辛いなど色々議論をして、今回はk6を採用しています。
最初は本来欲しかったパフォーマンスの1/1000くらいしか達成できませんでしたが、チューニングを重ねることで、最終的には大幅に改善させることができました。 大きく改善に寄与したポイントは以下となります。
- キャッシュを使って、他マイクロサービスとの通信を減らす
- インメモリキャッシュのロックの調整
- DBやPod数のリソース調整
- DBコネクション数のチューニング
特にDBコネクション数のチューニングは効果が大きく、DBリソースに合わせてコネクションプールの大きさを適切にすること、SetMaxOpenConns
と SetMaxIdleConns
は同じ値を設定することで、不要なコネクションの再接続が起きないようにしています。
また、負荷試験を通じてアーキテクチャに関しておこなった「絶妙に妥協」した決断が正しかったことを確認できました。
意思決定に利用したADR
eSquare Liveの開発においては、ADR(Architecture Decision Record)を活用して、アーキテクチャや技術選定に関する意思決定を記録しています。 リリースまでに作られたADRは約70件。その中から、以下のようなADRがありました。
- Webフロントエンドのビルドシステム / 配信方法
- WebフロントエンドからgRPCサーバーへのAPI疎通のプロトコル
- Workerで実装する注文・約定パイプラインについて
- GCP Pub/Subを利用したメッセージの順序指定について
- 約定処理アルゴリズムについて
- Golangのレイヤードアーキテクチャ整理
- 定期実行・スケジューリングしたいジョブの実現方法
- ユーザーロールの管理について
ADRは、開発チームのメンバーが意思決定の背景や理由を共有するための重要なツールとなっています。
今振り返っての反省点
メンバー構成
初期開発メンバーはPdM 1名、デザイナー 1名、EM 1名、エンジニア 5名でしたが、この中の5人は入社歴が数ヶ月未満でした。 よって、12月はドメイン知識のキャッチアップや信頼関係の構築、技術選定などに時間を費やすことになってしまいました。
成熟したチームであればもっと上手くスタートダッシュを切れたであろうと思います。 急成長スタートアップにはあるあるなこともかもしれませんが、振り返ってみると、もう少しメンバー構成に工夫が必要だったかもしれません。
仕様書の保守、QAの進め方
リリース前のQAは社内のQAエンジニアだけでは規模が大きく難しかったため、外注をしながらQAを進めましたが、結果としてQAの想定期間を延長し多方面に迷惑をかけてしましました。
最大の要因は仕様書と実装に差分があったことです。 eSquare Liveはだいたい動くようになってからはトレーダーへのヒアリングを繰り返しおこなっていきました。 ユーザーに早く動くものを体感してもらい、そのFBをもとに仕様を変更していくというプロセス自体は良いことだとは思っています。
しかし、FBをもらった変更された仕様が仕様書に反映されていなかったり、テストケースが作成されてから仕様が変更されてしまったり、QAの進め方がうまくいかなかったことが大きな反省点です。 仕様書フリーズのタイミングを会社全体で共有し、その後の変更についてはどのように進めるかを明確にすることが重要でした。 仮にどうしてもプロダクトを提供する上で必要不可欠な変更が入る場合はリリース日の延長と天秤にかけなければいけません。
完全なウォータフォールでやっているわけではないので、仕様の変更は必ず起きます。 そのときにSlackや会議資料、タスクチケットの説明文で伝えて開発するのではなく、当たり前ですが必ず仕様書をインターフェイスとして使っていくことがまずは重要です。 また、どれだけ初期に社外のユーザーや社内のユーザーの本気の声を引き出せるのかも仕様変更の可能性を減らすことにつながります。
今後の展望
eSquare Liveは、ローンチ後も機能追加や改善を続けています。 特に海外のトレーダーからは海外の取引サービスではこの機能があるのに、eSquare LiveにはないよねというFBをいくつもいただいています。 enechainのプロダクトは国内では類を見ないプロダクトであり、日本のサービスではなく、海外のサービスとしか比較されないというのは非常に珍しい特徴だと思っています。 我々がやらなければ日本では誰もやってくれないので身が引き締まる思いです。
大きな目玉としては、eSquare LiveのAPIを外部に公開し、他のサービスとの連携を可能にすることです。 今作っているAPIはFIX protocolという金融取引のためのプロトコルに準拠しており、FIX APIを公開することで、金融プレイヤーとの連携が容易になります。 前例がなく、まだまだわからないことも多いですが、日本を代表する電力取引プラットフォームとして、日本のトレーダーにも、海外のトレーダーにも満足してもらえるプロダクトにしていきます。
お知らせ
enechainは2024年もAdvent Calendarを開催します!
enechainがどんな開発組織を目指しているのか、どんな技術的挑戦をしているのか、ぜひAdvent Calendarを通じて知っていただければと思います。
また、この記事はeSquare LiveのOverviewを紹介するものであり、技術的な詳細については紹介していませんでした。 Advent Calendarでは開発に関わっているPdM、デザイナー、エンジニアも記事を書いてくれる予定ですので、ぜひお楽しみに!