Home

Awesome

due 基于Go语言开发的高性能分布式游戏服务器框架

Build Status goproxy Go Reference License: MIT Go Report Card Coverage Awesome Go

1.介绍

due是一款基于Go语言开发的轻量级、高性能分布式游戏服务器框架。 其中,模块设计方面借鉴了kratos的模块设计思路,旨在为游戏服务器开发提供完善、高效、标准化的解决方案。 框架自创建至今已在多个企业级游戏项目中上线实践过,稳定性有充分的保障。

架构图

2.优势

3.功能

4.下一期新功能规划

5.特殊说明

在due交流群中经常有小伙伴提及到Gate、Node、Mesh之间到底是个什么关系,这里就做一个统一的解答

6.通信协议

在due框架中,通信协议统一采用size+header+route+seq+message的格式:

1.数据包

 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+---------------------------------------------------------------+-+-------------+-------------------------------+-------------------------------+
|                              size                             |h|   extcode   |             route             |              seq              |
+---------------------------------------------------------------+-+-------------+-------------------------------+-------------------------------+
|                                                                message data ...                                                               |
+-----------------------------------------------------------------------------------------------------------------------------------------------+

2.心跳包

 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+---------------------------------------------------------------+-+-------------+---------------------------------------------------------------+
|                              size                             |h|   extcode   |                      heartbeat time (ns)                      |
+---------------------------------------------------------------+-+-------------+---------------------------------------------------------------+

size: 4 bytes

header: 1 bytes

h: 1 bit

extcode: 7 bit

route: 1 bytes | 2 bytes | 4 bytes

seq: 0 bytes | 1 bytes | 2 bytes | 4 bytes

message data: n bytes

heartbeat time: 8 bytes

7.相关工具链

1.安装protobuf编译器(使用场景:开发mesh微服务)

$ apt install -y protobuf-compiler
$ protoc --version  # Ensure compiler version is 3+
$ brew install protobuf
$ protoc --version  # Ensure compiler version is 3+

2.安装protobuf go代码生成工具(使用场景:开发mesh微服务)

go install github.com/gogo/protobuf/protoc-gen-gofast@latest

3.安装grpc代码生成工具(使用场景:使用GRPC组件开发mesh微服务)

go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

4.安装rpcx代码生成工具(使用场景:使用RPCX组件开发mesh微服务)

go install github.com/rpcxio/protoc-gen-rpcx@latest

5.安装gorm dao代码生成工具(使用场景:使用GORM作为数据库orm)

go install github.com/dobyte/gorm-dao-generator@latest

6.安装mongo dao代码生成工具(使用场景:使用MongoDB作为数据库orm)

go install github.com/dobyte/mongo-dao-generator@latest

8.配置中心

1.功能介绍

配置中心主要定位于业务的配置管理,提供快捷灵活的配置方案。支持完善的读取、修改、删除、热更新等功能。

2.支持组件

9.注册中心

1.功能介绍

注册中心用于集群实例的服务注册和发现。支撑整个集群的无感知停服、重启、动态扩容等功能。

2.支持组件

10.网络模块

1.功能介绍

网络模块主要以组件的形式集成于网关模块,为网关提供灵活的网络通信支持。

2.支持组件

11.快速开始

下面我们就通过两段简单的代码来体验一下due的魅力,Let's go~~

1.启动组件

docker-compose up

docker-compose.yaml文件已在docker目录中备好,可以直接取用

2.获取框架

go get -u github.com/dobyte/due/v2@latest
go get -u github.com/dobyte/due/locate/redis/v2@latest
go get -u github.com/dobyte/due/network/ws/v2@latest
go get -u github.com/dobyte/due/registry/consul/v2@latest
go get -u github.com/dobyte/due/transport/rpcx/v2@latest

3.构建Gate服务器

package main

import (
   "github.com/dobyte/due/locate/redis/v2"
   "github.com/dobyte/due/network/ws/v2"
   "github.com/dobyte/due/registry/consul/v2"
   "github.com/dobyte/due/v2"
   "github.com/dobyte/due/v2/cluster/gate"
)

func main() {
   // 创建容器
   container := due.NewContainer()
   // 创建服务器
   server := ws.NewServer()
   // 创建用户定位器
   locator := redis.NewLocator()
   // 创建服务发现
   registry := consul.NewRegistry()
   // 创建网关组件
   component := gate.NewGate(
      gate.WithServer(server),
      gate.WithLocator(locator),
      gate.WithRegistry(registry),
   )
   // 添加网关组件
   container.Add(component)
   // 启动容器
   container.Serve()
}

