Giter Club home page Giter Club logo

cherry's Introduction

欢迎使用cherry!

cherry logo cherry license go version cherry tag

  • 这是一款分布式的golang游戏服务器框架
  • 基于golang + nats.io + pomelo protocol技术构建
  • 它具备高性能、可伸缩、分布式、协程分组管理等特点。并且上手简单、易学
  • 让开发者更多的关注游戏业务,高效完成功能实现
  • 文档陆续补充中,欢迎加入一起建设框架

新增功能

  • 新增Actor model实现
  • 新增simple网络数据包结构(id(4bytes) + dataLen(4bytes) + data(n bytes))

讨论与交流

教程

多节点精简版聊天室(❤推荐)

  • 实现网页客户端,构建http server
  • 选择websocket作为连接器
  • 选择json做为通信格式
  • 实现创建房间
  • 实现发送消息
  • 实现广播消息
  • 示例代码跳转

多节点分布式游戏示例(❤强烈推荐)

  • 选择h5搭建一个客户端
  • 搭建web服节点
  • 搭建网关服节点
  • 搭建中心服节点
  • 搭建游戏服节点
  • 选择master做为发现服务节点
  • 实现部份基础功能(区服列表、多sdk帐号体系、帐号注册、帐号登录、创建角色、角色登录)
  • 示例代码跳转

核心功能

组件管理

  • 基于组件的方式组合功能,方便统一管理生命周期
  • 可根据需求自定义组件,并注册到框架,灵活扩展
  • 可配置cluster modestandalone mode

环境配置

  • 可配置多个环境的参数,方便切换
  • 所有系统参数、组件参数都基于profile文件配置,方便扩展
  • 可根据业务需求自由的拆分或组装多个profile子文件,精简配置,拒绝冗余

actor模型

  • 每个Actor独立运行在一个goroutine中,所有的逻辑都是串行处理
  • Actor接收三种消息:本地消息(Local)、远程消息(Remote)、事件消息(Event)
    • 三种消息都有自己的队列(Queue),每个队列依据FIFO原则进行消费
    • 本地消息(Local),用于接收游戏客户端发送过来的本地消息
    • 远程消息(Remote),用于Actor之间调用的远程消息
    • 事件消息(Event),通过订阅/发布进行的事件消息
  • Actor可以创建多个子Actor(ChildActor),子Actor的消息由父Actor进行路由转发
  • 通过cluster集群组件、discovery发现服务组件,进行跨节点的actor通信

集群&注册发现

  • 三种发现服务实现方式:
    • 开发用,直接读取本地的节点配置文件
    • 小规模用,基于nats.io创建一个master节点,实现单节点的发现服务
    • 线上用,基于etcd封装,实现集群方式的发现服务
  • 基于nats.io实现的RPC调用,默认提供同步/异步的调用方式

连接器

  • tcp
  • websocket
  • http server
  • http client
  • kcp(未实现,以后作为组件集成)

消息&路由

  • 实现pomelo网络数据包结构 & simple网络数据包结构
  • 包解码&编码
  • 消息路由
  • 消息序列化(自带json/protobuf)
  • 事件

日志

  • 基于uber zap封装,性能良好
  • 可配置多文件进行日志输出
  • 基于rotatelogs处理切割日志

扩展组件

  • 策划配表读取管理组件
  • 可基于本地配置文件的方式加载
  • 可基于redis数据的方式加载
  • 可基于接口抽像自定义数据源加载
  • 支持自定义文件格式读取,目前已实现JSON格式读取
  • 支持缓存热更新
  • 可自定义类型检测
  • 可根据go-linq进行数据集合的条件查询
  • 基于etcd组件进行封装,节点集群和注册发现
  • 集成gin组件,实现http server功能
  • 自定义controller,增加PreInit()Init()Stop()初始周期的管理
  • 增加几个常用的middleware组件
    • gin zap
    • recover with zap
    • cors跨域
    • max connect限流
  • 封装了GET/POST方式获取各种数据类型的函数
  • 集成gorm组件,实现mysql的数据库访问
  • 支持多个mysql数据库配置和管理
  • 集成mongo-driver驱动
  • 支持多个mongodb数据库配置和管理
  • 基于github.com/robfig/cron/v3进行封装成组件
  • 性能良好

待开放组件

  • db队列
  • gopher-lua脚本
  • 限流组件

游戏客户端SDK

游戏服务端架构示例(点击看大图)

game-server-architecture

致谢

cherry's People

Contributors

goldpasser avatar hollowj avatar phantacix avatar qq358860528 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

cherry's Issues

demo_game_cluster中gate踢下线的问题

在测试gate的websocket连接的时候发现一个踢下线的问题。

问题:同一个用户请求两次路由gate.user.login后,再通过这个函数 agent, ok := pomelo.GetAgentWithUID(userId),无法获取到agent。

场景:已登录建立了websocket连接的用户,再请求这个路由gate.user.login建立新的websocket连接

原因:再次登录时会将之前的agent踢下线(会解绑用户),再重新绑定用户uid。但是踢下线操作比较费时,导致在完成了用户绑定后,又进行了解绑,使得uidMap中的uid被删除了。

规避:
image

点个赞

pitaya之前看过,有点臃肿,nanoserver又略显简陋,cherry实现的就比较合适,会长期关注,谢谢作者的付出。

使用pomeloClient的websocket做压力测试,发现github.com\gorilla\websocket会报concurrent write to websocket connection

报错日志如下:
18:19:01.519 bot ERROR actor/actor_timer.go:142 concurrent write to websocket connection
github.com/cherry-game/cherry/net/actor.(*actorTimer).updateTimer.func2
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/actor_timer.go:142
github.com/cherry-game/cherry/extend/utils.catchError
D:/Workspace/go-game/cherry_server_dev/cherry/extend/utils/utils.go:19
runtime.gopanic
C:/Program Files/Go/src/runtime/panic.go:914
github.com/gorilla/websocket.(*messageWriter).flushFrame
D:/Workspace/gopath/pkg/mod/github.com/gorilla/[email protected]/conn.go:617
github.com/gorilla/websocket.(*messageWriter).Close
D:/Workspace/gopath/pkg/mod/github.com/gorilla/[email protected]/conn.go:731
github.com/gorilla/websocket.(*Conn).beginMessage
D:/Workspace/gopath/pkg/mod/github.com/gorilla/[email protected]/conn.go:480
github.com/gorilla/websocket.(*Conn).NextWriter
D:/Workspace/gopath/pkg/mod/github.com/gorilla/[email protected]/conn.go:520
github.com/gorilla/websocket.(*Conn).WriteMessage
D:/Workspace/gopath/pkg/mod/github.com/gorilla/[email protected]/conn.go:773
github.com/cherry-game/cherry/net/connector.(*WSConn).Write
D:/Workspace/go-game/cherry_server_dev/cherry/net/connector/ws_connector.go:141
github.com/cherry-game/cherry/net/parser/pomelo/client.(*Client).Send
D:/Workspace/go-game/cherry_server_dev/cherry/net/parser/pomelo/client/client.go:379
github.com/cherry-game/cherry/net/parser/pomelo/client.(*Client).Request
D:/Workspace/go-game/cherry_server_dev/cherry/net/parser/pomelo/client/client.go:138
main.(*bot).doubleBet
D:/Workspace/go-game/cherry_server_dev/bot/double.go:88
main.(*bot).subscribeDouble.func1.2
D:/Workspace/go-game/cherry_server_dev/bot/double.go:36
github.com/cherry-game/cherry/net/actor.(*actorTimer).updateTimer.func1
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/actor_timer.go:140
github.com/cherry-game/cherry/extend/utils.Try.func1
D:/Workspace/go-game/cherry_server_dev/cherry/extend/utils/utils.go:11
github.com/cherry-game/cherry/extend/utils.Try
D:/Workspace/go-game/cherry_server_dev/cherry/extend/utils/utils.go:13
github.com/cherry-game/cherry/net/actor.(*actorTimer).updateTimer
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/actor_timer.go:139
reflect.Value.call
C:/Program Files/Go/src/reflect/value.go:596
reflect.Value.Call
C:/Program Files/Go/src/reflect/value.go:380
github.com/cherry-game/cherry/net/actor.InvokeRemoteFunc.func3
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/invoke.go:63
github.com/cherry-game/cherry/extend/utils.Try.func1
D:/Workspace/go-game/cherry_server_dev/cherry/extend/utils/utils.go:11
github.com/cherry-game/cherry/extend/utils.Try
D:/Workspace/go-game/cherry_server_dev/cherry/extend/utils/utils.go:13
github.com/cherry-game/cherry/net/actor.InvokeRemoteFunc
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/invoke.go:61
github.com/cherry-game/cherry/net/actor.(*Actor).invokeFunc
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/actor.go:224
github.com/cherry-game/cherry/net/actor.(*Actor).processRemote
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/actor.go:158
github.com/cherry-game/cherry/net/actor.(*Actor).loop
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/actor.go:83
github.com/cherry-game/cherry/net/actor.(*Actor).run
D:/Workspace/go-game/cherry_server_dev/cherry/net/actor/actor.go:61

run test_sample1 error when client demo open

