大量データで性能テストをする際に考えた事 ~ 将来のユーザーを見据えたテスト方針 ~

こんにちは!
京都開発拠点でGoエンジニアをやっている @ysakura_ です。
私のチームではマネーフォワード クラウド会計Plusの中長期の発展を見据えて、将来のユーザーの為に必要となる改善を行っています。
現在は将来発生するパフォーマンス問題の解決にフォーカスしており、大量データによる性能テストを先日行いました。

今回は思考過程を中心に実際にどういう方針でテストを行ったかを紹介します。
アプリケーションが受け入れ可能なキャパシティを探索する場合には、今回の考え方が役に立つのではないかと思います。

 

性能テストの概要

背景と目的

私のチームでは、ユーザー数が増加しても動く事、より大規模なユーザーを受入可能にする事を目標としています。
その為、目先の問題だけにとらわれずに、まずは将来遅くなりうる機能の全容を把握する事を重視しました。
その手段として、大量データによる性能テストを行う事にしました。

内容

具体的には、以下の事を行いました。

今回はこの各内容について掘り下げます。

  1. テストケースを洗い出す
  2. 大量データを生成するコードを作る
  3. 試すデータ量を考える
  4. 性能テストを行う
  5. 3と4の繰り返し

 

テストケースを洗い出す

今回の目的は問題の全容を洗い出す事なので、全容をカバー出来るテストケースを作成する事にしました。
加えて、現実と乖離した計測値には意味がない為、実際のユースケースに近いシナリオでテストをする事を重要視しました。
具体的には、プロダクトオーナーと話し合いながら、どのデータを大量にするか(条件)、何をテストするか(手順)を洗い出しました。
特に、どのデータが実際の業務上大量になりうるか、という点はプロダクトオーナーの話がとても参考になりました。
プロダクトオーナーとの距離が近い点が京都拠点の良い所だと思います。

例えば帳票の出力機能であれば、以下の様なテストケースとしました。

  • 条件
    • 仕訳数が多い
    • 仕訳に紐づくデータ(部門や補助科目)が分散している
    • 一部の仕訳は行数が多い
  • 手順
    • 全帳票の出力を試す。

 

大量データの生成コード

大量に用意したいデータの種類が分かったので、その生成コードを用意しました。
MySQLで数万 ~ 数百万件のレコードを生成する必要があった為、スクリプトには速度が要求されました。
メインとなるWebシステムはRailsで提供されており、Goエンジニアの私としては、Goで書くかRubyで書くか悩みました。
最終的には、保守・運用コストの削減の為、MySQLのスキーマ、Railsのモデルに変更があったとしても動作し続ける事を重視し、Rubyでスクリプトを作りました。
Rubyでスクリプトを作るにあたり、技術的には以下の事に気をつけました。

Bulk Insertを用いる

数万 ~ 数百万のレコード数で1件ずつINSERTするとオーバーヘッドが大きいため、Bulk Insertをする方針としました。
今回はチームで利用していた、activerecord-importを用いました。
他にはRails6から追加されたinsert_allを使う方法もあると思います。

Active RecordのValidationを行わない

大量データのBulk Insertを試してみた所、ActiveRecordのValidationで遅くなっている様でした。
その為、Validationをfalseにしました。
Validationが実行されずアプリケーションが想定していないデータが入っては性能テストの意味がないので、少量のデータでValidationを行いデータの性質が問題ない事は確認しました。

 

性能テストの実施

以下ではテストするデータ量を考えていく過程と、実際の結果について纏めます。

社内の品質目標

社内でプロダクトの品質目標というものを定義していた為、そのスペックを初めのデータ量としました。
品質目標はサポートデータ量上限という位置づけでした。
自分は動くものだろうと思って試したのですが、これが動きませんでした。

この時点で土台がなくなったので、全体の方針から考え直す事にしました。

実際のユーザー規模のデータ

品質目標が現実的ではない事が分かったので、現状のユーザー傾向を見つめ直す事にしました。
それによると品質目標は、特定の項目が実際のユーザーから乖離している事が分かりました。
なので、まずは現状動いているユーザーのMax規模での性能値を取る事にしました。
Max規模のユーザーにも傾向が複数あった為、この時は2ケースを試しました。

結果、遅かったり特定の条件で動かない機能はあったものの、概ね動くことが確認できました。

今後受け入れていきたいユーザーを精査する

基準点が出来たので、次は大量データの具体値を決めることにしました。
当初は大量データとして、普通・多い・とても多いの3パターンを試す事を考えていました。
しかし、大量データを用意するテーブルが5種類あった為、全パターンを網羅しようとすると243通りのテストが必要となりました。
現状、テストは自動化できていないので、とても一人でテストしきれる量ではありませんでした。

要望として高速化したいという話だけ受け取っていたので、プロダクトとしてどう進みたいかという観点が漏れている事に気づきました。
その為、大量データになっても将来受け入れたいユーザーの傾向を明確化する事に決め、これをプロダクトオーナーと目線合わせをしました。
この目線合わせにより、自分のチームのプロダクトの将来に対する解像度が上がりました。
その中で出てきた2テーブルに関して性能テストを行いました。

 

結果

これらのテストの結果、特定のケースに限ると現状でも大量データが動作するという事が分かりました。
具体的には、補助科目数が少なければ仕訳数が多くても動作する事が分かりました。

見えてきた課題

結果として以下の課題が分かりました。
帳票が遅い事は分かっていたのですが、他の課題があるかを洗い出す事が今回の目的の1つでした。
帳票が一番大きな問題と結論づけられたので、今後は帳票出力の改善に注力していく予定です。

  • 大量データになると帳票出力が遅い
    • この問題を解決する為の、Goのマイクロサービスを構築中です
  • Sidekiq(Rubyの非同期処理ワーカー)が複数ジョブを処理し始めると遅い
    • RubyのThreadがGVLを用いており、Concurrentに実行してもブロッキングされうるからと考えています。
  • 極端に遅い画面がちらほら存在する
    • これは徐々に解決していく予定です。

 

さいごに

将来のユーザーを見据えた大量データによる性能テスト、における考え方について紹介しました。
高速化したい、キャパシティを知りたい、といった要望は一般的によくありますが、漠然としているケースもあり進め方が難しい様に思います。
今回紹介した様に、実際のユーザーを見つめながらプロダクトの進みたい方向を精査する事で、その第一歩を踏み出せるのではないかと思います。


私のチームでは、Goエンジニアを絶賛募集中です。
今後は大規模事業者が受け入れられる性能改善をGoを中心に行っていきます。
メイン技術としてはGo言語を使いつつ、今回行った性能テストの様な周辺領域にも粘り強くトライしてくださる方を募集しています。

ご応募お待ちしています。
 
 

【サイトのご案内】
マネーフォワード採用サイト
Wantedly
京都開発拠点

【プロダクトのご紹介】
お金の見える化サービス 『マネーフォワード ME』 iPhone,iPad Android

ビジネス向けバックオフィス向け業務効率化ソリューション 『マネーフォワード クラウド』

おつり貯金アプリ 『しらたま』

お金の悩みを無料で相談 『マネーフォワード お金の相談』

だれでも貯まって増える お金の体質改善サービス 『マネーフォワード おかねせんせい』

金融商品の比較・申し込みサイト 『Money Forward Mall』

くらしの経済メディア 『MONEY PLUS』

Pocket