Upgrade to Pro — share decks privately, control downloads, hide ads and more …

インターンでハチナイのAPIを高速化しました!

akatsukinewgrad
December 17, 2021
780

 インターンでハチナイのAPIを高速化しました!

akatsukinewgrad

December 17, 2021
Tweet

Transcript

  1. インターンで
    ハチナイのAPIを高
    速化しました!

    View full-size slide

  2. 自己紹介
    ▣ 長谷川 貴斗
    ▣ 京都大学大学院 情報学研究科 数理工学専攻 M1(23卒)
    ▣ 先月10月にアカツキの就業型インターン(Ruby on Rails,
    八月のシンデレラナイン)に1ヶ月参加
    ▣ アカツキインターンでの担当業務
    □ 管理画面の開発
    □ バリデーションの追加
    □ 新規機能開発
    □ APIの高速化←
    ▣ 趣味
    □ 喫茶店(モス,ドトール,近所)で読書
    □ お絵描き 2

    View full-size slide

  3. 目次
    ▣ 何を高速化したいのか
    ▣ どのくらい遅いのか
    ▣ どうやって高速化したのか
    □ 既存のコードの問題点
    □ 解決策
    ▣ どのくらい高速化されたのか
    ▣ まとめ
    3

    View full-size slide

  4. 1.
    何を
    高速化したいのか
    4

    View full-size slide

  5. 高速化したいAPI
    ▣ 八月のシンデレラナイン
    ▣ チャプター情報一覧取得API
    □ ステージは解放済み?
    □ チャプターはボーナス期間?
    □ クリアスターはいくつ?
    などチャプターに関する情報諸々を取ってくるAPI
    5

    View full-size slide

  6. APIが返却するデータ
    ▣ 返却するデータは大きく分けると
    □ マスターデータだけで計算できるもの
    ■ チャプターはボーナス期間中か
    □ ユーザーデータが計算に必要なもの
    ■ チャプターはクリア済か
    ▣ マスターデータ
    □ 選手情報,能力値やスカウトの開催時期など
    ▣ ユーザーデータ
    □ ミッションのクリア状況や獲得経験値など
    6

    View full-size slide

  7. 2.
    どのくらい
    遅かったのか
    7

    View full-size slide

  8. 計測結果
    3957ms (Views: 2452.5ms | ActiveRecord: 251.4ms)
    ▣ Viewsも遅いが,ViewsとActiveRecord以外の部分もかなり時
    間かかってる
    →Controllerに遅い処理がありそう...
    8

    View full-size slide

  9. 大量のpreload
    ▣ Chapterの関連テーブルを
    読み込むところの処理が
    1300msほどかかっていた.
    9

    View full-size slide

  10. なぜ遅いか
    ▣ preload
    □ クエリの使用回数を減らすために関連づけられたレコードを一括で読み込む
    □ いわゆるN+1問題を解消するのによく使われる
    ▣ 遅い理由
    □ レコード数が多いものでは20000ほどもあり,preloadするとそれぞれに対
    してActiveRecordインスタンスが生成.さらにそれぞれのレコードに対して
    カラム数分だけActiveRecord::AttributeMethods関連オブジェクトのメ
    ソッドが呼ばれたりして.生成コストが高くなる
    つまり,レコード数が多い時preloadはそれなりに重たい.
    10

    View full-size slide

  11. 3.
    どうやって
    高速化したのか
    11

    View full-size slide

  12. preloadする回数を減らしたい
    かといって,ただpreloadをやめるだけではN+1が起きてしまう
    ▣ マスターデータだけで計算できるデータは,アプデなどでマスターデー
    タが変更されない限り不変.
    □ 一回計算した後はキャッシュに持たせておけば,preloadしなくて
    済む.
    ▣ キャッシュはマスターデータが変更されるときに削除
    12

    View full-size slide

  13. APIが返却するデータ(再掲)
    ▣ 返すデータは大きく分けると
    □ マスターデータだけで計算できるもの
    ■ チャプターはボーナス期間中か
    □ ユーザーデータに紐づくもの
    ■ チャプターはクリア済か
    ▣ マスターデータ
    □ 選手情報,能力値やスカウトの開催時期など
    ▣ ユーザーデータ
    □ ミッションのクリア状況や獲得経験値など
    13

    View full-size slide

  14. 他にも色々
    ▣ N+1っぽい問題が起こっている箇所の修正
    ▣ キャッシュを作る時だけpreloadが必要だが,毎回preloadしてし
    まっていた箇所を修正
    など...
    14

    View full-size slide

  15. 4.
    どのくらい
    高速化されたのか
    15

    View full-size slide

  16. 結果
    3957ms→1871ms!!
    50%程高速化できました.
    16

    View full-size slide

  17. 5.
    まとめ
    17

    View full-size slide

  18. まとめ
    ▣ 「N+1問題」を起こさないのは基本
    ▣ 「ActiveRecordインスタンスの生成コスト」はそれなりに高い
    ▣ 変更される頻度が低いデータはキャッシュに持たせるという解決策
    をとった.
    - Future Work
    ▣ 技術の選定(たとえばErlangだとプロセスをまたがる場合でも内蔵
    のオンメモリDBが使えたりするらしい...)
    ▣ joinとかpluckを使ってActiveRecordインスタンスを生成しない
    みたいな方法もあったのかも
    18

    View full-size slide