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

PHPからgoへの移行で分かったこと

Avatar for mahiguch mahiguch
December 01, 2019

 PHPからgoへの移行で分かったこと

php conference 2019 発表資料です。

Avatar for mahiguch

mahiguch

December 01, 2019
Tweet

More Decks by mahiguch

Other Decks in Technology

Transcript

  1. Copyright © LIMIA, Inc. All Rights Reserved. • グリーグループのリミア株式会社で、LIMIA という住まい領域のメディア

    を作っています。ゲーム会社ですが、最近はメディアに力を入れていま す。 • 機械学習(RecSys)のエンジニアですが、iOS, Android,JSなどもやってい る何でも屋です。5歳の娘のパパ。twitter: @mahiguch1 • GCPのイベントでAWSの話をしたら、Googleの担当営業の方から呼び 出されました。w • https://limia.jp/ • https://arine.jp/ • https://aumo.jp/ • https://www.mine-3m.com/mine/ Masahiro Higuchi/樋口雅拓 2
  2. Copyright © LIMIA, Inc. All Rights Reserved. グリーグループ公式部活動とし て技術書典部を立ち上げ、合同 誌を作って頒布しました。

    次の合同誌を制作着手してお り、技術書典8にもサークル参加 予定です。 企業部活動として技術書典7にサークル参加 3
  3. Copyright © LIMIA, Inc. All Rights Reserved. オフィスが新宿に移 転しました。最大190 名収容可能な勉強会

    スペースがあります。 社内外の勉強会を開 催できたらと思ってい ます。 松屋自販機もありま す! 最高すぎる勉強会スペースと松屋自販機 4
  4. Copyright © LIMIA, Inc. All Rights Reserved. 弊社では、PHPシステムの一部をgoで書き換えました。その経験から学んだことについ て、以下の構成で発表します。 •

    移行前後のWebシステム構成 • Pythonからgoに移行した推薦システム • PHPエンジニアがgolangを学ぶ時にハマりがちなこと • golangに移行して良かった点 • 改めて分かったPHPの良さ アジェンダ 5
  5. Copyright © LIMIA, Inc. All Rights Reserved. LIMIAとは? 7 •

    メディアサービス • Android, iOS, Web • 記事一覧を表示し、タップすると 記事詳細を閲覧できる。 • 記事一覧はパーソナライズ。 • 記事詳細読了後に関連記事を出 している。 • Fuel PHP/EC2, go/ECS • 分析基盤はBigQuery
  6. Copyright © LIMIA, Inc. All Rights Reserved. • EC2の上にfpmを乗せて。 •

    MySQL/Memc/Dynamo • Fuel PHP つまり、どこにでもあるシンプルなシステム。 移行前のシステム 8
  7. Copyright © LIMIA, Inc. All Rights Reserved. • 最近バージョンアップの話を聞かない •

    Githubを確認すると、最後のcommitが2018年5月 • Laravelに行く? いや、コンテナ考えたらgolangでしょ! → PHPをgolangで書き換えてしまおう! 移行の動機 Fuel PHPが。。。 9
  8. Copyright © LIMIA, Inc. All Rights Reserved. • PHP vs

    go: 基本はPHP。goのマイクロサービスを作り少しづづ処理を寄 せていく。 • https vs grpc: 型の問題が度々発生していたので、grpcで。 • EKS vs ECS: インフラ工数が取れないため、まずはお手軽なECSで。 • Envoy vs NLB: 同じく、まずはお手軽なECSで。 (比較レイヤーが異なるため、登壇後記載削除) 技術選定 10
  9. Copyright © LIMIA, Inc. All Rights Reserved. • PHPからMemcacheへは、ConsistentHashを使って直接アクセスして いた。

    • goからも同様にMemcacheへアクセスしたところ、ライブラリが異なるた め、ConsistentHashが合わない! → 仕方がないので、MemcacheへアクセスするだけのECS Service(go)を 作って、必ずそこを通すようにした。 システム構成ハマりポイント(1) MemcachedのConsistentHashが合わない 12
  10. Copyright © LIMIA, Inc. All Rights Reserved. Memcacheが辛すぎるので、MySQL/Memcachedへ のアクセスをgoに閉じ込めたい。 API部分をgoで実装する。

    WebはLaravelコンテナをECSで動かし、APIを叩いて データを取得する。 システム最終形予想図 13
  11. Copyright © LIMIA, Inc. All Rights Reserved. • 基本文法は自習。書籍を読んだり、playgroundで試したり。 •

    システム構成などを座学で毎日1時間x2週間。 • Build用コンテナやMakefileを整備した。 これで、書こうと思えば書けるレベルに。 (だけどPHPで書いた方が早い) Golangトレーニング PHPerのみでバックエンドを書いていた 14
  12. Copyright © LIMIA, Inc. All Rights Reserved. • UnitTestだけでなく、APIの結合テストもFuel phpのテストを書いてい

    た。 • レスポンスのIFをかなり網羅していたので、リファクタのときには重要。 • GitのDevelop branchにmergeされるとJenkinsでテストが走り、成功 したら結合テスト環境に配布していた。 —> 実装完了してmergeしたらテストが失敗。何故!? システム的なハマりポイント(2) テストが失敗する 15
  13. Copyright © LIMIA, Inc. All Rights Reserved. • Jenkins Slaveは、EC2にphpをインストールしてテストを実行していた。

    • 当然だがgolangコンテナが無いので、接続失敗でテストがコケる。 • Jenkins Slave専用にECS Service建てるのは、もったいないよねー。 —> 開発環境用に作ったdocker-composeをJenkins Slaveの中に立 ててしまおう! システム的なハマりポイント(2) テストが失敗した理由 16
  14. Copyright © LIMIA, Inc. All Rights Reserved. Repository構成 • docker:

    docker-compose.ymlなど • app: PHPで書かれた本体 • api: golangで書かれたマイクロサービス これまでは、Jenkinsにgithubのtokenとrepository pathを登録しておくと、手元に 展開されていた。 Repositoryが3つだとScriptの所でgit cloneを3行書く。—> Permission Denied... あれ? どうやってtoken渡そう。—> .netrcに書くことで解決! システム的なハマりポイント(2) 第1の関門: git tokenの渡し方 17
  15. Copyright © LIMIA, Inc. All Rights Reserved. • 1つ目のテストは成功したが、別のテストで失敗。 •

    コンテナが立てっぱなしだったので、ポートを取れなかった。 • 80/tcp —> 8080/tcp(dockerのNginxが動くport)に透過させていたのが原 因。 —> テストの開始時にdocker-compose up、終了時にdocker-compose downすることで解決。 システム的なハマりポイント(2) 第2の関門: コンテナの建て方 18
  16. Copyright © LIMIA, Inc. All Rights Reserved. • しばらくうまく動いていたが、突然テストが失敗するように。 •

    Jenkins Slaveでコンテナの更新を行なっていなかった。 • テスト開始前にdocker-compose pullしたが上手くいかない。あれ? —> ecr loginしてなかったので、docker repos.にアクセスできていな かった。loginすることで解決。 課題も解決し、処理の一部がgoで動き始めました。 システム的なハマりポイント(2) 第3の関門: コンテナの更新 19
  17. Copyright © LIMIA, Inc. All Rights Reserved. 起動直後の一覧表示。興味関心に合わせたものを掲載 すれば、使いやすいアプリになるのではないか。 そう考え、記事の推薦システムを開発中でした。

    → これもgolang化してしまおう! 記事のベクトル化、ユーザのベクトル化、掲載リストの生 成の3点について、golang化したシステムの解説を行い ます。 概要 21
  18. Copyright © LIMIA, Inc. All Rights Reserved. 記事が更新されると、 SQSに通知されます。そ れをLambdaで読み込ん

    で、単語に分割し、単語を vectorにします。記事に 含まれる単語の平均を記 事のvectorとします。ただ し頻出単語の影響緩和の ため、IDFで補正します。 アイテムベクトル作成 23
  19. Copyright © LIMIA, Inc. All Rights Reserved. • リクエスト単位 PHP:

    static → go: context • 長期: PHP: apc → go: static すぐ消えると思ってstaticに入れたらOOMになった。。。orz キャッシュの持ち方 26
  20. Copyright © LIMIA, Inc. All Rights Reserved. type Person struct

    { Name string Age int } func (p Person) ToString() string { return fmt.Sprintf("%s: %d", p.Name, p.Age) } class xx {}みたいに書くのではなく、funcの直後に書く。 関数名の先頭が小文字だとprivate、大文字だとpublic。 classをどう書けば良いのか interfaceに足を生やす 27
  21. Copyright © LIMIA, Inc. All Rights Reserved. // 単純に投げると、待たずに終わってしまう。 concurrent

    := make(chan struct{}, 5) for i := start; i < end; i += step { concurrent <- struct{}{} go func(startAt uint64, endAt uint64) { service.CreateByRange(startAt, endAt) }(i, i+step) } 並列数制限 こういうケースだと別ファイルにしてsystem()で起動していた。 28 // 当たり前だが、並列数制限して待つ必要がある。 var wg sync.WaitGroup concurrent := make(chan struct{}, 5) for i := start; i < end; i += step { wg.Add(1) concurrent <- struct{}{} go func(startAt uint64, endAt uint64) { defer func() { wg.Done() <-concurrent }() service.CreateByRange(startAt, endAt) }(i, i+step) } wg.Wait() // 待つだけだと、限界まで起動しちゃう。 var wg sync.WaitGroup for i := start; i < end; i += step { wg.Add(1) go func(startAt uint64, endAt uint64) { defer func() { wg.Done() }() service.CreateByRange(startAt, endAt) }(i, i+step) } wg.Wait()
  22. Copyright © LIMIA, Inc. All Rights Reserved. 【コンテナサイズ】 • PHP:

    1,500MB • go: 150MB 【インスタンスサイズ】 • PHP: 4CPU/8GB • go: 2CPU/8GB 開発系実験結果。コンテナサイズは小さくなる。CPUは少し軽くなってそう。メモ リはキャッシュを載せているので、ほとんど変わらない。 登壇後追記: 不要なファイルを削ればPHPのコンテナサイズは、200MB程度 になりそう。 コンテナサイズ/CPU使用量が小さい 30
  23. Copyright © LIMIA, Inc. All Rights Reserved. shuffleとかexplodeとか、自分で書かなきゃいけないの??? → はい。そうです。

    これは書いていて、PHPが懐かしくて仕方なくなった。 標準クラスの充実 34
  24. Copyright © LIMIA, Inc. All Rights Reserved. • WebはPHPで書いた方が早い。 •

    推薦システムはPythonで書いた方が早い。 • 安定的なシステムを作る場合、golangが早い。 当たり前だが適材適所に使うのが良い。 WebはPHP(Laravel)に、推薦システムはPythonに戻す予定。 お気付きの点がございましたら懇親会で教えてください。 まとめ 38