Money Forward Developers Blog

株式会社マネーフォワード公式開発者向けブログです。技術や開発手法、イベント登壇などを発信します。サービスに関するご質問は、各サービス窓口までご連絡ください。

20230215130734

インターンでの性能改善タスクの取り組み

初めまして! 京都開発本部テクニカルアーキテクトグループ(KTA)でインターンをしているonetkです。

この記事ではインターンを始める前に気になっていた「京都でインターンとしてどのようなことをしているのか」について、以前取り組んでいた性能改善のタスクを例に少し掘り下げた内容となっています。

概要

マネーフォワード クラウド会計Plusでは会計という大量のデータを扱うシステムの都合上、一部の機能が重くなることがあります。 そこで、KTAチームでは既存機能の性能改善を主に行っており、インターン生でも1タスクに丸々チャレンジさせて貰えます!

今回は丸々取り組ませていただいた1タスクが一段落したので過程も含めつつまとめています。内容は大量のRedisの読み込みの影響で特定条件下で2~3分かかっていた一機能の原因探索と改善です。

タスクについて

京都拠点では日々Datadogなどでパフォーマンスも改善できるよう監視しています。 今回課題となった機能の計測結果を覗いてみると、以下のように平均して2分ほど時間がかかっていることが分かりました。

その原因を見てみるとRedisの読み/書き回数が1.25万回と異常に多い事が分かったため、今回はこれを解決していくことになります。

目標

このリクエストにかかる処理の時間短縮・解決

  • 具体的には同規模の条件でALBのidle_timeout(1分)以内に抑える

調査

ここからは実際に行った原因探索の詳細な流れです。とても冗長なのでざっくりと流し読みで大丈夫です。

調査前と修正ミス

事前情報

取り組み始めの際に、上記「タスクについて」の内容、どういう機能なのか、Datadogでこの問題が起きているログへのアクセス(今回はp99 latencyのTop1)の説明を受けた後にスタートしました。

  • 質問した内容:この他のログや現状の可能性
    • この問題の主要なログはここだけ。原因としてN+1の可能性。

掘り下げ

Datadogのログなどの詳細から以下の内容が推測・判明しました。

  • Redisのcacheのキー名称から、どのクエリの代わりに読み込むのか
  • 課題の機能をコントローラーから掘り下げていく中で、特定の金額を算出する部分で上記と同じRedisのcacheを読み込んでいる

仮の修正

上記判明した箇所:算出した金額を持たずに算出に用いる期間の情報などをハッシュで保持、連続したいくつかのメソッドで金額を用いる際はこれをもとに適宜算出している。ここでは ?

  • 修正結果
    • cacheを読み込ませる部分を削減対応 (※実装ミスだった)
    • 効果があったり無かったりで迷走。原因が憶測の域を出なくなる

次の方向性

そもそもの問題のリクエストの前提条件、何が問題だったのかが不明なために修正箇所が間違っていたのでは?

  • 「修正前」で再現・原因の要素の特定を試みる

実験 1 : 再現性の確認

手元の仮のデータ(軽め)を用いて本番に近い統合テスト環境で試す

確認できる範囲のログでは全て2分以上かかっている。もとの機能自体にcache読み込みの異常がないかサンプルのデータで検証

  • リクエストの中身を比較するとcacheのspan数が元の 1.25万回 に対して 53回
  • 機能自体に致命的な問題はなさそう
  • 再現のためにはデータの規模が圧倒的に異なる

  • CloudWatchを使ってモニタリングしているECSのとあるコンテナに見にいくとリクエスト直後からCache読み込みが確かに複数発生。内容から場所は特定の金額を算出する部分に確定。

実験 2 : 規模を増やしたデータで確認

データについて

ここで用いるデータにはカテゴリが存在します。カテゴリには親子関係があり、勘定科目(親カテゴリ)、補助科目(子カテゴリ)といいます。 例えば「給料賃金」という勘定科目には、「住宅手当」や「残業手当」などの補助科目がついている場合があります。

仮のデータ(重め)を生成、本番に近い統合テスト環境で試す

先ほどはデータが数件と小規模だったため、今回はより規模を拡大したデータで試し、どこまで問題の結果に近づけられるか検証

  • 136カテゴリで生成した1万件のデータ (※1)
    • 数秒かかる + cacheの割合も増えていくが、2分を超える規模の差は出ない
    • 変化がごく僅かなため、1万件でもデータの数が圧倒的に足りない or データのカテゴリ数が足りない or その両者の可能性

※1 通常の操作では新規カテゴリ追加の際にGUI操作が一部必要となるため、DB操作以外ですぐに検証可能な既存のカテゴリ・サブカテゴリを組み合わせた136種を上限に生成するスクリプトを作って試しています

