Weitere ähnliche Inhalte
Ähnlich wie [ScalaMatsuri] グリー初のscalaプロダクト!チャットサービス公開までの苦労と工夫 (20)
Kürzlich hochgeladen (20)
[ScalaMatsuri] グリー初のscalaプロダクト!チャットサービス公開までの苦労と工夫
- 1. The Trial and Error in
Releasing GREE Chat
Shun Ozaki, Takayuki Hasegawa
Copyright © GREE, Inc. All Rights Reserved.
Scala Matsuri2014 B-6
GREE's First Scala Product
- 2. Copyright © GREE, Inc. All Rights Reserved.
Self Introduction
• Shun Ozaki
• @wozaki
• Joined in April, 2013
• Android Application
• Takayuki Hasegawa
• @hase1031
• Joined in April, 2013
• NLP, Machine Learning
1/56
- 4. How to build our system for hundreds of
thousands daily users
Copyright © GREE, Inc. All Rights Reserved.
Agenda
3/56
- 5. Goal
Share our knowledge we got through
the development of GREE Chat
Copyright © GREE, Inc. All Rights Reserved.
• Why Scala?
• Team development
• Decision of frameworks
• Obstacles & workarounds
4/56
- 6. Copyright © GREE, Inc. All Rights Reserved.
Outline
• Reason of Selecting Scala
• Learning Scala in a Team
• Architecture of GREE Chat
• Obstacles
• Summary
- 7. • Reason of Selecting Scala
• Learning Scala in a Team
• Architecture of GREE Chat
• Obstacles
• Summary
Copyright © GREE, Inc. All Rights Reserved.
Outline
- 9. Requirements
• Hundreds of thousands daily users
• Real-time response
Copyright © GREE, Inc. All Rights Reserved.
Connect with streaming
• Run on a small number of servers
Utilize server resource effectively
• Maintain for over 5 years
8/56
- 10. Copyright © GREE, Inc. All Rights Reserved.
◎ GREE uses PHP so heavily
• Many libraries and know-how in GREE
△ Streaming
• #connections = #processes
△ Single thread, multi process
• Overhead of spawning an OS process
△ Maintainability
• Dynamic typing
9/56
- 11. ◎Compatible with concurrent programming
◎One process, many connections
◎High maintainability
• Static typing
• Functional programming (no side effects)
◎Stimulate new technology learning in GREE
• Open to new languages & technologies!
Copyright © GREE, Inc. All Rights Reserved.
Scala!
10/56
- 12. • Reason of Selecting Scala
• Learning Scala in a Team
• Architecture of GREE Chat
• Obstacles
• Summary
Copyright © GREE, Inc. All Rights Reserved.
Outline
- 14. Only two Scala programmers in a team of seven
Copyright © GREE, Inc. All Rights Reserved.
Shortage of Scala experts
2/
7
13/56
- 15. Only two Scala programmers in a team of seven
We must build up our skill!
Copyright © GREE, Inc. All Rights Reserved.
Shortage of Scala experts
2/
7
14/56
- 16. Copyright © GREE, Inc. All Rights Reserved.
Learning of Scala
1. Self study
2. Study club
3. Pair programming
15/56
- 17. Copyright © GREE, Inc. All Rights Reserved.
1. Self Study
Understand the basic syntax
- 19. Copyright © GREE, Inc. All Rights Reserved.
1. Self Study
Documents by Twitter
https://twitter.github.io/scala_school/ http://twitter.github.io/effectivescala/ 18/56
- 20. Copyright © GREE, Inc. All Rights Reserved.
1. Self Study
Source code from OSS
19/56
- 21. Copyright © GREE, Inc. All Rights Reserved.
2. Study Club
Share what we learned by ourselves
Introduction to functional programming
- 22. 2. Study Club
• Each engineer solves the problems
provided by Scala experts
Copyright © GREE, Inc. All Rights Reserved.
• e.g., Binary Tree, Fibonacci Sequence
21/56
- 23. • Example of factorial generation algorithm
Copyright © GREE, Inc. All Rights Reserved.
2. Study Club
Discussion with Members
Use var Use recursion
22/56
- 24. • Example of factorial generation algorithm
Use var Use recursion
Copyright © GREE, Inc. All Rights Reserved.
2. Study Club
Discussion with Members
No side effect
23/56
- 25. 3. Pair Programming
Practice by using the knowledge
Copyright © GREE, Inc. All Rights Reserved.
obtained from study club
- 26. Copyright © GREE, Inc. All Rights Reserved.
3. Pair Programming
• Effective learning
• Learn about symbols (e.g., +, @), which cannot
be searched easily on the Internet
• Supplement the knowledge not taught at
study club
• Complex syntaxes (e.g., implicit, currying)
• Development tools (e.g., sbt, IntelliJ)
25/56
- 27. Copyright © GREE, Inc. All Rights Reserved.
Summary: Adopting Scala
• Reasons of selecting Scala
• Compatible with concurrent programming
• Maintainability because of static typing
• Learning of Scala
• Self Study, Study Club, Pair Programming
• Big burdens on Scala experts
• Needed for teaching team members
• Maintain the quality of codes
26/56
- 28. • Reason of Selecting Scala
• Learning Scala in a Team
• Architecture of GREE Chat
• Obstacles
• Summary
Copyright © GREE, Inc. All Rights Reserved.
Outline
- 29. Architecture of Backend (simplified)
Copyright © GREE, Inc. All Rights Reserved.
• Servers separated by Queues
• API Server: Process users’ requests
• EventBus Server: Process events in Queue
• Stream Server: Supply event to connected users
28/56
- 30. Role of Each Server
Copyright © GREE, Inc. All Rights Reserved.
and Framework
- 31. Copyright © GREE, Inc. All Rights Reserved.
API Server
Process users’ requests
• Enqueue events
• e.g., Send message
Join/leave conversation
• Techniques to process a lot of requests
• Delegate heavy tasks (e.g., Disk I/O) to others
• Logic is written to run asynchronously
• scala.concurrent.Future
30/56
- 32. • RPC system for JVM based on Netty
• Support us to write asynchronous logic
Copyright © GREE, Inc. All Rights Reserved.
• Used by large scale web services
• e.g., Twitter, Tumblr, Foursquare, Pinterest
• Equipped with various clients
• Redis, Memcached
• With retry policy, connection pools
31/56
- 33. Copyright © GREE, Inc. All Rights Reserved.
EventBus Server
Process events in Queue
• Examples of tasks
• Logging
• Inquire GREE internal system
• Store events in DB
• etc.
• Problems of concurrent processing
• Deadlock, race condition, …
32/56
- 34. Framework to write concurrent, distributed
logic more easily
• No need to handle shared resources
Copyright © GREE, Inc. All Rights Reserved.
• Race condition, dead-lock
• Logic separation
• Parent-Child
• Fault tolerance
33/56
- 36. Copyright © GREE, Inc. All Rights Reserved.
Example of Akka
Match by Event type
35/56
- 37. Copyright © GREE, Inc. All Rights Reserved.
Example of Akka
Send copy to child
36/56
- 39. Copyright © GREE, Inc. All Rights Reserved.
Stream Server
Supply events to connected users
• Connect by streaming
• Increase connections as much as possible
• Keep users data in the memory to reduce I/O
• Asynchronous I/O by Finagle, Akka
• Task division by Akka
• Supply events to users
• Update users data
• Send KeepAlive to users
38/56
- 40. Copyright © GREE, Inc. All Rights Reserved.
Summary: Architecture
• Each server is separated by Queue
• API, EventBus, Stream Server
• Framework is selected by considering
asynchronous processing
• Finagle, Akka
• Task is divided by Akka
• Easy to write concurrent logic
39/56
- 41. Copyright © GREE, Inc. All Rights Reserved.
Outline
• Reason of Selecting Scala
• Learning Scala in a Team
• Architecture of GREE Chat
• Obstacles
• Summary
- 42. Copyright © GREE, Inc. All Rights Reserved.
Obstacles
1.JVM
• Full GC
2. Self-created Scala library
• Sharding
• ID Architecture
41/56
- 44. • Scala runs on JVM
• We want to prevent “stop the world”
• GC in young generation is faster than full GC
• Try not to let it store object in old generation
Copyright © GREE, Inc. All Rights Reserved.
Full GC
Young generation Old generation
43/56
- 45. Copyright © GREE, Inc. All Rights Reserved.
Causes of Uncollected
Reference Problem
• Use method that has side effects
• Reuse object everywhere
• Forget to release used resources
44/56
- 46. Copyright © GREE, Inc. All Rights Reserved.
Causes of Uncollected
Reference Problem
• Use method that has side effects
• Reuse object everywhere
• Forget to release used resources
Difficult to recognize by developers
45/56
- 47. Copyright © GREE, Inc. All Rights Reserved.
Short-Lived Object
• Use val variable (final variable)
• Don’t use mutable variable
• Don’t leave references to objects for too long
Create new objects instead of updating old ones
46/56
- 51. Copyright © GREE, Inc. All Rights Reserved.
Horizontal Partitioning
• Sharding is necessary!
• Considering capacity and #accesses
• We have Cascade, a sharding library
• For PHP, not Scala
• So, we created Aurora and make it OSS
• Aurora and application were developed
simultaneously
• So difficult to integrate them during
development
• Code modification must be done in many parts
50/56
- 52. ID Architecture:
UUID and InnoDB
Ref:MySQL InnoDB Primary Key Choice: GUID/UUID vs Integer Insert Performance
http://kccoder.com/mysql/uuid-vs-int-insert-performance/
Copyright © GREE, Inc. All Rights Reserved.
- 53. Ref:MySQL InnoDB Primary Key Choice: GUID/UUID vs Integer Insert Performance
http://kccoder.com/mysql/uuid-vs-int-insert-performance/
Copyright © GREE, Inc. All Rights Reserved.
UUID
AUTO_INCREMENT #record
#time
- 54. Drop UUID, Take Time-Based
• At first, we used UUID as primary key
• But this caused MySQL to insert randomly
• Created a library to generate ID instead
• Referred to Snowflake by Twitter
• Sequential insertion based on sorted created
time
53/56
Copyright © GREE, Inc. All Rights Reserved.
- 55. Copyright © GREE, Inc. All Rights Reserved.
Summary: Obstacles &
Workaround
• JVM
• Use short-lived objects to avoid Full GC
• Self-created Scala library
• Sharding
• Made Scala library OSS
• Integration of library to application was difficult
• ID Architecture
• Adopt time-based ID for sequential insertion
54/56
- 56. Copyright © GREE, Inc. All Rights Reserved.
Outline
• Reason of Selecting Scala
• Learning Scala in a Team
• Architecture of GREE Chat
• Obstacles
• Summary
- 57. Copyright © GREE, Inc. All Rights Reserved.
Summary
• Reasons for selecting Scala
• Compatible with concurrent programming
• Plan Scala learning within the team
• Learning cost is expensive
• Architecture & Frameworks
• Each server is separated by Queue
• Finagle, Akka
• Shortage of libraries
• We must have made libraries by ourselves
• Needed to pull request to OSS repository
56/56
- 58. Copyright © GREE, Inc. All Rights Reserved.
Thanks!
@tomoyoshi_ogura, @kyo_ago, @takc923
@yoshie_777, @le_chang, @beketa, @j5ik2o
and
ScalaMatsuri staffs
Hinweis der Redaktion
- 前半のプレゼンは 私が担当
後半 長谷川が担当
グリーで初めてのScalaプロダクト チャットサービスを作った
リリースするまでの苦労や工夫について
30分
- 2013年に入社
それから チャットのバックエンド開発に参加している
大学時代はAndroidアプリケーションの開発
フロントエンジニアより
- 本日話すGREEチャットの画面例
動作のイメージは、 ざっくり言うと、GREEユーザ同士で会話できるLINE
LINEさんが来ている前で こんなこと言うと怒られるかもしれませんが
GREE Chatを作った目的
リアルタイムのコミュニケーションで、ユーザのアクティビティを活性化させるという目的
- 本日話す内容
数十万人の利用を想定するチャットのバックエンド
Scalaでどのように構築したか
- このプレゼンのゴール
主な対象者=>これからScalaでプロダクトを構築する人
今回バックエンドをScalaで構築するにあたって得た知見の共有
具体的には
1.なぜScalaを選んだか
2 Scalaを利用して、どのようにチームで開発したか
3 どのようなシステム構成でどのようなフレームワークを選定したか
4 開発で苦労したこと、解決策
- Scalaを選んだ理由
- 言語を選定するにあたって、GREEチャットの要件から決めました
- 主な要件は4つ
1. 数十万の利用者を想定
2. チャット特有のリアルタイムなレスポンス
何千もストリーミングで同時接続できること
3. 少ないサーバ台数で稼働すること、コスト削減
=>サーバの資源を効率的に活用できる言語であるということが求められる
4. 5年以上の保守
- まず白羽の矢がたったのがPHP
GREEの主要言語はPHP
->社内にライブラリや運用ノウハウがたくさんある
今回の要件に適さない問題が3つ(PHP disではない)
1 ストリーミング
接続数分だけプロセス数が必要
-> 何千とか接続してきたときにプロセスを立ち上げるのは辛い
2 基本的にシングルスレッド
-> プロセス起動のオーバーヘッドが発生する
-> サーバCPUを効率的に利用 難しい
3 保守性
・動的型付け言語 => ある程度の規模になると、保守難しくなる
その他:セミコロンが無い
- そこでScalaを採用しました
1.並行プログラミングとの親和性
-> CPUを効率よく使える
-> サーバ台数少なくてすむ
2.一つのプロセスで複数のコネクション
3.保守性(静的型付け言語、関数型言語の特徴があるので、副作用がない関数をつくりやすい=>バグを生みにくい)
4.社内技術の活性化 (一つの言語に縛られないこと、)
Javaと比較 短いコードの記述量
他にも細かいところ 色々あるが、決めてScalaが大好きなエンジニアがいたからScala
- どのようにチームでScalaを学んで言ったかについてお話します
- Scalaを採用したのはいいんですが
- Scalaの経験者は不足していました
チーム7人中二人
- チームでScala力向上の必要
- 学習のコンテンツは3つです
1 自主学習
2 チームでの勉強会
3 経験者とペアプロ
- 目的:基本手な構文の理解
Scalaはどういった特徴
- 1 Programming in Scala (通称コップ本
言語設計上の話など詳細
1度に全部理解するのは困難だが、
何度も見返す
Scala逆引きレシピ
リファレンスとして手元に置いておく
webの問題点として、回答の質がばらついている
逆引きリファレンスは質も網羅性も高い
著者が全員 登壇しているが、よいしょでも やらせでもなく
- Scala School
コンソールで動きを確かめながら
手を動かしながら進めやすい
Effective Scala
コードのフォーマットからエラーハンドルまで、Twitterのscalaノウハウがあるので参考にしている
- Scalaのライブラリは、基本的にGithub上に公開されている
Twittreの中の人が、どんなscalaコードを書いているかなど分かる
参考に
- 勉強会
目的:
個々の学びをチームで共有、
関数型プログラミングの入門
- Scala経験者が提供する練習問題作成
チームで問題を解く
二分木、フィボナッチ数列など
- できた回答をチームメンバーで共有し議論する
階乗計算の答えを2つ載せる
1 var 再代入可能な変数とforループを使用
2 再帰
- varを利用している方は、ループの中で再代入しているのが分かる
再帰: データの破壊的代入はしていな
varのように後から変更可能な変数の利用
-> 自分が想定していない箇所で変更される可能性がある
-> バグの元
(規模が大きくなってくるときつい)
◆チームの方針:
必要最小限の副作用で構成されたコードを目指す => 保守性を維持
- ペアプロ
経験者のサポートありで、
自主学習や勉強会で得た知識を実践で活用
- 利点
1.効果的な学習
記号が使われているがwebで検索できない問題->人に聞くのが早い
Scalaでは様々な書き方できるが故に結局どう書いていいのか混乱
2.勉強会で補えないものを補足する
a 難解な構文、implicit やカリー化、 なんでもかんでもimplicitにすればいいものじゃない
b コード以外で言うと、sbtやIntelliJの効果的な使い方の共有
午前中に横田さんのsbtで一緒にやった方
- Scalaを選んだ理由
1 並行プログラミングと親和性高い
2 コードの保守性高い
静的型付け言語や副作用の無い関数型プロミングができるので
Scalaの初期学習コストは、それなりにある
・自主学習、勉強会、ペアプロ
・チームで取り組む
Scala経験者には負荷はかかる
・Scakaのノウハウの布教、コードのクオリティを保つためのコードレビュー
- GREEチャットのアーキテクチャ
- バックエンドの簡略図
青:アプリケーションサーバ、赤;Q
Qで別れている。
CPUバウンド=>サーバ台数を増やすことでスケーリングすることが可能
API Server: ユーザのリクエストを受け付け 処理
EventBus Server: Qからデータを取得・加工
Stream Server: 接続しているユーザへデータを流す
- 各サーバの役割詳細
そこで利用しているフレームワークを紹介
- ユーザのリクエストを処理する
Eventをエンキュー
Event:メッセージの送信、会話の参加、離脱
大量のリクエストを捌く工夫
1.重い処理、例えばDisl I/Oは キューイングして 他のサーバへ委譲
->ユーザのリクエストの受付に専念
2.ロジックは基本的に非同期処理(scalaのFutureライブラリを利用している)
- Finagle
NettyをベースのRPCフレームワーク
Twitter社が提供している、
非同期前提でアクションを書きやすい
2 他の大規模webサービスの事例もある
・Twitter, Tublr, Foursquare, Pinterest
3 サーバだけで無くクライアントも提供している
Redis、Memcacheクライアントにも利用してる
- Qに積まれたEventの処理
例
ログ出力
GREE内部システムへ問い合わせ
DBにstore等..
複雑な処理を並行で効率良く捌く際の問題点
デッドロック、競合
- 並行・分散処理をより簡単に書くためのフレームワーク
特徴は3つ
1 共有データを処理する必要がない=> 競合、デッドロックで悩むことが無い
2 ロジックを親と子で階層構造で分けることができ、ロジックの分離・分散させやすい
3 耐障害性
- コードを使って、
Akkaが何故、並行処理をやりやすいか説明します
上と下は親子関係になっている
親はEventを子に割り振る
子はEventをログに出力する
- まず親が受け取ったEventの中から、
種類によって処理を変えます
赤線で囲まれた処理を説明していきます
- 子にEventを送る
Eventはコピーされたもの =>共有オブジェクトの管理から解放されます
- 受け取った子はログに出力する
これをデッドロックや競合なしで、並行で複数走っている
- 接続しているユーザへEventをStreamで送信している
接続数をできるだけ増やす工夫
1. ユーザ情報をメモリ上で管理している。Disk I/Oを減らしている
2. AkkaやFinagleを利用した非同期処理をここでも利用
Eventbus同様にいくつかの処理をAkkaで処理している
1 Eventをユーザへ送信
2 ユーザ情報の更新
3 KeepAliveの送信
- アーキテクチャの特徴としてQによってアプリケーションサーバを分けている
フレームワークはFinagle,Akka,を採用している
- ここからは長谷川がお話します
- Gangliaというソフトウェアでヒープ領域を計測していたときの実際のグラフです。
左側が急上昇しているのはプログラムに一つおかしなところがあったからで、そこを修正してからは右側のように平穏で、リリース後は一度もFullGCが起きていません。
そこでこれからどのようにFullGCを防いできたかについて話します。
- FullGCが起こる原理から説明
JVMを使ってるからにはストップザ・ワールドを防ぐ
なぜなら、サービスが一時的に停止してしまうから
そこで、なるべくYoungでGCを起こすようにしたい
もっというなら、Oldにobjectが移動しないようにしたい
- Old領域にobjectが移動してしまう原因の1つがobjectへの参照が開放されないこと
参照が開放されない原因はいくつかあって
1つ目が、副作用のあるメソッドを使うことです
2つ目が、objectの使い回し
3つ目が、使用したリソースを開放しない
- これらの原因は開発者が認識することは意外に難しく、日頃から意識しておく必要があります
わたしたちのチームでは短命オブジェクトを作るということを心がけてきました
- 短命オブジェクトとはYoungで回収されるobjectを指す
この短命オブジェクトを作るために、基本valを使う
Var のようなmutableな変数を極力使わず、長く参照を残さないようにする
この例は、チャットの会話情報をDBから引いてきて、それを変更し、保存するコード
全てvalで書かれていることがわかるように、conversationのparticipantIdsのみを部分的に変更するのではなく、新しいobjectを生成する
このような工夫を至るところでおこなった結果、FullGCが起きていないことにつながったのではないか
今でも大きな変更を行うときには、jmapで変に参照が残っていないか確認したりしながら運用をしています。
- Shading分かる?
なぜ、shardingをする必要あったか
- Shading分かる?
なぜ、shardingをする必要あったか
- Shading分かる?
なぜ、shardingをする必要あったか
- グリーチャットのようなI/Oが多く、ユーザーもそれなりに多いサービスになると、ストレージもスレールアウトできるように
Sharding、つまりDBの水平分割をする必要があった
Cascadeがあったが、PHP用でScala用じゃなかった
そこでAuroraを作って、OSS化した
ここまで聞くと、おおー、上手くやってるなと思う方もいるかもしれないですが、
実際はアプリケーションの開発とAuroraの開発が同時並行で進んでしまったため、途中でAuroraを組み込む必要がでてきました。
この影響で広範囲にわたって修正する必要があり、これに1ヶ月以上費やしたかと思います。
これはいい教訓になりました
- 次はUUIDとInnoDBの相性で苦労した話
- スライドに描かれた図
横軸:100万レコード
縦軸:Insertにかかる時間
緑がUUIDを利用した際のIntertTime
Insertの速度が段違い
つまり、UUIDをPrimary keyにするのはアンチパターン
- なんでこんな話をしているかというと、わたしたちがUUIDをPrimary keyとして利用していたから
UUIDの悪いところはランダムインサートを引き起こすところ
しかし、プログラムの設計上、AUTO_INCREMENTで採番したIDを利用することができない
ので、自分たちでID生成ライブラリを作成
TwitterのSnowflakeを参考に
採番したIDは生成時刻でソートできるため、Insertするときにもほぼほぼシーケンシャルになる
Snowflakeを使わなかったのは、Zookeeperで専用のID生成サーバーを管理する必要があったため、コストが高い
自分たちで作ったCornflakeというライブラリはもっとlightに使える
- 苦労したことのまとめ
JVM周りではFull GCを起こさないように短命オブジェクトを作るよう意識がけていました
ライブラリを自作した話では
Shardingライブラリを途中で組み込んで大変だったこと
それをOSSにしたこと
Snowflakeを参考にしてシーケンシャルインサートできるID生成ライブラリを作成したこと
- 全体のまとめ
Scalaを選んだ理由は、並行プログラミングとの親和性が大きかった
チームのScala力向上はコストが高いので、それなりの時間を割いてチーム全体で取り組む必要がある
Scalaは他の言語と比べると若い言語なので、ライブラリを自作したり、利用している外部ライブラリにプルリクエストを送るということは当たり前
最後に…