Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add controller performance metrics #391

Merged
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9283e2f
Added GameServer control performance metrics;
dsmith111 Sep 15, 2022
466f2af
Merge branch 'main' of https://github.com/dsmith111/thundernetes into…
dsmith111 Sep 15, 2022
71fd931
Merge branch 'main' into smithdavi/add-controller-performance-metrics
dsmith111 Sep 15, 2022
f432e82
Update monitoring documentation;
dsmith111 Sep 15, 2022
baa71f4
Merge branch 'smithdavi/add-controller-performance-metrics' of https:…
dsmith111 Sep 15, 2022
41e68da
Update yaml
dsmith111 Sep 17, 2022
e9cd4fb
Fix capitalization
dsmith111 Sep 17, 2022
293efc1
Revert extra changes triggering installfile alret
dsmith111 Sep 17, 2022
dc28b13
Handle dereferencing;
dsmith111 Sep 18, 2022
c2a122e
Add pointers
dsmith111 Sep 19, 2022
38c7592
Decreasing time diff
dsmith111 Sep 19, 2022
dbd8b71
Merge branch 'main' into smithdavi/add-controller-performance-metrics
dsmith111 Sep 19, 2022
ecebe2b
PR Updates;
dsmith111 Sep 19, 2022
d8f0d88
Merge branch 'smithdavi/add-controller-performance-metrics' of github…
dsmith111 Sep 19, 2022
e41d915
Add patching exception
dsmith111 Sep 21, 2022
b7ed55e
Merge branch 'main' into smithdavi/add-controller-performance-metrics
dsmith111 Sep 21, 2022
0be080c
Change metric emission to nodeagent
dsmith111 Sep 25, 2022
20be9c0
Update dashboard
dsmith111 Sep 25, 2022
6e30235
Merge branch 'main' of github.com:dsmith111/thundernetes into smithda…
dsmith111 Sep 25, 2022
e0fc978
Revert test
dsmith111 Sep 25, 2022
a67fbb9
Cleanup deletes
dsmith111 Sep 25, 2022
0cd6e86
Minor tweaks
dsmith111 Sep 25, 2022
c4217f8
Conditional
dsmith111 Sep 25, 2022
77b1c88
PR Suggested changes
dsmith111 Sep 26, 2022
feab86c
Remove spacing added to gameserverbuild
dsmith111 Sep 26, 2022
d0dbb61
Remove empty line in nodeagent
dsmith111 Sep 26, 2022
b3e07d9
Renaming
dsmith111 Sep 26, 2022
fd2fbae
Update dashboard
dsmith111 Sep 26, 2022
9318c35
Remove metric
dsmith111 Sep 26, 2022
1861a24
Merge branch 'main' into smithdavi/add-controller-performance-metrics
dgkanatsios Sep 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@ installfilesdev

.uptodate

# vscode settings
.vscode

# allocator compiled plugin
kubectl-gameserver
5 changes: 5 additions & 0 deletions cmd/nodeagent/nodeagentmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,15 @@ func (n *NodeAgentManager) gameServerCreatedOrUpdated(obj *unstructured.Unstruct
// or that the NodeAgent crashed and we're having a new instance
// in any case, we're adding the details to the map
logger.Infof("GameServer %s/%s does not exist in cache, we're creating it", gameServerNamespace, gameServerName)
// save actual gameserver creation time
creationTimeStamp := obj.GetCreationTimestamp()

gsdi = &GameServerInfo{
GameServerNamespace: gameServerNamespace,
Mutex: &sync.RWMutex{},
GsUid: obj.GetUID(),
CreationTime: n.nowFunc().UnixMilli(),
CreationTimeStamp: &creationTimeStamp,
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved
BuildName: gameServerBuildName,
MarkedUnhealthy: false,
// we're not adding details about health/state since the NodeAgent might have crashed
Expand Down Expand Up @@ -454,6 +458,7 @@ func (n *NodeAgentManager) updateHealthAndStateIfNeeded(ctx context.Context, hb
status.ReachedInitializingOn = &now
} else if hb.CurrentGameState == GameStateStandingBy {
status.ReachedStandingByOn = &now
GameServerCreateDuration.WithLabelValues(gsd.BuildName).Set(getStateDuration(status.ReachedStandingByOn, gsd.CreationTimeStamp))
}
}

Expand Down
21 changes: 16 additions & 5 deletions cmd/nodeagent/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
)
Expand Down Expand Up @@ -58,6 +59,15 @@ var (
Name: "connected_players",
Help: "Number of connected players per GameServer",
}, []string{"namespace", "ServerName", "BuildName"})

GameServerCreateDuration = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "thundernetes",
Name: "gameserver_create_duration",
Help: "Time taken to create a GameServers",
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved
},
[]string{"BuildName"},
)
)

