Skip to content

Latest commit

 

History

History
152 lines (145 loc) · 6.63 KB

README.md

File metadata and controls

152 lines (145 loc) · 6.63 KB

index-offset-scheduler

中文 | English

概述

index-offset-scheduler是一个自定义的kubernetes调度器。它可以让属于同一个GameServerSet的pod按照pod的索引编号滚动部署,使得每个节点上的 pod的索引的偏移量/差值尽可能得大。
对于滚动开服类的游戏,这是常见的需求场景:

  • 在游戏上线前,由于存在大量预约或者导量,需要提前准备较多的游戏服务。在k8s环境中,游戏服务的id 一般与pod编号存在对应关系。
  • 开服后,游戏服对应的pod负载会明显上升并导致所在机器的负载明显上升,如果临近的多个pod位于同一个node上, 例如pod-1和pod-2,短期内的pod的负载快速上升可能导致需要按照两个pod的所需的最高资源准备node配置。而一段时间后,随着活跃玩家的下降,机器的负载又会下降。
  • 因此在传统机器部署的场景下,常见的做法是:提前准备多台机器,将游戏服务按照滚动部署的方式部署,以使得节点能够部署较多的服务,并且不会面临短期内 单台机器承载多个游戏服的最高负载的风险。部署效果类似下方的分布:
    node1: game-1, game-4...
    node2: game-2, game-5...
    node3: game-3, game-6...

默认的k8s调度器会保障pod尽可能均匀的分布,但是不能确保每个节点上pod之间的编号差值尽可能大,甚至可能出现连续索引编号的两个pod分布在同一个节点上。 因此需要实现一个自定义调度器,使得每个节点上的 pod的索引的偏移量/差值尽可能尽可能得大。

部署

如果你安装了OpenKruiseGame,直接通过下面的命令安装:

# 如果你没有部署OKG,而希望通过StatefulSet类型的应用测试效果,你需要提前创建namespace: kruise-game-system
# kubectl create namespace kruise-game-system
kubectl apply -f deploy/index-offset-scheduler.yaml

使用示例

deploy目录下提供了示例test-gss.yaml,你分别可以用来测试OpenKruiseGame的GameServerSet的效果。
关键点在于指定pod.spec.schedulerName为index-offset-scheduler。

apiVersion: game.kruise.io/v1alpha1
kind: GameServerSet
metadata:
  name: test
  namespace: kube-system
spec:
  serviceName: ""
  replicas: 10
  gameServerTemplate:
    metadata:
      labels:
        app: test
    spec:
      schedulerName: index-offset-scheduler
      containers:
        - name: test
          image: nginx

说明

  • 自定义调度器是对打分逻辑的扩展,内置的其他调度器插件仍然会正常工作,因此打分不一定会完全影响到最终的绑定结果。你可以参考 KubeSchedulerConfiguration配置调度器的启动参数,通过配置插件 的启用与否和权重来控制最终的调度效果。例如你可以将index-offset-scheduler的权重增加至5:
    # configmap
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: index-offset-scheduler-config
      namespace: kruise-game-system
    data:
      scheduler-config.yaml: |
        # stable v1 after version 1.25
        apiVersion: kubescheduler.config.k8s.io/v1
        kind: KubeSchedulerConfiguration
        leaderElection:
          leaderElect: false
          resourceNamespace: kruise-game-system
          resourceName: index-offset-scheduler
        profiles:
          - schedulerName: index-offset-scheduler
            plugins:
              score:
                enabled:
                  - name: index-offset-scheduler
                    weight: 5
  • 兼容性: Scheduler Configuration 在kubernetes的1.25版本已经处于stable状态,已经在1.25和1.31版本的集群上测试可以正常工作。

工作原理

这个文档展示了自定义调度器的工作原理: Configure Multiple Schedulers。 index-offset-scheduler的核心工作原理如下:
假如集群中有3个节点: n1、n2、n3。此时每个节点上都没有指定的GameServerSet的pod。并且这3个节点的状态一致,即其他默认插件的打分一致。

n1: []   
n2: []   
n3: []

1、当pod-0被创建待调度时,由于每个节点上都没有属于指定的GameServerSet的pod(GameServer), 所以每个节点得分为100,pod可能被调度到任意一个节点。
2、如果pod-0倍绑定到n2,当pod-1被创建待待调度时,n1、n3的得分是100。n2的打分逻辑为,找出n2上小于当前待调度索引编号的最大值,将差值作为得分, 即1=1-0。
3、如果pod-1被绑定到n3,pod-2将被绑定到n1。现在pod的调度情况将如下所示:

n1: pod-2   
n2: pod-0    
n3: pod-1   

4、按照上方的打分规则,如果pod-3~pod-5被调度, 最终的调度器情况如下所示:

n1: pod-2, pod-5  
n2: pod-0, pod-3  
n3: pod-1, pod-4  

当你重建pod-2时,打分情况如下:

n1: 5(当节点上存在pod,但是最小的pod索引编号也大于当前编号,那么以节点上的最小索引编号作为差值)  
n2: 2=2-0 
n3: 1=2-1

pod-2将会被重新绑定至n1。 5、一些特别的例子: 如果你的节点超过了100个,或者你使用了Open Kruise Game框架跳过了许多编号,使得pod的分布如下:

n1: pod-2, pod-105  
n2: pod-4, pod-107  
n3: pod-7, pod-108  

如果你删除了pod-4,最终的得分如下:

n1: 2=4-2
n2: 107
n3: 7

所有节点的打分最终会被归一化处理以确保小于100:

n1: 1 = 2/2  
n2: 53 = 107/2  
n3: 3 = 7/2  

实验性功能:

  • index-offset-scheduler提供了对于不通过StatefulSet/GameServerSet管理的pod的支持。如果你通过编写多份pod的配置管理多个pod,并且保持 pod的命名符合StatefulSet的风格。通过在pod的注解中添加key为index-offset-scheduler/scheduler-selector,值为pod的labels的注解,可以 实现类似的效果。

开发指引

核心的打分逻辑位于pkg/scheduler.go,如果你想要改进逻辑:

git clone <repo>
# add your code
go mod tidy
docker build -t index-offset-scheduler:latest  -f Dockerfile .
# 如果网络情况不佳,请在dockerfile中的编译语句中添加GOPROXY

下方文档可供参考: