-
Notifications
You must be signed in to change notification settings - Fork 822
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Docs: High Density Integration Pattern (#2270)
* Docs: High Density Integration Pattern Documentation explaining how to use the new advanced allocation features to run multiple concurrent game sessions in a single `GameServer` instance. Closes #1239 * Review updates. Co-authored-by: Robert Bailey <[email protected]>
- Loading branch information
1 parent
fbe5380
commit b77874b
Showing
5 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
site/content/en/docs/Integration Patterns/high-density-gameservers.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
--- | ||
title: "High Density GameServers" | ||
linkTitle: "High Density GameServers" | ||
date: 2021-08-31 | ||
weight: 70 | ||
description: > | ||
How to run multiple concurrent game sessions in a single GameServer process. | ||
--- | ||
|
||
{{< alpha title="Allocation Player Filter and Allocation State Filter" gate="PlayerAllocationFilter,StateAllocationFilter" >}} | ||
|
||
Depending on the setup and resource requirements of your game server process, sometimes it can be a more economical | ||
use of resources to run multiple concurrent game sessions from within a single `GameServer` instance. | ||
|
||
The tradeoff here is that this requires more management on behalf of the integrated game server process and external | ||
systems, since it works around the common Kubernetes and/or Agones container lifecycle. | ||
|
||
Utilising the new allocation `gameServerState` filter as well as the existing ability to edit the | ||
`GameServer` labels at both [allocation time]({{% ref "/docs/Reference/gameserverallocation.md" %}}), and from | ||
within the game server process, [via the SDK]({{% ref "/docs/Guides/Client SDKs/_index.md#setlabelkey-value" %}}), | ||
means Agones is able to atomically remove a `GameServer` from the list of potentially allocatable | ||
`GameServers` at allocation time, and then return it back into the pool of allocatable `GameServers` if and when the | ||
game server process deems that is has room to host another game session. | ||
|
||
<a href="../../../diagrams/high-density.puml.png" target="_blank"> | ||
<img src="../../../diagrams/high-density.puml.png" alt="High Density Allocation Diagram" /> | ||
</a> | ||
|
||
{{< alert title="Info" color="info">}} | ||
To watch for Allocation events, there is the initial `GameServer.status.state` change from `Ready` to `Allocated`, | ||
but it is also useful to know that the value of `GameServer.metadata.annotations["agones.dev/last-allocated"]` will | ||
change as it is set by Agones with each allocation with the current timestamp, regardless of if there | ||
is a state change or not. | ||
{{< /alert >}} | ||
|
||
## Example `GameServerAllocation` | ||
|
||
The below `Allocation` will first attempt to find a `GameServer` from the `Fleet` `simple-udp` that is already | ||
Allocated and also has the label `agones.dev/sdk-gs-session-ready` with the value of `true`. | ||
|
||
The above condition indicates that the matching game server process behind the matched `GameServer` record is able to | ||
accept another game session at this time. | ||
|
||
If an Allocated `GameServer` does not exist with the desired labels, then use the next selector to allocate a Ready | ||
`GameServer` from the `simple-udp` `Fleet`. | ||
|
||
Whichever condition is met, once allocation is made against a `GameServer`, its label of `agones.dev/sdk-gs-session-ready` | ||
will be set to the value of `false` and it will no longer match the first selector, thereby removing it from any | ||
future allocations with the below schema. | ||
|
||
It will then be up to the game server process to decide on if and when it is appropriate to set the | ||
`agones.dev/sdk-gs-session-ready` value back to `true`, thereby indicating that it can accept another concurrent | ||
gameplay session. | ||
|
||
```yaml | ||
apiVersion: "allocation.agones.dev/v1" | ||
kind: GameServerAllocation | ||
spec: | ||
selectors: | ||
- matchLabels: | ||
agones.dev/fleet: simple-udp | ||
agones.dev/sdk-gs-session-ready: "true" # this is important | ||
gameServerState: Allocated # new state filter: allocate from Allocated servers | ||
- matchLabels: | ||
agones.dev/fleet: simple-udp | ||
gameServerState: Ready # Allocate out of the Ready Pool (which would be default, so backward compatible) | ||
metadata: | ||
labels: | ||
agones.dev/sdk-gs-session-ready: "false" # this removes it from the pool | ||
``` | ||
{{< alert title="Info" color="info">}} | ||
It's important to note that the labels that the `GameServer` process use to add itself back into the pool of | ||
allocatable instances, must start with the prefix `agones.dev/sdk-`, since only labels that have this prefix are | ||
available to be [updated from the SDK]({{% ref "/docs/Guides/Client SDKs/_index.md#setlabelkey-value" %}}). | ||
{{< /alert >}} | ||
|
||
## Next Steps | ||
|
||
* View the details about [using the SDK]({{% ref "/docs/Guides/Client SDKs/_index.md#setlabelkey-value" %}}) to set | ||
labels on the `GameServer`. | ||
* Check all the options available on [`GameServerAllocation`]({{% ref "/docs/Reference/gameserverallocation.md" %}}). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
@startuml | ||
participant Matchmaker | ||
participant Agones | ||
participant "Game Server\nProcess" as Binary | ||
participant SDK | ||
participant "GameServer\nResource" as GameServer | ||
box "Game Server Pod" | ||
participant Binary | ||
participant SDK | ||
end box | ||
|
||
== GameServer Start == | ||
|
||
Agones -> GameServer: GameServer created through\na <i>Fleet</i> configuration | ||
activate GameServer | ||
GameServer -> Binary: Agones creates a Pod with the\nconfigured Game Server Container | ||
activate Binary | ||
activate SDK | ||
Binary -> SDK: SDK.WatchGameServer() | ||
note right | ||
Use the SDK Watch function | ||
to watch and react to allocation | ||
events | ||
end note | ||
|
||
Binary -> SDK: SDK.Ready() | ||
note right | ||
Call <i>Ready()</i> when the | ||
Game Server can take player | ||
connections and is able to | ||
be allocated. | ||
end note | ||
GameServer <-- SDK: Update to <i>Ready</i> State | ||
|
||
== No allocated <i>GameServers</i> == | ||
|
||
Matchmaker -> Agones: Create: <i>GameServerAllocation</i> | ||
note left | ||
The <i>GameServerAllocation</i> is implemented to | ||
optionally select an already allocated <i>GameServer</i> | ||
with <i>metadata.labels["agones.dev/sdk-gs-session-ready"] = "true"</i> | ||
if one exists. At this stage, one does not, so | ||
Agones will allocate a <i>Ready</i> <i>GameServer</i>. | ||
end note | ||
Agones -> GameServer: Finds a <i>Ready</i> <i>GameServer</i>.\n\nSets <i>status.state</i> to <i>Allocated</i> State\nand <i>metadata.labels["agones.dev/sdk-gs-session-ready"] = "false"</i>\nand <i>metadata.annotations["agones.dev/last-allocated"] = current timestamp</i> | ||
note left | ||
By setting the label "agones.dev/sdk-gs-session-ready" to "false" | ||
this remove the `GameServer` from possibly being | ||
re-allocated until it knows it can handle another session. | ||
end note | ||
Matchmaker <-- Agones : <i>GameServerAllocation</i> is returned\nwith <i>GameServer</i> details\nincluding IP and port to connect to. | ||
|
||
SDK --> Binary: Sends SDK.WatchGameServer()\nevent for Allocation. | ||
note right | ||
This initial allocation can be determined | ||
as a change in <i>GameServer.status.state</i> | ||
from <i>Ready</i> to <i>Allocated</i> | ||
end note | ||
|
||
Binary -> SDK: SDK.SetLabel("gs-session-ready", "true") | ||
note right | ||
Since this game process can handle <i>n</i> | ||
concurrent sessions, set this label to match | ||
optional allocation label selectors, so it can be | ||
re-allocated. | ||
(See example below for more details) | ||
end note | ||
SDK --> GameServer: Sets <i>metadata.labels["agones.dev/sdk-gs-session-ready"] = "true"</i> | ||
|
||
== Allocated <i>GameServers</i> with room for more sessions == | ||
|
||
Matchmaker -> Agones: Create: <i>GameServerAllocation</i> | ||
note left | ||
The <i>GameServerAllocation</i> will this time | ||
find the Allocated <i>GameServer</i> with the label | ||
<i>metadata.labels["agones.dev/sdk-gs-session-ready"] = "true"</i>, | ||
indicating that it can accept more | ||
concurrent game sessions. | ||
end note | ||
Agones -> GameServer: Finds the Allocated <i>GameServer</i> with\n<i>metadata.labels["agones.dev/sdk-gs-session-ready"] = "true"</i>.\n\nSets <i>metadata.labels["agones.dev/sdk-gs-session-ready"] = "false"</i>\nand <i>metadata.annotations["agones.dev/last-allocated"] = current timestamp</i>. | ||
note right | ||
This is the a <i>GameServer</i> that has room | ||
for another concurrent game session. | ||
end note | ||
Matchmaker <-- Agones: returns <i>Allocated GameServer</i> record | ||
|
||
SDK --> Binary: Sends SDK.WatchGameServer()\nevent for Allocation. | ||
note right | ||
The game server process can watch for a change | ||
in <i>metadata.annotations["agones.dev/last-allocated"]</i> | ||
to determine there is an allocation event. | ||
end note | ||
|
||
alt <i>GameServer</i> can accept more concurrent sessions | ||
Binary -> SDK: SDK.SetLabel("gs-session-ready", "true") | ||
SDK --> GameServer: Sets <i>metadata.labels["agones.dev/sdk-gs-session-ready"] = "true"</i>. | ||
end alt | ||
note right | ||
If the <i>GameServer</i> can accept more | ||
concurrent sessions, reset the label | ||
<i>"agones.dev/sdk-gs-session-ready"</i> | ||
back to "true" | ||
end note | ||
|
||
== <i>GameServer</i> has completed <i>n</i> number of complete sessions == | ||
|
||
Binary -> SDK: SDK.Shutdown() | ||
note left | ||
The <i>GameServer</i> process tracks the number of sessions | ||
that it hosts, and after <i>n</i> number, calls <i>Shutdown()</i> | ||
to delete the <i>GameServer</i> resource and backing Pod. | ||
end note | ||
SDK --> GameServer: Update to <i>Shutdown</i> state. | ||
Agones -> GameServer: Deletes GameServer resource and backing Pod. | ||
destroy Binary | ||
destroy SDK | ||
destroy GameServer | ||
@enduml |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.