// HeartbeatRequest contains data for the heartbeat request coming from the GSDK running alongside GameServer
Expand Down Expand Up @@ -101,9 +111,10 @@ type GameServerInfo struct {
GameServerNamespace string
ConnectedPlayersCount int
Mutex *sync.RWMutex
GsUid types.UID // UID of the GameServer object
CreationTime int64 // time when this GameServerInfo was created in the nodeagent
LastHeartbeatTime int64 // time since the nodeagent received a heartbeat from this GameServer
MarkedUnhealthy bool // if the GameServer was marked unhealthy by a heartbeat condition, used to avoid repeating the patch
BuildName string // the name of the GameServerBuild that this GameServer belongs to
GsUid types.UID // UID of the GameServer object
CreationTime int64 // time when this GameServerInfo was created in the nodeagent
CreationTimeStamp *metav1.Time // time when the GameServer was created
LastHeartbeatTime int64 // time since the nodeagent received a heartbeat from this GameServer
MarkedUnhealthy bool // if the GameServer was marked unhealthy by a heartbeat condition, used to avoid repeating the patch
BuildName string // the name of the GameServerBuild that this GameServer belongs to
}
12 changes: 12 additions & 0 deletions cmd/nodeagent/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package main
import (
"errors"
"fmt"
"math"
"net/http"
"os"
"strconv"
"strings"
"time"

log "github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
Expand Down Expand Up @@ -104,6 +107,15 @@ func getLogger(gameServerName, gameServerNamespace string) *log.Entry {
return log.WithFields(log.Fields{"GameServerName": gameServerName, "GameServerNamespace": gameServerNamespace})
}

// getStateDuration determine whether to use an existing saved time variables or the current time for state duration
func getStateDuration(endTime *metav1.Time, startTime *metav1.Time) float64 {
// If the end time state is missing, use the current time
if endTime == nil {
return math.Abs(float64(time.Since(startTime.Time).Milliseconds()))
}
return math.Abs(float64(endTime.Time.Sub(startTime.Time).Milliseconds()))
}

// sanitize removes new line characters from the string
// https://codeql.github.com/codeql-query-help/go/go-log-injection/
func sanitize(s string) string {
Expand Down
4 changes: 4 additions & 0 deletions docs/howtos/monitoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,13 @@ There is a custom Grafana dashboard example that visualizes some of this data in
| connected_players | Gauge | nodeagent |
| gameservers_current_state_per_build | Gauge | controller-manager |
| gameservers_created_total | Counter | controller-manager |
| gameservers_create_duration | Gauge | controller-manager |
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved
| gameservers_reconcile_standby_duration | Gauge | controller-manager |
| gameservers_sessionended_total | Counter | controller-manager |
| gameservers_crashed_total | Counter | controller-manager |
| gameservers_deleted_total | Counter | controller-manager |
| gameservers_end_duration | Gauge | controller-manager |
| gameservers_clean_up_duration | Gauge | controller-manager |
| allocations_total | Counter | controller-manager |

## More pictures
Expand Down
2 changes: 2 additions & 0 deletions pkg/operator/api/v1alpha1/gameserver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ type GameServerStatus struct {
Health GameServerHealth `json:"health,omitempty"`
// State defines the state of the game server (Initializing, StandingBy, Active etc.)
State GameServerState `json:"state,omitempty"`
// The Previously known manually set state
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved
PrevState GameServerState `json:"prevState,omitempty"`
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved
// PublicIP is the PublicIP of the game server
PublicIP string `json:"publicIP,omitempty"`
// Ports is a concatenated list of the ports this game server listens to
Expand Down
29 changes: 19 additions & 10 deletions pkg/operator/controllers/gameserverbuild_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"runtime"
"sort"
"sync"
"time"

mpsv1alpha1 "github.com/playfab/thundernetes/pkg/operator/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -140,6 +141,7 @@ func (r *GameServerBuildReconciler) Reconcile(ctx context.Context, req ctrl.Requ

// calculate counts by state so we can update .status accordingly
var activeCount, standingByCount, crashesCount, initializingCount, pendingCount int
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved

for i := 0; i < len(gameServers.Items); i++ {
gs := gameServers.Items[i]

Expand All @@ -156,6 +158,7 @@ func (r *GameServerBuildReconciler) Reconcile(ctx context.Context, req ctrl.Requ
if err := r.Delete(ctx, &gs); err != nil {
return ctrl.Result{}, err
}
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved

GameServersSessionEndedCounter.WithLabelValues(gsb.Name).Inc()
r.expectations.addGameServerToUnderDeletionMap(gsb.Name, gs.Name)
r.Recorder.Eventf(&gsb, corev1.EventTypeNormal, "Exited", "GameServer %s session completed", gs.Name)
Expand Down Expand Up @@ -183,19 +186,19 @@ func (r *GameServerBuildReconciler) Reconcile(ctx context.Context, req ctrl.Requ
// calculate the total amount of servers not in the active state
nonActiveGameServersCount := standingByCount + initializingCount + pendingCount

// Evaluate desired number of servers against actual
var totalNumberOfGameServersToDelete int = 0

// user has decreased standingBy numbers
if nonActiveGameServersCount > gsb.Spec.StandingBy {
totalNumberOfGameServersToDelete := int(math.Min(float64(nonActiveGameServersCount-gsb.Spec.StandingBy), maxNumberOfGameServersToDelete))
err := r.deleteNonActiveGameServers(ctx, &gsb, &gameServers, totalNumberOfGameServersToDelete)
if err != nil {
return ctrl.Result{}, err
}
totalNumberOfGameServersToDelete += int(math.Min(float64(nonActiveGameServersCount-gsb.Spec.StandingBy), maxNumberOfGameServersToDelete))
}

// we need to check if we are above the max
// we also need to check if we are above the max
// this can happen if the user modifies the spec.Max during the GameServerBuild's lifetime
if nonActiveGameServersCount+activeCount > gsb.Spec.Max {
totalNumberOfGameServersToDelete := int(math.Min(float64(nonActiveGameServersCount+activeCount-gsb.Spec.Max), maxNumberOfGameServersToDelete))
totalNumberOfGameServersToDelete += int(math.Min(float64(totalNumberOfGameServersToDelete+(nonActiveGameServersCount+activeCount-gsb.Spec.Max)), maxNumberOfGameServersToDelete))
}
if totalNumberOfGameServersToDelete > 0 {
err := r.deleteNonActiveGameServers(ctx, &gsb, &gameServers, totalNumberOfGameServersToDelete)
if err != nil {
return ctrl.Result{}, err
Expand All @@ -207,13 +210,16 @@ func (r *GameServerBuildReconciler) Reconcile(ctx context.Context, req ctrl.Requ
// we attempt to create the missing number of game servers, but we don't want to create more than the max
// an error channel for the go routines to write errors
errCh := make(chan error, maxNumberOfGameServersToAdd)

// Time how long it takes to trigger new standby gameservers
standByReconcileStartTime := time.Now()
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved
// a waitgroup for async create calls
var wg sync.WaitGroup
for i := 0; i < gsb.Spec.StandingBy-nonActiveGameServersCount &&
i+nonActiveGameServersCount+activeCount < gsb.Spec.Max &&
i < maxNumberOfGameServersToAdd; i++ {
wg.Add(1)
go func() {
go func(standByStartTime time.Time) {
defer wg.Done()
newgs, err := NewGameServerForGameServerBuild(&gsb, r.PortRegistry)
if err != nil {
Expand All @@ -227,9 +233,11 @@ func (r *GameServerBuildReconciler) Reconcile(ctx context.Context, req ctrl.Requ
r.expectations.addGameServerToUnderCreationMap(gsb.Name, newgs.Name)
GameServersCreatedCounter.WithLabelValues(gsb.Name).Inc()
r.Recorder.Eventf(&gsb, corev1.EventTypeNormal, "Creating", "Creating GameServer %s", newgs.Name)
}()
GameServersStandByReconcileDuration.WithLabelValues(gsb.Name).Set(float64(time.Since(standByStartTime).Milliseconds()))
}(standByReconcileStartTime)
}
wg.Wait()

if len(errCh) > 0 {
return ctrl.Result{}, <-errCh
}
Expand Down Expand Up @@ -325,6 +333,7 @@ func (r *GameServerBuildReconciler) deleteNonActiveGameServers(ctx context.Conte
// a waitgroup for async deletion calls
var wg sync.WaitGroup
deletionCalls := 0

// we sort the GameServers by state so that we can delete the ones that are empty state or Initializing before we delete the StandingBy ones (if needed)
// this is to make sure we don't fall below the desired number of StandingBy during scaling down
sort.Sort(ByState(gameServers.Items))
Expand Down
8 changes: 8 additions & 0 deletions pkg/operator/controllers/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ var (
},
[]string{"BuildName"},
)
GameServersStandByReconcileDuration = registry.NewGaugeVec(
dsmith111 marked this conversation as resolved.
Show resolved Hide resolved
prometheus.GaugeOpts{
Namespace: "thundernetes",
Name: "gameservers_reconcile_standby_duration",
Help: "Time it took to begin initialization for all new GameServers",
},
[]string{"BuildName"},
)
GameServersSessionEndedCounter = registry.NewCounterVec(
prometheus.CounterOpts{
Namespace: "thundernetes",
Expand Down
Loading