4.启动Gate服务器

$ go run main.go
                    ____  __  ________
                   / __ \/ / / / ____/
                  / / / / / / / __/
                 / /_/ / /_/ / /___
                /_____/\____/_____/
┌──────────────────────────────────────────────────────┐
| [Website] https://github.com/dobyte/due              |
| [Version] v2.1.0                                     |
└──────────────────────────────────────────────────────┘
┌────────────────────────Global────────────────────────┐
| PID: 27159                                           |
| Mode: debug                                          |
└──────────────────────────────────────────────────────┘
┌─────────────────────────Gate─────────────────────────┐
| Name: gate                                           |
| Link: 172.22.243.151:46545                           |
| Server: [ws] 0.0.0.0:3553                            |
| Locator: redis                                       |
| Registry: consul                                     |
└──────────────────────────────────────────────────────┘

5.构建Node服务器

package main

import (
   "fmt"
   "github.com/dobyte/due/locate/redis/v2"
   "github.com/dobyte/due/registry/consul/v2"
   "github.com/dobyte/due/v2"
   "github.com/dobyte/due/v2/cluster/node"
   "github.com/dobyte/due/v2/codes"
   "github.com/dobyte/due/v2/log"
   "github.com/dobyte/due/v2/utils/xtime"
)

const greet = 1

func main() {
   // 创建容器
   container := due.NewContainer()
   // 创建用户定位器
   locator := redis.NewLocator()
   // 创建服务发现
   registry := consul.NewRegistry()
   // 创建节点组件
   component := node.NewNode(
      node.WithLocator(locator),
      node.WithRegistry(registry),
   )
   // 初始化监听
   initListen(component.Proxy())
   // 添加节点组件
   container.Add(component)
   // 启动容器
   container.Serve()
}

// 初始化监听
func initListen(proxy *node.Proxy) {
   proxy.Router().AddRouteHandler(greet, false, greetHandler)
}

type greetReq struct {
   Message string `json:"message"`
}

type greetRes struct {
   Code    int    `json:"code"`
   Message string `json:"message"`
}

func greetHandler(ctx node.Context) {
   req := &greetReq{}
   res := &greetRes{}
   defer func() {
      if err := ctx.Response(res); err != nil {
         log.Errorf("response message failed: %v", err)
      }
   }()

   if err := ctx.Parse(req); err != nil {
      log.Errorf("parse request message failed: %v", err)
      res.Code = codes.InternalError.Code()
      return
   }

   log.Info(req.Message)

   res.Code = codes.OK.Code()
   res.Message = fmt.Sprintf("I'm server, and the current time is: %s", xtime.Now().Format(xtime.DateTime))
}

6.启动Node服务器

$ go run main.go
                    ____  __  ________
                   / __ \/ / / / ____/
                  / / / / / / / __/
                 / /_/ / /_/ / /___
                /_____/\____/_____/
┌──────────────────────────────────────────────────────┐
| [Website] https://github.com/dobyte/due              |
| [Version] v2.1.0                                     |
└──────────────────────────────────────────────────────┘
┌────────────────────────Global────────────────────────┐
| PID: 27390                                           |
| Mode: debug                                          |
└──────────────────────────────────────────────────────┘
┌─────────────────────────Node─────────────────────────┐
| Name: node                                           |
| Link: 172.22.243.151:37901                           |
| Codec: json                                          |
| Locator: redis                                       |
| Registry: consul                                     |
| Encryptor: -                                         |
| Transporter: -                                       |
└──────────────────────────────────────────────────────┘

7.构建测试客户端

package main

import (
   "fmt"
   "github.com/dobyte/due/eventbus/nats/v2"
   "github.com/dobyte/due/network/ws/v2"
   "github.com/dobyte/due/v2"
   "github.com/dobyte/due/v2/cluster"
   "github.com/dobyte/due/v2/cluster/client"
   "github.com/dobyte/due/v2/eventbus"
   "github.com/dobyte/due/v2/log"
   "github.com/dobyte/due/v2/utils/xtime"
   "time"
)

const greet = 1

