Más contenido relacionado
La actualidad más candente (20)
Similar a PHPからgoへの移行で分かったこと (20)
PHPからgoへの移行で分かったこと
- 1. Copyright © LIMIA, Inc. All Rights Reserved.
PHPからgoへの移行で分かっ
たこと
PHP Conference 2019発表資料
- 2. 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
- 3. Copyright © LIMIA, Inc. All Rights Reserved.
グリーグループ公式部活動とし
て技術書典部を立ち上げ、合同
誌を作って頒布しました。
次の合同誌を制作着手してお
り、技術書典8にもサークル参加
予定です。
企業部活動として技術書典7にサークル参加
3
- 4. Copyright © LIMIA, Inc. All Rights Reserved.
オフィスが新宿に移
転しました。最大190
名収容可能な勉強会
スペースがあります。
社内外の勉強会を開
催できたらと思ってい
ます。
松屋自販機もありま
す!
最高すぎる勉強会スペースと松屋自販機
4
- 5. Copyright © LIMIA, Inc. All Rights Reserved.
弊社では、PHPシステムの一部をgoで書き換えました。その経験から学んだことについ
て、以下の構成で発表します。
• 移行前後のWebシステム構成
• Pythonからgoに移行した推薦システム
• PHPエンジニアがgolangを学ぶ時にハマりがちなこと
• golangに移行して良かった点
• 改めて分かったPHPの良さ
アジェンダ
5
- 7. Copyright © LIMIA, Inc. All Rights Reserved.
LIMIAとは?
7
● メディアサービス
● Android, iOS, Web
● 記事一覧を表示し、タップすると
記事詳細を閲覧できる。
● 記事一覧はパーソナライズ。
● 記事詳細読了後に関連記事を出
している。
● Fuel PHP/EC2, go/ECS
● 分析基盤はBigQuery
- 8. Copyright © LIMIA, Inc. All Rights Reserved.
● EC2の上にfpmを乗せて。
● MySQL/Memc/Dynamo
● Fuel PHP
つまり、どこにでもあるシンプルなシステム。
移行前のシステム
8
- 9. Copyright © LIMIA, Inc. All Rights Reserved.
● 最近バージョンアップの話を聞かない
● Githubを確認すると、最後のcommitが2018年5月
● Laravelに行く? いや、コンテナ考えたらgolangでしょ!
→ PHPをgolangで書き換えてしまおう!
移行の動機
Fuel PHPが。。。
9
- 10. Copyright © LIMIA, Inc. All Rights Reserved.
• PHP vs go: 基本はPHP。goのマイクロサービスを作り少しづづ処理を寄
せていく。
• https vs grpc: 型の問題が度々発生していたので、grpcで。
• EKS vs ECS: インフラ工数が取れないため、まずはお手軽なECSで。
• Envoy vs NLB: 同じく、まずはお手軽なECSで。
(比較レイヤーが異なるため、登壇後記載削除)
技術選定
10
- 11. Copyright © LIMIA, Inc. All Rights Reserved.
NLB経由でgoにアクセス。
MySQLは両方から。
APIを一つづつ移行していく。
移行後のシステム
11
- 12. Copyright © LIMIA, Inc. All Rights Reserved.
● PHPからMemcacheへは、ConsistentHashを使って直接アクセスして
いた。
● goからも同様にMemcacheへアクセスしたところ、ライブラリが異なるた
め、ConsistentHashが合わない!
→ 仕方がないので、MemcacheへアクセスするだけのECS Service(go)を
作って、必ずそこを通すようにした。
システム構成ハマりポイント(1)
MemcachedのConsistentHashが合わない
12
- 13. Copyright © LIMIA, Inc. All Rights Reserved.
Memcacheが辛すぎるので、MySQL/Memcachedへ
のアクセスをgoに閉じ込めたい。
API部分をgoで実装する。
WebはLaravelコンテナをECSで動かし、APIを叩いて
データを取得する。
システム最終形予想図
13
- 14. Copyright © LIMIA, Inc. All Rights Reserved.
● 基本文法は自習。書籍を読んだり、playgroundで試したり。
● システム構成などを座学で毎日1時間x2週間。
● Build用コンテナやMakefileを整備した。
これで、書こうと思えば書けるレベルに。
(だけどPHPで書いた方が早い)
Golangトレーニング
PHPerのみでバックエンドを書いていた
14
- 15. Copyright © LIMIA, Inc. All Rights Reserved.
● UnitTestだけでなく、APIの結合テストもFuel phpのテストを書いてい
た。
● レスポンスのIFをかなり網羅していたので、リファクタのときには重要。
● GitのDevelop branchにmergeされるとJenkinsでテストが走り、成功
したら結合テスト環境に配布していた。
—> 実装完了してmergeしたらテストが失敗。何故!?
システム的なハマりポイント(2)
テストが失敗する
15
- 16. Copyright © LIMIA, Inc. All Rights Reserved.
● Jenkins Slaveは、EC2にphpをインストールしてテストを実行していた。
● 当然だがgolangコンテナが無いので、接続失敗でテストがコケる。
● Jenkins Slave専用にECS Service建てるのは、もったいないよねー。
—> 開発環境用に作ったdocker-composeをJenkins Slaveの中に立
ててしまおう!
システム的なハマりポイント(2)
テストが失敗した理由
16
- 17. 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
- 18. Copyright © LIMIA, Inc. All Rights Reserved.
● 1つ目のテストは成功したが、別のテストで失敗。
● コンテナが立てっぱなしだったので、ポートを取れなかった。
● 80/tcp —> 8080/tcp(dockerのNginxが動くport)に透過させていたのが原
因。
—> テストの開始時にdocker-compose up、終了時にdocker-compose
downすることで解決。
システム的なハマりポイント(2)
第2の関門: コンテナの建て方
18
- 19. Copyright © LIMIA, Inc. All Rights Reserved.
● しばらくうまく動いていたが、突然テストが失敗するように。
● Jenkins Slaveでコンテナの更新を行なっていなかった。
● テスト開始前にdocker-compose pullしたが上手くいかない。あれ?
—> ecr loginしてなかったので、docker repos.にアクセスできていな
かった。loginすることで解決。
課題も解決し、処理の一部がgoで動き始めました。
システム的なハマりポイント(2)
第3の関門: コンテナの更新
19
- 21. Copyright © LIMIA, Inc. All Rights Reserved.
起動直後の一覧表示。興味関心に合わせたものを掲載
すれば、使いやすいアプリになるのではないか。
そう考え、記事の推薦システムを開発中でした。
→ これもgolang化してしまおう!
記事のベクトル化、ユーザのベクトル化、掲載リストの生
成の3点について、golang化したシステムの解説を行い
ます。
概要
21
- 22. Copyright © LIMIA, Inc. All Rights Reserved.
ItemとUserの距離を計算し、近い物を出す。
ただし、全記事との距離をリアルタイムに計算
すると遅いので、分類して中心点との距離を計
算することにした。クラスタ内での順位はCTR
を使った。
記事の推薦
22
- 23. Copyright © LIMIA, Inc. All Rights Reserved.
記事が更新されると、
SQSに通知されます。そ
れをLambdaで読み込ん
で、単語に分割し、単語を
vectorにします。記事に
含まれる単語の平均を記
事のvectorとします。ただ
し頻出単語の影響緩和の
ため、IDFで補正します。
アイテムベクトル作成
23
- 24. Copyright © LIMIA, Inc. All Rights Reserved.
ユーザが記事を閲覧すると、その情報がKinesisに流れます。Lambdaで受け取
り、直近30件の閲覧履歴をDynamoDBに保存します。その変更をDynamoDB
Streamに流し、Lambdaで受け取って記事のベクトルの平均をユーザベクトルと
してDynamoDBに書き込みます。
これで推薦システムもgolang化することができました。
ユーザベクトル作成
24
- 26. Copyright © LIMIA, Inc. All Rights Reserved.
● リクエスト単位 PHP: static → go: context
● 長期: PHP: apc → go: static
すぐ消えると思ってstaticに入れたらOOMになった。。。orz
キャッシュの持ち方
26
- 27. 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
- 28. 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()
- 30. Copyright © LIMIA, Inc. All Rights Reserved.
【コンテナサイズ】
● PHP: 1,500MB
● go: 150MB
【インスタンスサイズ】
● PHP: 4CPU/8GB
● go: 2CPU/8GB
開発系実験結果。コンテナサイズは小さくなる。CPUは少し軽くなってそう。メモ
リはキャッシュを載せているので、ほとんど変わらない。
登壇後追記: 不要なファイルを削ればPHPのコンテナサイズは、200MB程度
になりそう。
コンテナサイズ/CPU使用量が小さい
30
- 31. Copyright © LIMIA, Inc. All Rights Reserved.
goはコンパイルが必要なので、ビルドエラーになってくれる。
これまでは、123を文字列で返して結合検証で見つかることが多かった。
テストから書けば問題ないが。。。
型安全
31
- 32. Copyright © LIMIA, Inc. All Rights Reserved.
みんな新しいものが好きなので。
API速度改善という名目でgo lang対応を挟むと気分転換になる。
最新技術を使っている気がしてモチベーションが上がる
32
- 34. Copyright © LIMIA, Inc. All Rights Reserved.
shuffleとかexplodeとか、自分で書かなきゃいけないの???
→ はい。そうです。
これは書いていて、PHPが懐かしくて仕方なくなった。
標準クラスの充実
34
- 35. Copyright © LIMIA, Inc. All Rights Reserved.
goには、それっぽいのがあまりない。
仕方がないから自作したけど、これで良かったのか。。。
Laravelにしておけば良かったと。
フレームワークが充実
35
- 36. Copyright © LIMIA, Inc. All Rights Reserved.
gopherまじ本当いない。募集しても全く応募がない。感覚的にはPHPの
1/100程度。
PHPerはgoに興味を持っている人が多いので、やるならPHPerを採用してgo
をトレーニングした方が良さそう。
(登壇後記載削除)
採用
36
- 38. Copyright © LIMIA, Inc. All Rights Reserved.
● WebはPHPで書いた方が早い。
● 推薦システムはPythonで書いた方が早い。
● 安定的なシステムを作る場合、golangが早い。
当たり前だが適材適所に使うのが良い。
WebはPHP(Laravel)に、推薦システムはPythonに戻す予定。
お気付きの点がございましたら懇親会で教えてください。
まとめ
38
- 39. Copyright © LIMIA, Inc. All Rights Reserved.
グリーグループ及びリミアでは、一緒にメディアを作っていく仲間を募集中で
す。興味のある方は、以下のサイトをご覧ください。
http://corp.gree.net/jp/ja/recruit/
https://www.wantedly.com/companies/limia
ご静聴、ありがとうございました。
We are hiring!
39