DockerCompose 启动 open-match

背景介绍

open-match是Google和unity联合开源的支持实时多人匹配的框架,已有多家游戏厂商在生产环境使用,官网 https://open-match.dev/site/ 。原本我们使用的是UOS上提供的匹配能力,但是UOS目前不支持自建的Dedicated servers 集群,只能上传镜像,UOS会自动完成分配以及创建,灵活性就不是那么高了,按照open-match的官方教程,需要有k8s的环境。但是小公司就是不想要k8s,我就想单机部署,可以使用docker-compose。open-match本身的镜像build 提供了dockerfile文件。把项目clone到本地,然后在 tm中以此使用以下命令构建对用的image

tip:该方案只是启动了 core 部分要求的组件即

搭建步骤

Install with YAML | Open Match

后面的部分,需要自行探索了,现在也在学习中,欢迎交流讨论

先构建一个中间镜像base builder,然后一次构建对应的component即可,需要修改Dockerfile.cmd中的

FROM open-match-base-build as builder

为,目的是指定使用本地的version版本,否则会远程拉取镜像,网络问题会导致不成功,需要开梯子

FROM open-match-base-build:latest as builder
docker build -f .\Dockerfile.base-build -t open-match-base-build . 
docker build --build-arg IMAGE_TITLE=synchronizer -f .\Dockerfile.cmd -t open-match-synchronizer .

接着使用docker-compose.yaml 来控制启动过程,内如如下

version: '3'
services:
  open-match-backend:
    image: open-match-backend:latest
    container_name: open-match-backend
    volumes:
      - ./matchmaker_config_default.yaml:/app/matchmaker_config_default.yaml
      - ./matchmaker_config_override.yaml:/app/matchmaker_config_override.yaml
    ports:
      - "50505:50505"  # gRPC
      - "51505:51505"  # HTTP
    environment:
      API_BACKEND_HOSTNAME: "open-match-backend"
      API_BACKEND_GRPC_PORT: "50505"
      API_BACKEND_HTTP_PORT: "51505"
      REDIS_HOSTNAME: "open-match-redis"
      REDIS_PORT: "6379"
    depends_on:
      - redis

  open-match-frontend:
    image: open-match-frontend:latest
    container_name: open-match-frontend
    ports:
      - "50504:50504"  # gRPC
      - "51504:51504"  # HTTP
    volumes:
      - ./matchmaker_config_default.yaml:/app/matchmaker_config_default.yaml
      - ./matchmaker_config_override.yaml:/app/matchmaker_config_override.yaml
    environment:
      API_FRONTEND_HOSTNAME: "open-match-frontend"
      API_FRONTEND_GRPC_PORT: "50504"
      API_FRONTEND_HTTP_PORT: "51504"
      REDIS_HOSTNAME: "open-match-redis"
      REDIS_PORT: "6379"
    depends_on:
      - redis

  open-match-query:
    image: open-match-query:latest
    container_name: open-match-query
    ports:
      - "50503:50503"  # gRPC
      - "51503:51503"  # HTTP
    environment:
      API_QUERY_HOSTNAME: "open-match-query"
      API_QUERY_GRPC_PORT: "50503"
      API_QUERY_HTTP_PORT: "51503"
      REDIS_HOSTNAME: "open-match-redis"
      REDIS_PORT: "6379"
    volumes:
      - ./matchmaker_config_default.yaml:/app/matchmaker_config_default.yaml
      - ./matchmaker_config_override.yaml:/app/matchmaker_config_override.yaml
    depends_on:
      - redis

  open-match-synchronizer:
    image: open-match-synchronizer:latest
    container_name: open-match-synchronizer
    volumes:
      - ./matchmaker_config_default.yaml:/app/matchmaker_config_default.yaml
      - ./matchmaker_config_override.yaml:/app/matchmaker_config_override.yaml
    ports:
      - "50506:50506"  # gRPC
      - "51506:51506"  # HTTP
    environment:
      API_SYNCHRONIZER_HOSTNAME: "open-match-synchronizer"
      API_SYNCHRONIZER_GRPC_PORT: "50506"
      API_SYNCHRONIZER_HTTP_PORT: "51506"
      REDIS_HOSTNAME: "open-match-redis"
      REDIS_PORT: "6379"
    depends_on:
      - redis

  open-match-swaggerui:
    image: open-match-swaggerui:latest
    container_name: open-match-swaggerui
    ports:
      - "51500:51500"  # HTTP for Swagger UI
    volumes:
      - ./matchmaker_config_default.yaml:/app/matchmaker_config_default.yaml
      - ./matchmaker_config_override.yaml:/app/matchmaker_config_override.yaml
    environment:
      API_SWAGGERUI_HOSTNAME: "open-match-swaggerui"
      API_SWAGGERUI_HTTP_PORT: "51500"
    depends_on:
      - open-match-backend
      - open-match-frontend
      - open-match-query
      - open-match-synchronizer

  redis:
    image: redis:alpine
    container_name: open-match-redis
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data