func main() {
   // 初始化事件总线
   eventbus.SetEventbus(nats.NewEventbus())
   // 创建容器
   container := due.NewContainer()
   // 创建客户端组件
   component := client.NewClient(
      client.WithClient(ws.NewClient()),
   )
   // 初始化监听
   initListen(component.Proxy())
   // 添加客户端组件
   container.Add(component)
   // 启动容器
   container.Serve()
}

// 初始化监听
func initListen(proxy *client.Proxy) {
   // 监听组件启动
   proxy.AddHookListener(cluster.Start, startHandler)
   // 监听连接建立
   proxy.AddEventListener(cluster.Connect, connectHandler)
   // 监听消息回复
   proxy.AddRouteHandler(greet, greetHandler)
}

// 组件启动处理器
func startHandler(proxy *client.Proxy) {
   if _, err := proxy.Dial(); err != nil {
      log.Errorf("gate connect failed: %v", err)
      return
   }
}

// 连接建立处理器
func connectHandler(conn *client.Conn) {
   doPushMessage(conn)
}

// 消息回复处理器
func greetHandler(ctx *client.Context) {
   res := &greetRes{}

   if err := ctx.Parse(res); err != nil {
      log.Errorf("invalid response message, err: %v", err)
      return
   }

   if res.Code != 0 {
      log.Errorf("node response failed, code: %d", res.Code)
      return
   }

   log.Info(res.Message)

   time.AfterFunc(time.Second, func() {
      doPushMessage(ctx.Conn())
   })
}

// 推送消息
func doPushMessage(conn *client.Conn) {
   err := conn.Push(&cluster.Message{
      Route: 1,
      Data: &greetReq{
         Message: fmt.Sprintf("I'm client, and the current time is: %s", xtime.Now().Format(xtime.DateTime)),
      },
   })
   if err != nil {
      log.Errorf("push message failed: %v", err)
   }
}

type greetReq struct {
   Message string `json:"message"`
}

type greetRes struct {
   Code    int    `json:"code"`
   Message string `json:"message"`
}

8.启动客户端

$ go run main.go
                    ____  __  ________
                   / __ \/ / / / ____/
                  / / / / / / / __/
                 / /_/ / /_/ / /___
                /_____/\____/_____/
