云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第4篇

简介: 云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第4篇

介绍



这将是一个完整的,完全践行 DevOps/GitOpsKubernetes 上云流程的 Golang 游戏服务器开发的系列教程。


这个系列教程是对开源项目 Nanoserver 的完整拆解,旨在帮助大家快速上手 Golang(游戏)服务器后端开发。通过实践去理解 Golang 开发的精髓 —— Share memory by communication(通过通信共享内存)


同时这个项目可能还会涉及到 Linux 性能调优(BPF 相关的工具)和系统保障(SRE)的相关的工作。


Step-By-Step 开发 Mahjong Server


  • 单体架构理解 Mahjong Server 业务 -> Nano Distributed Game Server(分布式) + 微服务 改造。
  • Demo:go-mahjong-server


VSCode REST Client 插件


如果你是用 VSCode 作为 IDE,这个插件不错:


微信图片_20220611152444.png


游客登录业务



业务分析


从0到1使用Golang开发生产级麻将游戏服务器—第3篇


业务 E-R 图

微信图片_20220611152503.png


API:查询游客登录是否启用



REST Client 测试 API


Request


POST http://192.168.31.125:12307/v1/user/login/query HTTP/1.1
content-type: application/json
{
    "channelId": "konglai",
    "appId": "konglai"
}


Response


HTTP/1.1 200 OK
Access-Control-Allow-Headers: Origin, Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Sun, 07 Feb 2021 15:00:16 GMT
Content-Length: 24
Connection: close
{
  "code": 0,
  "guest": true
}


微信图片_20220611152521.png


业务逻辑分析


  1. 比较简单,就是根据服务器 configs/config.toml 文件的配置,进行验证:


...
[login]
guest = true
lists = ["test", "konglai"]
...


API:游客登录



REST Client 测试 API


Request


POST http://127.0.0.1:12307/v1/user/login/guest HTTP/1.1
content-type: application/json
{
    "channelId": "konglai",
    "appId": "konglai",
    "imei": "c0a4ce912c48a3d0b17b59e6b97f1dca"
}


Response


{
  "code": 0,
  "name": "G1",
  "uid": 1,
  "headUrl": "http://wx.qlogo.cn/mmopen/s962LEwpLxhQSOnarDnceXjSxVGaibMRsvRM4EIWic0U6fQdkpqz4Vr8XS8D81QKfyYuwjwm2M2ibsFY8mia8ic51ww/0",
  "fangka": 10,
  "sex": 1,
  "ip": "192.168.31.125",
  "port": 33251,
  "playerIp": "192.168.31.125",
  "config": {
    "version": "1.9.3",
    "android": "https://fir.im/tand",
    "ios": "https://fir.im/tios",
    "heartbeat": 30,
    "forceUpdate": true,
    "title": "血战到底",
    "desc": "纯正四川玩法,快捷便利的掌上血战,轻松组局,随时随地尽情游戏",
    "daili1": "kefuweixin01",
    "daili2": "kefuweixin01",
    "kefu1": "kefuweixin01",
    "appId": "xxx",
    "appKey": "xxx"
  },
  "messages": ["系统消息:健康游戏,禁止赌博", "欢迎进入游戏"],
  "clubList": [],
  "debug": 0
}


业务逻辑分析


DB Model

db/model/struct.go


type User struct {
  Id              int64
  Algo            string `xorm:"not null VARCHAR(16) default"`
  Hash            string `xorm:"not null VARCHAR(64) default"`
  Salt            string `xorm:"not null VARCHAR(64) default"`
  Role            int    `xorm:"not null TINYINT(3) default 1"`
  Status          int    `xorm:"not null TINYINT(3) default 1"`
  IsOnline        int    `xorm:"not null TINYINT(1) default 1"`
  LastLoginAt     int64  `xorm:"not null index BIGINT(11) default"`
  PrivKey         string `xorm:"not null VARCHAR(512) default"`
  PubKey          string `xorm:"not null VARCHAR(128) default"`
  Coin            int64  `xorm:"not null BIGINT(20) default 0"`
  RegisterAt      int64  `xorm:"not null index BIGINT(20) default 0"`
  FirstRechargeAt int64  `xorm:"not null index BIGINT(20) default 0"`
  Debug           int    `xorm:"not null index TINYINT(1) default 0"`
}


