Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Game Servers in OTP
Search
Martin Schürrer
July 26, 2014
Programming
9
670
Game Servers in OTP
Given at ElixirConf 2014
Martin Schürrer
July 26, 2014
Tweet
Share
More Decks by Martin Schürrer
See All by Martin Schürrer
Deploying Elixir
msch
3
290
RailsGirls Linz Lightning Talk
msch
0
100
Erlang for Rubyists
msch
4
620
Whirlwind Tour of Erlang
msch
1
240
Other Decks in Programming
See All in Programming
Arm移行タイムアタック
qnighy
0
320
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
100
subpath importsで始めるモック生活
10tera
0
300
ペアーズにおけるAmazon Bedrockを⽤いた障害対応⽀援 ⽣成AIツールの導⼊事例 @ 20241115配信AWSウェビナー登壇
fukubaka0825
6
1.9k
3rd party scriptでもReactを使いたい! Preact + Reactのハイブリッド開発
righttouch
PRO
1
600
WebフロントエンドにおけるGraphQL(あるいはバックエンドのAPI)との向き合い方 / #241106_plk_frontend
izumin5210
4
1.4k
LLM生成文章の精度評価自動化とプロンプトチューニングの効率化について
layerx
PRO
2
190
ローコードSaaSのUXを向上させるためのTypeScript
taro28
1
610
카카오페이는 어떻게 수천만 결제를 처리할까? 우아한 결제 분산락 노하우
kakao
PRO
0
110
最新TCAキャッチアップ
0si43
0
140
弊社の「意識チョット低いアーキテクチャ」10選
texmeijin
5
24k
型付き API リクエストを実現するいくつかの手法とその選択 / Typed API Request
euxn23
8
2.2k
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Become a Pro
speakerdeck
PRO
25
5k
Documentation Writing (for coders)
carmenintech
65
4.4k
Testing 201, or: Great Expectations
jmmastey
38
7.1k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
27
4.3k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
229
52k
Six Lessons from altMBA
skipperchong
27
3.5k
Practical Orchestrator
shlominoach
186
10k
10 Git Anti Patterns You Should be Aware of
lemiorhan
654
59k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
47
2.1k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
506
140k
Music & Morning Musume
bryan
46
6.2k
Transcript
Game Servers in OTP
@msch featurebranch.com
None
None
None
None
Architecture big-picture The Table-FSM Life of an in-game event Real
world concerns BoldPoker <3 Elixir Lessons Learned & QA
HA keepalived haproxy active Erlang active Erlang standby Erlang standby
PostgreSQL haproxy standby
Erlang active
OTP Apps :cardgame :storage :network :gameserver
:cardgame OTP APP {Table,9} {Table,8} {Table,7} {Table,6}
:network OTP APP WebSocket :cowboy Flash (TCP) :ranch
:storage OTP APP PSQLDBWorker TableIdSequence
:gameserver OTP APP {Player,1} {Player,2} {Player,3}
Architecture big-picture The Table-FSM Life of an in-game event Real
world concerns BoldPoker <3 Elixir Lessons Learned & QA
None
DealCards Knocking DealCards Play Result idle playing
[ {DealCards, [cards_to_deal, :private]}, {Knocking, [5000]}, {DealCards, [cards_to_deal, :private]}, {Negotiation,
[]}, {Play, [contra_enabled: true]}, {Play, []}, {Play, []}, … {Play, []}, {Play, []}, {Result, []} ]
gen_fsm:send_event/2 -----> Module:StateName/2 gen_fsm:send_event/2 -----> Table.playing/2 {:next_state, next_state_name, new_state_data} !
{:stop, reason, new_state_data}
DealCards Knocking DealCards Play Result idle playing
{:next_stage, new_stage_data, new_state_data} ! {:end_game, new_stage_data, new_state_data} ! Table.broadcast_event {:next_state,
next_state_name, new_state_data} ! {:stop, reason, new_state_data} ! GenServer.reply Table.playing/2 -----> DealCards.playing/3
DealCards Knocking DealCards Play Result idle playing
Knocking DealCards Play Result idle playing
DealCards Play Result idle playing
Play Result idle playing {:game_event, …}
Play Result idle playing {:game_event, …}
Architecture big-picture The Table-FSM Life of an in-game event Real
world concerns BoldPoker <3 Elixir Lessons Learned & QA
P1 P2 P3 P4 {Table,9} {Player,1}
P1 P2 P3 P4 {Table,9} {Player,1} Ports
P1 P2 P3 P4 {Table,9} {Player,1}
P1 P2 P3 P4 {Table,9} {Player,1} {:game_event, :must_play_card}
P1 {Table,9} {Player,1} {:game_event, …}
P1 {Table,9} {Player,1} { "type": "mustPlayCard" } {:game_event, :must_play_card} ProtocolJSON.write/1
P1 {Table,9} {Player,1}
P1 {Table,9} {Player,1} { "type": "playACard", "card": "XH" } {:game_event,
{:play_card,{:ten,:hearts}} ProtocolJSON.parse/1
P1 {Table,9} {Player,1} {:game_event, …}
Architecture big-picture The Table-FSM Life of an in-game event Real
world concerns BoldPoker <3 Elixir Lessons Learned & QA
P1 P2 P3 P4 {Table,9} {Player,1}
haproxy active Erlang active Erlang standby Erlang standby
haproxy active Erlang standby Erlang active Erlang standby
:rpc.multicall(GameServer, switch_active, [node()])
P1 P2 P3 P4 {Table,9} P5 P6 P7 old
P1 P2 P3 P4 {Table,9} P5 P6 P7 old
P1 P2 P3 P4 {Table,9} old
P1 P2 P3 P4 {Table,9} old new {TableMigrator,9}
P1 P2 P3 P4 {Table,9} old new {TableMigrator,9}
P1 P2 P3 P4 {Table,9} P5 P6 P7 old new
{TableMigrator,9}
P1 P2 P3 P4 {Table,9} P5 P6 P7 old new
{TableMigrator,9}
P1 P2 P3 P4 {Table,9} P5 P6 P7 old new
{TableMigrator,9}
P1 P2 P3 P4 {Table,9} P5 P6 P7 old new
{TableMigrator,9}
P1 P2 P3 P4 {Table,9} P5 P6 P7 old new
ConnectionProxy {TableMigrator,9}
P1 P2 P3 P4 {Table,9} P5 P6 P7 old new
{TableMigrator,9}
P1 P2 P3 P4 {Table,9} old new {TableMigrator,9}
None
DealCards Knocking DealCards Play Result idle playing
P1 P2 P3 P4 old new {TableMigrator,9} portable_state
P1 2 3 4 old new { portable_state portable_state %{table_id:
9, player_ids: [1,2,3,4], positions: %{1 => 3, 2 => 0, 3 => 1, 4 => 2}, modifications: [:short_hand], last_game_id: 123 }
P1 P2 P3 P4 old new {TableMigrator,9}
old new {TableMigrator,9}
old new {TableMigrator,9}
None
None
old new {TableMigrator,9}
old new {TableMigrator,9} P1
old new {TableMigrator,9} P2 P3 P4 P1
old new {TableMigrator,9} P2 P3 P4 P1 portable_state
old new P2 P3 P4 P1 {Table,9}
None
P2 P3 P4 P1 {Table,9}
Architecture big-picture The Table-FSM Life of an in-game event Real
world concerns BoldPoker <3 Elixir Lessons Learned & QA
All-in! Elixir Rewrite
Why? Extensibility goals stdlib mix ExUnit
:gen_fsm :ets GenServer Supervisor alias :ets, as: ETS
proper Tests send_events(ClientDeviceIDs, ClientIP) -> ?FORALL(Event, event(), ?FORALL(Data, event_data(Event), ...
parse_transform ?
Architecture big-picture The Table-FSM Life of an in-game event Moving
tables across servers BoldPoker <3 Elixir Lessons Learned & QA
Perform en/decoding at the system border P1 { "type": "playACard",
"card": "XH" } {:game_event, {:play_card,{:ten,:hearts}} ProtocolJSON.parse/1 WS
Create your own behaviours for fun better reusability and profit
easier testing {:next_stage, new_stage_data, new_state_data} {:end_game, new_stage_data, new_state_data}
Distributed Erlang makes hard things easy ConnectionProxy
DB failure? We got all data already, so finish the
game, then just store result on disk
Thank you! @msch featurebranch.com