volumes:
  redis-data:

matchmaker_config_default.yaml 的内容和 matchmaker_config_override.yaml的内容是一致的,目的就是override可以覆盖default中的值(猜的),这部分内容从k8s的yaml文件中copy过来,内容如下
 

logging:
  level: debug
  format: text
  rpc: false
# Open Match applies the exponential backoff strategy for its retryable gRPC calls.
# The settings below are the default backoff configuration used in Open Match.
# See https://github.com/cenkalti/backoff/blob/v3/exponential.go for detailed explanations
backoff:
  # The initial retry interval (in milliseconds)
  initialInterval: 100ms
  # maxInterval caps the maximum time elapsed for a retry interval
  maxInterval: 500ms
  # The next retry interval is multiplied by this multiplier
  multiplier: 1.5
  # Randomize the retry interval
  randFactor: 0.5
  # maxElapsedTime caps the retry time (in milliseconds)
  maxElapsedTime: 3000ms

api:
  backend:
    hostname: "open-match-backend"
    grpcport: "50505"
    httpport: "51505"
  frontend:
    hostname: "open-match-frontend"
    grpcport: "50504"
    httpport: "51504"
  query:
    hostname: "open-match-query"
    grpcport: "50503"
    httpport: "51503"
  synchronizer:
    hostname: "open-match-synchronizer"
    grpcport: "50506"
    httpport: "51506"
  swaggerui:
    hostname: "open-match-swaggerui"
    httpport: "51500"

  # Configurations for api.test and api.scale are used for testing.
  test:
    hostname: "open-match-test"
    grpcport: "50509"
    httpport: "51509"
  scale:
    httpport: "51509"

redis:
  # Open Match's default Redis setups
  hostname: open-match-redis
  # source value: open-match-core.redis.port = 6379
  port: 6379
  usePassword: false
  passwordPath: /redis-password
  pool:
    maxIdle: 200
    maxActive: 0
    idleTimeout: 0
    healthCheckTimeout: 300ms

telemetry:
  reportingPeriod: "1m"
  traceSamplingFraction: "0.01"
  zpages:
    enable: "true"
  prometheus:
    enable: "false"
    endpoint: "/metrics"
    serviceDiscovery: "true"
  stackdriverMetrics:
    enable: "false"
    gcpProjectId: "replace_with_your_project_id"
    prefix: "open_match"

然后就可以启动了

运行demo

如果要运行open-match的 demo-first-match,还要一个组件

evaluator

该组件的目的是对所有的matches进行评估,并返回得分,open-match会保留评分最高的组合,比如我们以 战力相差的相近为评估规则,假定 abc,三个玩家的战力分值分配时 10 20 25,则abc三人同时匹配在1v1的条件选,应当尽可能的选择20 25这个相近的评分,评分组件evaluator这个需要开始自行实行,通过synchronizer进行调用,open-match 提供了一个default实现 即default-evaluator,使用以下命令进行构建即可