┌──────────────────────────────────────────────────────┐
| [Website] https://github.com/dobyte/due              |
| [Version] v2.1.0                                     |
└──────────────────────────────────────────────────────┘
┌────────────────────────Global────────────────────────┐
| PID: 27801                                           |
| Mode: debug                                          |
└──────────────────────────────────────────────────────┘
┌────────────────────────Client────────────────────────┐
| Name: client                                         |
| Codec: json                                          |
| Protocol: ws                                         |
| Encryptor: -                                         |
└──────────────────────────────────────────────────────┘
INFO[2024/07/03 14:53:08.969845] main.go:72 [I'm server, and the current time is: 2024-07-03 14:53:08]
INFO[2024/07/03 14:53:09.983827] main.go:72 [I'm server, and the current time is: 2024-07-03 14:53:09]
INFO[2024/07/03 14:53:10.986592] main.go:72 [I'm server, and the current time is: 2024-07-03 14:53:10]
INFO[2024/07/03 14:53:11.988530] main.go:72 [I'm server, and the current time is: 2024-07-03 14:53:11]
INFO[2024/07/03 14:53:12.991217] main.go:72 [I'm server, and the current time is: 2024-07-03 14:53:12]
INFO[2024/07/03 14:53:13.995049] main.go:72 [I'm server, and the current time is: 2024-07-03 14:53:13]

12.压力测试

1.压测机器

Ubuntu 20.04.6 LTS 13th Gen Intel(R) Core(TM) i5-13400F 16GB

2.压测结果

                    ____  __  ________
                   / __ \/ / / / ____/
                  / / / / / / / __/
                 / /_/ / /_/ / /___
                /_____/\____/_____/
┌──────────────────────────────────────────────────────┐
| [Website] https://github.com/dobyte/due              |
| [Version] v2.1.0                                     |
└──────────────────────────────────────────────────────┘
┌────────────────────────Global────────────────────────┐
| PID: 28660                                           |
| Mode: debug                                          |
└──────────────────────────────────────────────────────┘
┌────────────────────────Client────────────────────────┐
| Name: client                                         |
| Codec: json                                          |
| Protocol: tcp                                        |
| Encryptor: -                                         |
└──────────────────────────────────────────────────────┘
server               : tcp
concurrency          : 50
latency              : 4.741343s
data size            : 1.00KB
sent requests        : 1000000
received requests    : 1000000
throughput (TPS)     : 210910
--------------------------------
server               : tcp
concurrency          : 100
latency              : 4.697039s
data size            : 1.00KB
sent requests        : 1000000
received requests    : 1000000
throughput (TPS)     : 212900
--------------------------------
server               : tcp
concurrency          : 200
latency              : 4.447127s
data size            : 1.00KB
sent requests        : 1000000
received requests    : 1000000
throughput (TPS)     : 224864
--------------------------------
server               : tcp
concurrency          : 300
latency              : 5.616742s
data size            : 1.00KB
sent requests        : 1000000
received requests    : 1000000
throughput (TPS)     : 178039
--------------------------------
server               : tcp
concurrency          : 400
latency              : 4.726411s
data size            : 1.00KB
sent requests        : 1000000
received requests    : 1000000
throughput (TPS)     : 211577
--------------------------------
server               : tcp
concurrency          : 500
latency              : 5.054949s
data size            : 1.00KB
sent requests        : 1000000
received requests    : 1000000
throughput (TPS)     : 197825
--------------------------------
server               : tcp
concurrency          : 1000
latency              : 5.486149s
data size            : 1.00KB
sent requests        : 1000000
received requests    : 1000000
throughput (TPS)     : 182277
--------------------------------
server               : tcp
concurrency          : 1000
latency              : 7.753779s
data size            : 2.00KB
sent requests        : 1000000
received requests    : 1000000
throughput (TPS)     : 128969
--------------------------------

本测试结果仅供参考,详细测试用例代码请查看due-benchmark

13.其他组件

  1. 日志组件
    • zap: github.com/dobyte/due/log/zap/v2
    • logrus: github.com/dobyte/due/log/logrus/v2
    • aliyun: github.com/dobyte/due/log/aliyun/v2
    • tencent: github.com/dobyte/due/log/zap/v2
  2. 网络组件
    • ws: github.com/dobyte/due/network/ws/v2
    • tcp: github.com/dobyte/due/network/tcp/v2
    • kcp: github.com/dobyte/due/network/kcp/v2
  3. 注册发现
    • etcd: github.com/dobyte/due/registry/etcd/v2
    • consul: github.com/dobyte/due/registry/consul/v2
    • nacos: github.com/dobyte/due/registry/nacos/v2
  4. 传输组件
    • grpc: github.com/dobyte/due/transporter/grpc/v2
    • rpcx: github.com/dobyte/due/transporter/rpcx/v2
  5. 定位组件
    • redis: github.com/dobyte/due/locate/redis/v2
  6. 事件总线
    • redis: github.com/dobyte/due/eventbus/redis/v2
    • nats: github.com/dobyte/due/eventbus/nats/v2
    • kafka: github.com/dobyte/due/eventbus/kafka/v2
  7. Web组件
    • http: github.com/dobyte/due/component/http/v2
  8. 配置中心
    • etcd: github.com/dobyte/due/config/etcd/v2
    • consul: github.com/dobyte/due/config/consul/v2
    • nacos: github.com/dobyte/due/config/nacos/v2
  9. 缓存组件
    • redis: github.com/dobyte/due/cache/redis/v2

14.其他客户端

15.详细示例

16.三方示例

<ul> <li style="line-height:30px;padding: 5px 0;"> <a style="line-height: 30px;float: left;" href="https://github.com/Zekiee"><img alt="Zekiee" src="https://avatars.githubusercontent.com/u/69623693?v=4" style="width:30px;height:30px;display:block;border-radius:50%;"></a> <a style="line-height: 30px;float: left;margin-left: 10px;" href="https://github.com/Zekiee/due-game-example">due-game-example</a> </li> <li style="line-height:30px;padding: 5px 0;"> <a style="line-height: 30px;float: left;" href="https://github.com/lingfan"><img alt="lingfan" src="https://avatars.githubusercontent.com/u/455872?v=4" style="width:30px;height:30px;display:block;border-radius:50%;"></a> <a style="line-height: 30px;float: left;margin-left: 10px;" href="https://github.com/lingfan/due-v2-example">due-v2-example</a> </li> </ul>

17.交流与讨论

<img title="" src="group_qrcode.jpeg" alt="交流群" width="175"><img title="" src="personal_qrcode.jpeg" alt="个人二维码" width="177">

个人微信:yuebanfuxiao