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
700
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
310
RailsGirls Linz Lightning Talk
msch
0
140
Erlang for Rubyists
msch
4
700
Whirlwind Tour of Erlang
msch
1
270
Other Decks in Programming
See All in Programming
それ、本当に安全? ファイルアップロードで見落としがちなセキュリティリスクと対策
penpeen
7
3.9k
izumin5210のプロポーザルのネタ探し #tskaigi_msup
izumin5210
1
130
ぼくの開発環境2026
yuzneri
0
230
dchart: charts from deck markup
ajstarks
3
990
CSC307 Lecture 01
javiergs
PRO
0
690
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
2.3k
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
16
6.1k
CSC307 Lecture 03
javiergs
PRO
1
490
今こそ知るべき耐量子計算機暗号(PQC)入門 / PQC: What You Need to Know Now
mackey0225
3
380
Automatic Grammar Agreementと Markdown Extended Attributes について
kishikawakatsumi
0
190
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
620
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
580
Featured
See All Featured
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
290
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
640
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
120
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
Navigating Team Friction
lara
192
16k
How to make the Groovebox
asonas
2
1.9k
Building Adaptive Systems
keathley
44
2.9k
Faster Mobile Websites
deanohume
310
31k
The Cult of Friendly URLs
andyhume
79
6.8k
How to build a perfect <img>
jonoalderson
1
4.9k
Evolving SEO for Evolving Search Engines
ryanjones
0
120
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.3k
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