18:25:05.703 DEBUG [node#gate-1] test-cherry/cherry.go:120 [uid = 0] session create. [nodeId = gate-1, sid = 8e53813d-35e5-4385-ab96-d4f4c8ec84d3, address = 127.0.0.1]
18:25:05.705 DEBUG [node#gate-1] command/handshake.go:52 [uid = 0] request handshake. [data = map[code:200 routes:map[] sys:map[heartbeat:60]]]
18:25:05.705 DEBUG [node#gate-1] command/handshake_ack.go:22 [uid = 0] request handshakeACK.
18:25:05.705 DEBUG [node#gate-1] handler/component.go:232 [uid = 0] [local handler] [route = gate.userHandler.login], [group-index = 0]
18:25:05.705 WARN [node#gate-1] handler/handler_group.go:120 recover in executor. goroutine 26 [running]:
runtime/debug.Stack()
D:/Software/Dev/go/src/runtime/debug/stack.go:24 +0x65
github.com/cherry-game/cherry/net/handler.(*HandlerGroup).invokeExecutor.func1()
E:/go_workspace/test-cherry/net/handler/handler_group.go:120 +0x53
panic({0x13bff40, 0xc000380040})
D:/Software/Dev/go/src/runtime/panic.go:1038 +0x215
reflect.Value.call({0x13eb300, 0xc0000932b0, 0x1d476080a28}, {0x14e03c5, 0x4}, {0xc00039a000, 0x3, 0x0})
D:/Software/Dev/go/src/reflect/value.go:411 +0x19ff
reflect.Value.Call({0x13eb300, 0xc0000932b0, 0xc0002dbbc0}, {0xc00039a000, 0x3, 0x3})
D:/Software/Dev/go/src/reflect/value.go:339 +0xc5
github.com/cherry-game/cherry/net/handler.(*ExecutorLocal).Invoke(0xc000450310)
E:/go_workspace/test-cherry/net/handler/executor_local.go:71 +0x954
github.com/cherry-game/cherry/net/handler.(*HandlerGroup).invokeExecutor(0x0, {0x15d97f8, 0xc000450310})
E:/go_workspace/test-cherry/net/handler/handler_group.go:125 +0x70
github.com/cherry-game/cherry/net/handler.(*HandlerGroup).run.func1(0xc000092060)
E:/go_workspace/test-cherry/net/handler/handler_group.go:109 +0x4d
created by github.com/cherry-game/cherry/net/handler.(*HandlerGroup).run
E:/go_workspace/test-cherry/net/handler/handler_group.go:104 +0x1bb

18:25:05.706 WARN [node#gate-1] handler/handler_group.go:121 executor fail [gate.userHandler.login]

跑demo_chat发现一个竞争点

WARNING: DATA RACE
Write at 0x00c0001ce828 by goroutine 44:
sync/atomic.StoreInt64()
C:/Program Files/Go/src/runtime/race_amd64.s:237 +0xb
sync/atomic.StoreInt64()
:1 +0x15
github.com/cherry-game/cherry/net/parser/pomelo.(*Agent).processPacket()
D:/Workspace/gopath/pkg/mod/github.com/cherry-game/[email protected]/net/parser/pomelo/agent.go:266 +0x2b0
github.com/cherry-game/cherry/net/parser/pomelo.(*Agent).readChan()
D:/Workspace/gopath/pkg/mod/github.com/cherry-game/[email protected]/net/parser/pomelo/agent.go:166 +0x116
github.com/cherry-game/cherry/net/parser/pomelo.(*Agent).Run.func2()
D:/Workspace/gopath/pkg/mod/github.com/cherry-game/[email protected]/net/parser/pomelo/agent.go:140 +0x33

Previous read at 0x00c0001ce828 by goroutine 43:
github.com/cherry-game/cherry/net/parser/pomelo.(*Agent).writeChan()
D:/Workspace/gopath/pkg/mod/github.com/cherry-game/[email protected]/net/parser/pomelo/agent.go:192 +0x3a5
github.com/cherry-game/cherry/net/parser/pomelo.(*Agent).Run.func1()
D:/Workspace/gopath/pkg/mod/github.com/cherry-game/[email protected]/net/parser/pomelo/agent.go:139 +0x33

Goroutine 44 (running) created at:
github.com/cherry-game/cherry/net/parser/pomelo.(*Agent).Run()
D:/Workspace/gopath/pkg/mod/github.com/cherry-game/[email protected]/net/parser/pomelo/agent.go:140 +0xfc
github.com/cherry-game/cherry/net/parser/pomelo.(*actor).defaultOnConnectFunc()
D:/Workspace/gopath/pkg/mod/github.com/cherry-game/[email protected]/net/parser/pomelo/actor.go:91 +0x446
github.com/cherry-game/cherry/net/parser/pomelo.(*actor).defaultOnConnectFunc-fm()
:1 +0x47
github.com/cherry-game/cherry/net/connector.(*Connector).Start.func1()
D:/Workspace/gopath/pkg/mod/github.com/cherry-game/[email protected]/net/connector/connector.go:45 +0x93

net/parser/pomelo/agent.go:192
a.lastAt没有用atomic.LoadInt64来读取

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.