用户表 描述
Id 自增ID
Algo 加密算法
Hash 加密hash
Salt 加密撒盐
Role 账号类型(RoleTypeAdmin=1 管理员账号,RoleTypeThird=2 三方平台账号)
Status 账号状态(StatusNormal=1 正常,StatusDeleted=2 删除,StatusFreezed=3 冻结,StatusBound=4 绑定)
IsOnline 是否在线(UserOffline=1 离线,UserOnline=2 在线)
LastLoginAt 最后登录时间
PrivKey 账号证书私钥
PubKey 账号证书公钥
Coin 房卡数量
RegisterAt 注册时间
FirstRechargeAt 首充时间
Debug 用户信息调试

type Register struct {
  Id           int64
  Uid          int64  `xorm:"not null index BIGINT(20) default"`
  Remote       string `xorm:"not null VARCHAR(40) default"`
  Ip           string `xorm:"not null VARCHAR(40) default"`
  Imei         string `xorm:"not null VARCHAR(128) default"`
  Os           string `xorm:"not null VARCHAR(20) default"`
  Model        string `xorm:"not null VARCHAR(20) default"`
  AppId        string `xorm:"not null index VARCHAR(32) default"`
  ChannelId    string `xorm:"not null index VARCHAR(32) default"`
  RegisterAt   int64  `xorm:"not null index BIGINT(11) default"`
  RegisterType int    `xorm:"not null index TINYINT(8) default"`
}


用户注册记录表 描述
Id 自增ID
Uid 用户ID
Remote 外网IP
Ip 内网IP
Model 硬件型号
Imei 设备的imei号
Os os版本号
AppId 应用id
ChannelId 渠道id
RegisterAt 注册时间
RegisterType 注册类型(RegTypeThird=5 三方平台添加账号)

type Login struct {
  Id        int64
  Uid       int64  `xorm:"not null index BIGINT(20) default"`
  Remote    string `xorm:"not null VARCHAR(40) default"`
  Ip        string `xorm:"not null VARCHAR(40) default"`
  Model     string `xorm:"not null VARCHAR(64) default"`
  Imei      string `xorm:"not null VARCHAR(32) default"`
  Os        string `xorm:"not null VARCHAR(64) default"`
  AppId     string `xorm:"not null VARCHAR(64) default"`
  ChannelId string `xorm:"not null VARCHAR(32) default"`
  LoginAt   int64  `xorm:"not null BIGINT(11) default"`
  LogoutAt  int64  `xorm:"not null BIGINT(11) default"`
}


用户登录记录表 描述
Id 自增ID
Uid 用户ID
Remote 外网IP
Ip 内网IP
Model 硬件型号
Imei 设备的imei号
Os os版本号
AppId 应用id
ChannelId 渠道id
LoginAt 登录时间
LogoutAt 注销时间

  1. 根据 AppID(用户来自于哪一个应用) 与 Device.IMEI(设备的imei号),确定当前游客是否已经注册


user, err := db.QueryGuestUser(data.AppID, data.Device.IMEI)


db.QueryGuestUser,会从 registeruser 表中去查找用户是否存在。

相关 protocol 的定义:

protocol/login.go


type LoginRequest struct {
  AppID     string `json:"appId"`     //用户来自于哪一个应用
  ChannelID string `json:"channelId"` //用户来自于哪一个渠道
  IMEI      string `json:"imei"`
  Device    Device `json:"device"`
}


protocol/common.go


type Device struct {
  IMEI   string `json:"imei"`   //设备的imei号
  OS     string `json:"os"`     //os版本号
  Model  string `json:"model"`  //硬件型号
  IP     string `json:"ip"`     //内网IP
  Remote string `json:"remote"` //外网IP
}


  1. 如果没有注册,则生成一个新用户,并且注册一条用户记录

涉及到的相关 db 常量的定义:

db/const.go


const (
  StatusNormal  = 1 //正常
  StatusDeleted = 2 //删除
  StatusFreezed = 3 //冻结
  StatusBound   = 4 //绑定
)
const (
  UserOffline = 1 //离线
  UserOnline  = 2 //在线
)
// Users表中role字段的取值
const (
  RoleTypeAdmin = 1 //管理员账号
  RoleTypeThird = 2 //三方平台账号
)