実験 3 : 差分から原因の要素を確認

データ数・カテゴリ数を段階的に変化させた差分検証

完全再現はすぐにできそうにないので、データの内容を少しずつ変更、差分からデータ件数、データ種類の主にどちらが影響しているか検証していく

  • 0, 4, 16, 136, 1000, 10000(=実験2)と各項目を段階的に増やした差分の確認 (10回平均)
    • cache span数( = 特定のRedisのGet・Post数+α )
      • カテゴリ数とおおよそ相関、データ数は直接関係無し
      • 1種類につき3~5回、RedisのGetが増加している (カテゴリにサブカテゴリが混ざっているため変動したと見られる)
    • 処理時間
      • データ数に一部影響されるが、カテゴリ数が主に影響
    0件 / 0種 4件 / 4種 16件 / 16種 136件 / 136種 1000件 / 136種 10000件 / 136種 ? 件 / ? 種類 (本番)
    平均時間 (s) 1.010 1.090 1.107 2.482 2.475 2.730 138.07
    cache span数 12 32 68 428 428 428 約12500

考察

実験3でのカテゴリあたり3~5件の増加具合だと、本番で2500~4000近くのカテゴリを各事業者単位で保有している可能性あり (実験2の想定の20~30倍)

  • 質問した内容:本番DBの事業者あたりのカテゴリ数は3000を超えているのか
    • サブカテゴリ数において、平均はそこまでだが、3000件を超えている事業者が複数存在。

ほぼ確実にサブカテゴリ数の処理部位が主にcacheを冗長に読み込んでいると考えられる

修正と結果

修正方向

原因と流れが掴めたので対応

  • N+1 を根本的に解決、算出の仕方を変更するなど解決する場合は変更部位が多く影響範囲が広い
  • 最初の修正としてはRedisの繰り返し読み込みの部分において、引数として金額の算出に用いる期間などの状態ではなく算出した金額を直接持つ内容に変更
    • ここでの修正: 1敗。ただし修正すべき場所は正しい+相談の結果、実装ミスと推測
  • 改修したメソッドの部分のテストも修正 + 新設 (ここ本当に大事で難しい)

修正結果

  • 準備できる範囲での規模の場合 (カテゴリ・サブカテゴリ混在)

    • cache span数の変化

      0件 / 0種 4件 / 4種 16件 / 16種 136件 / 136種 1000件 / 136種 10000件 / 136種
      修正前 12 32 68 428 428 428
      修正後 10 19 31 152 152 152
    • 平均時間 (s)

      0件 / 0種 4件 / 4種 16件 / 16種 136件 / 136種 1000件 / 136種 10000件 / 136種
      修正前 1.010 1.090 1.107 2.482 2.475 2.730
      修正後 1.009 1.078 1.163 2.009 1.991 2.204
    • cacheの読み込み(主にRedisのGet)回数は1/2〜1/3に縮小

    • 処理時間は4/5に短縮
  • サブカテゴリ3000件の場合

    • 約1/3の100秒程高速化、目標のALBのidle_timeout(1分)以内に抑える
    • サブカテゴリがメインだったため、より短縮した結果になったと考えられる

まとめ

  • KTAチームではマネーフォワード クラウド会計Plusの性能改善を行っており、今回はとある既存機能の改善に丸々取り組みました。

  • 道中では研究の実験のように仮定・実験・考察のサイクルを回すことで原因を特定、修正することで何とか目標を達成しましたが、まだまだ改善の余地ありです。

  • インターン生でもこのような性能改善タスクに丸々チャレンジさせて貰える環境です。

最後に

これまでは別チームでクラウド会計Plusの管理画面の開発や、KTAチームで性能改善の一貫として特定機能群の処理時間をDatadogに送る部分などに携わっていました。

そのため、既存機能の性能改善というタスクは初めてで時間はかかりましたが、個人の希望に沿って週1で方向性やコードベースの相談を設けていただいたおかげで順調に進めれました。今回のタスクを経て、仮定・実験・考察のサイクルの重要性を再認識したことはもちろん、テストの重要性と面白さと綺麗に書く難しさを改めて痛感しましたが、諸々の知見も貯まり、振り返るとかなり面白いタスクでした。


この他にも、京都拠点ではチームによっては実際に既存プロダクトの開発に携われたり、より複雑で本格的な性能改善のタスクやMLもチャレンジできる可能性もあります。また並行してインターン生でも会計知識やʕ◔ϖ◔ʔなどの社内勉強会にも色々参加させてもらえる環境です。 インターンを京都近辺で探している方はおすすめです https://www.wantedly.com/projects/537965

長文となりましたが、ありがとうございました。

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

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

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

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

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

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

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

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