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

PHPで書いたAPIをGoに書き換えてみた 〜パフォーマンス改善の可能性を探る実験レポート〜

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

PHPで書いたAPIをGoに書き換えてみた 〜パフォーマンス改善の可能性を探る実験レポート〜

Avatar for Wakana Koizumi

Wakana Koizumi

April 10, 2025
Tweet

Other Decks in Programming

Transcript

  1. Copyright © Canly, Inc. All rights reserved. 目次 3 自己紹介

    課題 結論 前提共有 実験結果 P. 04 P. 06 P. 09 P. 12 P. 16 まとめ P. 29
  2. Copyright © Canly, Inc. All rights reserved. 自己紹介 5 茨城県水戸市

    2023年1月(在籍: 2年3ヶ月) HRエンジニア部 カンリー福利厚生(フクリー) PHP, Laravel, Ruby, Ruby on Rails, React, TypeScript, Next.js, React Native お茶 なかなかいい物件が見つからない 5 小泉若菜 出身 入社年月 所属チーム スキル 趣味 悩み
  3. Copyright © Canly, Inc. All rights reserved. 課題 8 店舗ピン取得のAPIのレスポンスをもっと早くしたい!

    • Input: ユーザーの緯度経度、ジャンル、自社割限定か などを受け取る • Output: 現在そのユーザーに表示できるクーポンを 持つ店舗のみ、返却する
  4. Copyright © Canly, Inc. All rights reserved. 前提共有 13 •

    PCのスペック ◦ MacBook Pro ◦ チップ: Apple M2 Pro ◦ メモリ: 16GB • 言語、ライブラリのバージョン ◦ PHP: 8.2.28 ◦ Laravel: 10.48.4 ◦ GO: 1.21.13 ◦ Echo: 4.11.4 • PHPとGOの比較はdockerコンテナ上で実行 実行環境
  5. Copyright © Canly, Inc. All rights reserved. 前提共有 14 PHP

    & Go • レスポンス速度 ◦ 総100回のリクエストを10リクエスト並列で実行した時の平均値 Go • メモリ使用率 ◦ 現在のメモリ使用率 ◦ メモリの割当履歴 • CPU使用率 ◦ CPUプロファイル 「パフォーマンス」の計測の指標
  6. Copyright © Canly, Inc. All rights reserved. パフォーマンス計測 15 →

    Apache Bench 使ったツール } • レスポンス速度 ◦ 総100回のリクエストを10リクエスト並列で実行した時の平均値 • メモリ使用率 ◦ 現在のメモリ使用率 ◦ メモリの割当履歴 • CPU使用率 ◦ CPUプロファイル → pprof
  7. Copyright © Canly, Inc. All rights reserved. 結果: レスポンス速度 17

    平均リクエスト処理時間 • 総100回のリクエストを10リクエスト並列で実行した時の平均値 ◦ $ ab -n 100 -c 10 http://localhost:9090/api/stores/pins • 結果: ◦ PHP: 96.757 ms ◦ GO: 16.230 ms
  8. Copyright © Canly, Inc. All rights reserved. 結果: レスポンス速度 18

    平均リクエスト処理時間 • 総100回のリクエストを10リクエスト並列で実行した時の平均値 ◦ 実行コマンド: ab -n 100 -c 10 http://localhost:9090/api/stores/pins • 結果: ◦ PHP: 96.757 ms ◦ GO: 16.230 ms ←もっと早くならないか?
  9. Copyright © Canly, Inc. All rights reserved. 結果: メモリ使用量 19

    heap & allocs分析 • heap: 現在の使用量 (メモリリーク、現在のメモリ圧迫分析) • allocs: 過去の割り当て履歴 (無駄なメモリ割り当て、頻度の高い割り当て分析) • 結果: ◦ Header.Clone → HTTPヘッダー処理によるもの。 ◦ 対象のAPIのはメモリ使用の13%程度 → APIの処理にはそこまでメモリを使用していない !
  10. Copyright © Canly, Inc. All rights reserved. 結果: CPU使用量 20

    CPU分析 • profile: seconds=10で10秒間プロファイリング • 結果: ◦ 多くは以下に使われている ▪ ネットワーク待機 ▪ syscall ▪ Echo内部 → APIの処理ではは CPUはほとんど消費していない
  11. Copyright © Canly, Inc. All rights reserved. 結果: レスポンス速度 22

    goroutineを使ってクーポンの出し分け処理を並列化 1. 変数A: ユーザーの現在地から近い順に並べられたクーポンリスト 2. 変数B: ユーザーが使えるクーポンの配列を入れる配列 3. 出し分け処理 a. クーポン1枚ごとに出し分けロジックをかける b. 通過したクーポンのみが入った配列B を作成 4. 配列Bを配列Aの順番に並び替え ←並列処理
  12. Copyright © Canly, Inc. All rights reserved. 結果: レスポンス速度 23

    平均リクエスト処理時間 • PHP: 96.757 • GO: 16.230 • GO(goroutine使用時): 30.258
  13. Copyright © Canly, Inc. All rights reserved. 結果: レスポンス速度 24

    1万件のループを並列化してみる 直列処理 並列処理(goroutine + WaitGroup + Mutex) Serial Even Count: 5000 Serial Time: 16.208µs (=0.016208ms) Parallel Even Count: 5000 Parallel Time: 20.755875ms
  14. Copyright © Canly, Inc. All rights reserved. 結果: レスポンス速度 25

    1万件のループを並列化してみる 直列処理 並列処理(goroutine + WaitGroup) Serial Even Count: 5000 Serial Time: 16.208µs(0.016208ms) Parallel Even Count: 5000 Parallel Time: 54.338958ms
  15. Copyright © Canly, Inc. All rights reserved. 結果: レスポンス速度 26

    1万件のループを並列化してみる 直列処理 並列処理(goroutineのみ) Serial Even Count: 5000 Serial Time: 16.208µs(0.016208ms) Parallel Even Count: 5000 Parallel Time: 15.900042ms
  16. Copyright © Canly, Inc. All rights reserved. 結果: レスポンス速度 28

    sleepを入れた SQLを実行する 直列処理 並列処理 Serial Even Count: 5000 Serial Time: 5.532775919(5532.775919 ms) Parallel Even Count: 5000 Parallel Time: 209.862501ms
  17. Copyright © Canly, Inc. All rights reserved. まとめ 30 •

    PHPからGOへ移行することで、速度は約 6倍になった ◦ → 言語的には性能が高いことがわかった • 処理を並列化したら処理速度があがるわけではない ◦ → 並列処理の中の処理が軽い場合、 Goroutineのオーバーヘッドのほう ◦ → 適切な場面で使うことが不可欠