docker build --build-arg IMAGE_TITLE=default-evaluator -f .\Dockerfile.cmd -t open-match-default-evaluator .

如果开发环境存在需要平凡需求的情况,直接ide环境启动即可,但是需要在 matchmaker_config_default.yaml中指明 evaluator的位置信息

api:
  evaluator:
    hostname: "open-match-default-evaluator"
    httpport: "5499"
    grpcport: "5498"

接着需要修改几个demo的hostname地址,一个是frontend的hostname,位置在

open-match/examples/demo/components/clients/clients.go:84

//修改前
conn, err := grpc.Dial("open-match-frontend.open-match.svc.cluster.local:50504", grpc.WithInsecure())

//修改后
conn, err := grpc.Dial("localhost:50504", grpc.WithInsecure())

另外一个是 backend的hostname

open-match/examples/demo/components/director/director.go:71

//修改前
conn, err := grpc.Dial("open-match-backend.open-match.svc.cluster.local:50505", grpc.WithInsecure())

//修改后
conn, err := grpc.Dial("localhost:50505", grpc.WithInsecure())

然后还需要部署一个组件mmf,负责判断给定的组合是否符合要求,可以直接启动 cmd/scale-mmf,或者build镜像,一样的需要修改query的hostname,位置信息如下

open-match/examples/scale/mmf/mmf.go:42

//修改前
conn, err := grpc.Dial("open-match-query.open-match.svc.cluster.local:50503", utilTesting.NewGRPCDialOptions(logger)...)

//修改后
conn, err := grpc.Dial("localhost:50503", utilTesting.NewGRPCDialOptions(logger)...)

mmf的服务地址,是由director在fetchMatches指定的,相关的代码位置在

open-match/examples/demo/components/director/director.go:82

不同版本可能会有所变化,当前提及的代码内容来源于open-match的最新master代码,2024年10月9日 

req := &pb.FetchMatchesRequest{
			Config: &pb.FunctionConfig{
				Host: "om-function.open-match-demo.svc.cluster.local",
				Port: 50502,
				Type: pb.FunctionConfig_GRPC,
			},
			Profile: &pb.MatchProfile{
				Name: "1v1",
				Pools: []*pb.Pool{
					{
						Name: "Everyone",
					},
				},
			},
		}

所以我们需要改掉这里Host所指定的值,修改为mmf的实际地址即可,最后更新docker-compose.yaml并执行 docker-compose -f docker-compose.yaml up,在cmd/demo-first-match/main.go 文件中运行main函数即可成功运行demo程序

demo程序的执行成功后会返回一个虚拟的链接地址,该链接地址由director组件返回,可以理解为在director中返回具体的dedicated server的ip地址,demo中是随机产生的代码位置在

examples/demo/components/director/director.go:132 

如果不正确可以搜索2222作为线索定位

	for _, match := range matches {
		ids := []string{}

		for _, t := range match.Tickets {
			ids = append(ids, t.Id)
		}

		req := &pb.AssignTicketsRequest{
			Assignments: []*pb.AssignmentGroup{
				{
					TicketIds: ids,
					Assignment: &pb.Assignment{
						Connection: fmt.Sprintf("%d.%d.%d.%d:2222", rand.Intn(256), rand.Intn(256), rand.Intn(256), rand.Intn(256)),
					},
				},
			},
		}

		resp, err := be.AssignTickets(ds.Ctx, req)
		if err != nil {
			panic(err)
		}

		_ = resp
	}

匹配成功后返回的链接地址

open-match对mmf,evaluator,director 提供了多种游戏场景的默认实现,可以在亦有模板的基础上结合业务进行开发,具体内容可以查看examples/scale/README.md

感觉联机几千人同时在线这种方式应该够够吧,先这样,散会

补一张open-match 时序图,看懂这个业务开发层面知道各个component的职责范围


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值