生成一个新用户:


const defaultCoin = 10 // 默认给的房卡数量是 10
user = &model.User{
  Status:   db.StatusNormal,
  IsOnline: db.UserOffline,
  Role:     db.RoleTypeThird,
  Coin:     defaultCoin,
}
db.InsertUser(user)


注册一条用户记录


db.RegisterUserLog(user, data.Device, data.AppID, data.ChannelID, protocol.RegTypeThird) //注册记录


  1. 构造 login 响应数据

相关 protocol 的定义:

protocol/login.go


type LoginResponse struct {
  Code     int          `json:"code"`
  Name     string       `json:"name"`
  Uid      int64        `json:"uid"`
  HeadUrl  string       `json:"headUrl"`
  FangKa   int64        `json:"fangka"`
  Sex      int          `json:"sex"` //[0]未知 [1]男 [2]女
  IP       string       `json:"ip"`
  Port     int          `json:"port"`
  PlayerIP string       `json:"playerIp"`
  Config   ClientConfig `json:"config"`
  Messages []string     `json:"messages"`
  ClubList []ClubItem   `json:"clubList"`
  Debug    int          `json:"debug"`
}
type ClientConfig struct {
  Version     string `json:"version"`
  Android     string `json:"android"`
  IOS         string `json:"ios"`
  Heartbeat   int    `json:"heartbeat"`
  ForceUpdate bool   `json:"forceUpdate"`
  Title string `json:"title"` // 分享标题
  Desc  string `json:"desc"`  // 分享描述
  Daili1 string `json:"daili1"`
  Daili2 string `json:"daili2"`
  Kefu1  string `json:"kefu1"`
  AppId  string `json:"appId"`
  AppKey string `json:"appKey"`
}


protocol/club.go


type (
  ClubItem struct {
    Id        int64  `json:"id"`
    Name      string `json:"name"`
    Desc      string `json:"desc"`
    Member    int    `json:"member"`
    MaxMember int    `json:"maxMember"`
  }
  // ....
)


  1. 插入登录记录,返回客户端所需数据


device := protocol.Device{
    IP:     ip(r.RemoteAddr),
    Remote: r.RemoteAddr,
  }
db.InsertLoginLog(user.Id, device, data.AppID, data.ChannelID)
return resp, nil


  1. 一图胜千言,秒懂


微信图片_20220611152619.jpg



关于游戏服务器登录与 Nano 游戏服务器通信相关代码实战,我们下篇再详细讨论。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
Kubernetes 网络安全 Docker
生产级K8S基础环境部署-20210917
生产级K8S基础环境部署-20210917
281 0
|
JavaScript 算法 前端开发
探索使用 Golang 和 Webassembly 构建一个多人游戏服务器
探索使用 Golang 和 Webassembly 构建一个多人游戏服务器
396 0
探索使用 Golang 和 Webassembly 构建一个多人游戏服务器
|
Kubernetes Cloud Native Devops
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第8篇
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第8篇
278 0
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第8篇
|
Kubernetes Cloud Native Devops
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第7篇
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第7篇
288 0
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第7篇
|
Cloud Native Devops Go
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第1篇(二)
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第1篇(二)
221 0
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第1篇(二)
|
Cloud Native Devops 关系型数据库
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第1篇(一)
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第1篇(一)
250 0
云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第1篇(一)
|
Kubernetes Devops 关系型数据库
生产级Golang麻将游戏服务器 NanoServer 二次开发,利用Drone CI/CD打通DevOps上 K8S 迭代流程
生产级Golang麻将游戏服务器 NanoServer 二次开发,利用Drone CI/CD打通DevOps上 K8S 迭代流程
712 0
生产级Golang麻将游戏服务器 NanoServer 二次开发,利用Drone CI/CD打通DevOps上 K8S 迭代流程
|
Go 网络协议 开发工具
|
2天前
|
存储 Go 索引
go语言使用for循环遍历
go语言使用for循环遍历
16 7
|
2天前
|
开发框架 Go 计算机视觉
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C++ 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。此外,在许多情况下,在各种平台上安装 OpenCV 是很麻烦的。使用纯Go开发的插件不仅在开发时方便,在项目部署和项目维护也能省很多时间精力。