# bigworld **Repository Path**: cjackie/bigworld ## Basic Information - **Project Name**: bigworld - **Description**: No description available - **Primary Language**: Go - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2017-03-22 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README Lv1up Server Cluster Document ======== Copyright © 2017 Lv1up Powered By Mega-Cluster Version 1.0.0 #目录 + Server 简介 & 整体框架 - [简介](#self) - [框架](#frame) + 编译 & 部署 - [编译](#build) - [部署](#release) - [Tidb 安装 & 部署](#tidb_install) - [Tidb 数据迁徙](#tidb_datamove) - [Mysql 数据导入&导出](#data_in_out) - [部署Auth服务器](#auth_release) - [部署Game服务器](#game_release) + Package 功能&描述 - [main](#model_main) - [config](#model_config) - [db](#model_db) - [logger](#model_logger) - [model](#model_model) - [pb](#model_pb) - [server](#model_server) - [services](#model_services) - [tools](#model_tools) - [utils](#model_utils) - [Script](#model_script) #简介 ### 什么是Lv1up Server Cluster? 一个用Golang编写的手游服务器集群系统;其致力于为多人在线游戏和交互行为提供服务支持。 完整服务器集群包括 数据库, 验证服, 拍卖服, 游戏服. 启动顺序: 数据库 -> 验证服 -> 拍卖服 -> 游戏服 ### 特点 * 轻量级 * 架构简单轻巧利于二次开发 * 部署维护方便 #框架 ![MacDown Screenshot](./frame.png) ![MacDown Screenshot](./moba.jpg) ##架构优点: * 玩家可就近接入 * 游戏逻辑就近计算 * 基本不存在数据一致性问题 * 灵活调整分布式节点 ##架构解读: ###游戏数据库集中部署 全球同服类型的游戏,任意玩家之间会有玩法交互,玩家游戏数据、游戏帐号数据和全局类游戏数据(如排行榜),都需要在某区域集中部署。玩家游戏数据读写频率较高且单条记录较大,所以最好采用分布式存储架构,比如使用阿里云DRDS和RDS产品进行分库分表,避免数据库单实例的性能瓶颈。 ###全球分区域接入玩家 由于这类游戏是面向全球玩家提供服务,其他国家到中国大陆的网络情况参差不齐,所以需要在全球分多个区域进行玩家的就近接入,比如依据阿里云的数据中心分布情况,接入点可分为中国南方、中国北方、东南亚、欧洲和北美,可在华东2、华北2、新加坡、德国和美东地域分别部署一套接入服务。 ###玩家数据分区域缓存定期回写中心数据库 各区域内玩家在一起游戏,为了避免远程读取数据的网络延迟影响游戏体验,玩家数据也需要分区域缓存,并分批定期回写中心数据库,这样各区逻辑服只需在玩家登录时远程读取一次数据,此后只需快速从缓存服读取玩家数据即可;缓存可以使用阿里云Redis产品,既可以做缓存也可以做持久化,即使专线链路不可用,也不会丢失数据。 ###智能DNS实现就近接入 对于全球玩家接入游戏时最好借助智能DNS服务来自动实现调度,也可以自建调度服务,需要根据玩家所在位置将同区域玩家调度到同一接入点;如果是基于匹配的玩法,需要在匹配算法中考虑玩家所在位置因素。 ###尽量控制同区域玩家间可战斗 由于每个区域都部署游戏逻辑服,也缓存对应区域玩家的数据,所以尽量从后端控制只让同区域玩家可互相PK。 ###全局数据集中存储 由于需要汇总所有区域的数据来生成像排行榜之类的全局数据,所以这部分数据也需要集中存储,每个区域可以定期来拉取需要的全局数据(需要根据排行榜生成的周期来设定拉取数据的时间间隔),但是在拉取到最新数据之前,本地缓存的上一版数据暂时不能删除,生成全局数据的相应服务也集中部署。 ###玩家跨区域接入 由于有可能出现玩家连续两次登录不同区域,所以每次玩家登录都需要检查其本地登录接入点和上次登录接入点是否相同,如果不同,需要先到上次接入点对应缓存将其数据回写数据库,然后再允许玩家在新接入点登录,防止出现数据不一致情况。 ###注: 1. 需要多区域部署。 2. 跨区域玩家互动时会有一方玩家网络延迟较大。 3. 需要有完善的脏数据回写机制以保证数据一致性。 #编译 * 切换目录至 lv1up_server/src: ```$ cd $HOME/code/lv1up_server/src;``` * 执行 ./build.py 编译项目: ```$ ./build.py``` * 执行 ./cos_build.py 编译目标平台 ```$ ./cos_build.py linux``` #部署 ##TiDB数据库安装&部署 TiDB 是 PingCAP 公司基于 Google [Spanner](http://research.google.com/archive/spanner.html) / [F1](http://research.google.com/pubs/pub41344.html) 论文实现的开源分布式 NewSQL 数据库。更多信息请参考[TiDB官方技术文档](https://github.com/pingcap/docs-cn/blob/master/README.md) ### 下载官方 Binary #### Linux (CentOS 7+, Ubuntu 14.04+) 1. 下载压缩包 ```bash wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256 ``` 2. 检查文件完整性,返回 ok 则正确 ```bash sha256sum -c tidb-latest-linux-amd64.sha256 ``` 3. 解开压缩包 ```bash tar -xzf tidb-latest-linux-amd64.tar.gz cd tidb-latest-linux-amd64 ``` ### 单节点方式快速部署 我们可以在单机上面,运行和测试 TiDB 集群,请按如下步骤 **依次启动** PD,TiKV,TiDB: 1. 启动 PD ```bash ./bin/pd-server --data-dir=pd ``` 2. 启动 TiKV ```bash ./bin/tikv-server --pd="127.0.0.1:2379" \ --store=tikv ``` 3. 启动 TiDB ```bash ./bin/tidb-server --store=tikv \ --path="127.0.0.1:2379" ``` ### 多节点集群模式部署 在生产环境中,我们推荐多节点部署 TiDB 集群。 这里我们使用六个节点,部署三个 PD,三个 TiKV,以及一个 TiDB,各个节点以及所运行服务信息如下: |Name|Host IP|Services| |----|-------|--------| |node1|192.168.199.113|PD1, TiDB| |node2|192.168.199.114|PD2| |node3|192.168.199.115|PD3| |node4|192.168.199.116|TiKV1| |node5|192.168.199.117|TiKV2| |node6|192.168.199.118|TiKV3| 请按如下步骤 **依次启动** PD 集群,TiKV 集群以及 TiDB: 1. 在 node1,node2,node3 启动 PD ```bash ./bin/pd-server --name=pd1 \ --data-dir=pd1 \ --client-urls="http://192.168.199.113:2379" \ --peer-urls="http://192.168.199.113:2380" \ --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" ./bin/pd-server --name=pd2 \ --data-dir=pd2 \ --client-urls="http://192.168.199.114:2379" \ --peer-urls="http://192.168.199.114:2380" \ --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" ./bin/pd-server --name=pd3 \ --data-dir=pd3 \ --client-urls="http://192.168.199.115:2379" \ --peer-urls="http://192.168.199.115:2380" \ --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" ``` 2. 在 node4,node5,node6 启动 TiKV ```bash ./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" \ --addr="192.168.199.116:20160" \ --store=tikv1 ./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" \ --addr="192.168.199.117:20160" \ --store=tikv2 ./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" \ --addr="192.168.199.118:20160" \ --store=tikv3 ``` 3. 在 node1 启动 TiDB ```bash ./bin/tidb-server --store=tikv \ --path="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" ``` ##数据迁徙 这里我们假定 MySQL 以及 TiDB 服务信息如下: |Name|Address|Port|User|Password| |----|-------|----|----|--------| |MySQL|127.0.0.1|3306|root|*| |TiDB|127.0.0.1|4000|root|*| ###下载 TiDB 工具集 (Linux) 1. 下载压缩包 ```bash wget http://download.pingcap.org/tidb-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-tools-latest-linux-amd64.sha256 ``` 2. 检查文件完整性,返回 ok 则正确 ```bash sha256sum -c tidb-tools-latest-linux-amd64.sha256 ``` 3. 解开压缩包 ```bash tar -xzf tidb-tools-latest-linux-amd64.tar.gz cd tidb-tools-latest-linux-amd64 ``` ###使用 checker 进行 Schema 检查 在迁移之前,我们可以使用 TiDB 的 checker 工具,来预先检查 TiDB 是否能支持需要迁移的 table schema。如果 check 某个 table schema 失败,表明 TiDB 当前并不支持,我们不能对该 table 里面的数据进行迁移。checker 包含在 TiDB 工具集里面。 + 使用 checker 检查 test database 里面所有的 table ```bash ./bin/checker -host 127.0.0.1 -port 3306 -user root test 2017/03/16 17:16:32 checker.go:48: [info] Checking database test 2017/03/16 17:16:32 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2017/03/16 17:16:32 checker.go:63: [info] Checking table t1 2017/03/16 17:16:32 checker.go:69: [info] Check table t1 succ 2017/03/16 17:16:32 checker.go:63: [info] Checking table t2 2017/03/16 17:16:32 checker.go:69: [info] Check table t2 succ ``` + 使用 checker 检查 test database 里面某一个 table 这里,假设我们只需要迁移 table `t1`。 ```bash ./bin/checker -host 127.0.0.1 -port 3306 -user root test t1 2016/10/27 13:13:56 checker.go:48: [info] Checking database test 2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:13:56 checker.go:63: [info] Checking table t1 2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ Check database succ! ``` ##使用 `mydumper`/`loader` 全量导入数据 `mydumper` 是一个更强大的数据迁移工具,具体可以参考 [https://github.com/maxbube/mydumper](https://github.com/maxbube/mydumper)。 我们使用 `mydumper` 从 MySQL 导出数据,然后用 `loader` 将其导入到 TiDB 里面。 > 注意:虽然 TiDB 也支持使用 MySQL 官方的 `mysqldump` 工具来进行数据的迁移工作,但相比于 `mydumper` / `myloader`,性能会慢很多,大量数据的迁移会花费很多时间,这里我们并不推荐。 ### 下载 mydumper (Linux) 1. 下载压缩包 ```bash wget http://download.pingcap.org/mydumper-linux-amd64.tar.gz wget http://download.pingcap.org/mydumper-linux-amd64.sha256 ``` 2. 检查文件完整性,返回 ok 则正确 ```bash sha256sum -c mydumper-linux-amd64.sha256 ``` 3. 解开压缩包 ```bash tar -xzf mydumper-linux-amd64.tar.gz cd mydumper-linux-amd64 ``` ### 从 MySQL 导出数据 我们使用 `mydumper` 从 MySQL 导出数据,如下: ```bash ./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 128 -B test -T t1,t2 --skip-tz-utc -o ./var/test ``` 上面,我们使用 `-B test` 表明是对 `test` 这个 database 操作,然后用 `-T t1,t2` 表明只导出 `t1`,`t2` 两张表。 `-t 16` 表明使用 16 个线程去导出数据。`-F 128` 是将实际的 table 切分成多大的 chunk,这里就是 128MB 一个 chunk。 `--skip-tz-utc` 添加这个参数忽略掉 MySQL 与导数据的机器之间时区设置不一致的情况,禁止自动转换。 > 注意:在阿里云等一些需要 `super privilege` 的云上面,`mydumper` 需要加上 `--no-locks` 参数,否则会提示没有权限操作。 ### 下载 loader (Linux) [源代码](https://github.com/pingcap/tidb-tools/tree/master/loader) [Binary 下载](http://download.pingcap.org/tidb-tools-latest-linux-amd64.tar.gz) ### 向 TiDB 导入数据 我们使用 `loader` 将之前导出的数据导入到 TiDB。 ```bash ./bin/loader -h 127.0.0.1 -u root -P 4000 -t 4 -q 1 -d ./var/test ``` 这里 `-q 1` 表明每个事务包含多少个 query,默认是 1,在像 TiDB 中导入数据时,推荐用默认值。 导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看: ```sql mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+ ``` ##部署AuthServer 使用git提交最新版本 1. 编译lv1up_auth ```bash cd $HOME/code/lv1up_auth/src ./cos_build.py linux ``` 2. 提交最新版本至远程仓库 ```bash cd $HOME/code/lv1up_auth_release git commit -am"someting" ``` 3. 登录目标服务器实例 ```bash ssh root@11.12.13.14 ``` 4. 从远程仓库下载最新版本 ```bash cd / mkdir auth_server cd auth_server git clone https://git.oschina.net/finalstage/lv1up_auth_release.git cd lv1up_auth_release ``` 5. 修改配置文件 ```bash vi ./config.json ``` 6. 采用nohup方式运行服务器 ```bash nohup ./auth_linux_amd64.run & ``` ##部署GameServer 使用git提交最新版本 1. 编译lv1up_server 参考 [编译](#build) 2. 提交最新版本至远程仓库 ```bash cd $HOME/code/lv1up_server_release git commit -am"someting" ``` 3. 登录目标服务器实例 ```bash ssh root@11.12.13.14 ``` 4. 从远程仓库下载最新版本 ```bash cd / mkdir auth_server cd auth_server git clone https://git.oschina.net/finalstage/lv1up_server_release.git cd lv1up_server_release ``` 5. 修改配置文件 ```bash vi ./config.json ``` 6. 采用nohup方式运行服务器 ```bash nohup ./zq_linux_amd64.run & ``` #Package 功能&描述 ##Main ###main.go ####描述 执行程序入口文件 ####主要功能 * 程序入口 `func main(){}` * 服务器初始化 * 加载配置参数 `func config.Init(){}` * 加载数据库 `func baseLoad(){}` * 准备游戏环境 `func services.Init(){}` * 开放对外接口 `func server.StartTcpServer(){}` * 游戏服务器关闭 `func clean(){}` ##Config ###config.go ####描述 解析config文件,获取配置参数 ####主要功能 * 加载config文件并解析 `func init(){}` * 提供参数获取的外部接口 `func Get...(){}` ##Db ###db.go ####描述 数据库连接和write操作落地,数据read操作在model包进行 ####主要功能 * 连接数据库 `func InitDB(){}` * 数据write操作落地 `func StartChan(){}` * 检查并创建表 `func UpdateDB(){}` ###create.go ####描述 存放数据库建表sql语句 ####主要功能 * 创建新表 `func CreateIfNotExists(){}` ##Logger ###logger.go ####描述 记录日志,日志等级分为 Debug, Info, Warning, Error, Finest ####主要功能 * 设置日志等级 `func SetLogger(){}` * 日志记录接口 `func Debug(){}; func Error(){} ...` ##Model ###xxx.go ####描述 model包含数据库表结构的映射go struct, 提供用操作go strcut的方式操作表数据. 由template自动生成,**不要手动书写**, template及相关工具位于 tools包内. ####主要功能 * 表结构 - go struct 映射 * 提供常用数据操作接口 * select `func GetByPk(){}; func GetByQueryMap(){} ...` * insert `func Insert(){}; BatchInsert(){} ...` * delete `func Delete(){}; BatchDelete(){} ...` * update `func Update(){}; BatchUpdateMap(){} ...` ##Pb ###xxx.go ####描述 Protocol Buffers 是google 提供的一种数据交换的格式. 由 protoc 编译生成.go文件, **不要手动书写** ####主要功能 * protocol buffers 消息结构体 - go struct 映射 * 提供用操作go struct的方式操作数据 `func Get...(){}` ##Server ###server.go ####描述 TCP服务的实现实例 ####主要功能 * 提供TCP通信服务支持 * 建立通信框架模型 ##Services 服务器的主要功能提供模块,涵盖所有的逻辑业务和绝大部分的系统服务. ###auth.go ####描述 提供与auth服务器的交互操作服务 ####主要功能 * AuthResult结构体 `type AuthResult struct{}` * 请求auth服务器,验证用户数据 `func auth(){}` ###client.go ####描述 提供与client交互操作, 逻辑服务 ####主要功能 * client管理 * 类型 `type ClientMgr {}` * get `func (*ClientMgr) get(){}` * insert `func (*ClientMgr) insert(){}` * delete `func (*ClientMgr) delete(){}` * count `func (*ClientMgr) count(){}` * client实例 * 类型 `type Client struct{}` * 开始一个新的客户端 `func StartClient(){}` * 接受数据 `func (*Client) recv(){}` * 解析数据 `func (*Client) decodeBuffer(){}` * 转发数据 `func (*Client) routePlayer(){}` ###cron.go ####描述 提供周期性执行函数服务 ####主要功能 * 注册周期执行函数 `func StartCron(){}` ###msg.go ####描述 消息体结构体,消息ID编号 ####主要功能 * 定义 MSG 接口 `type MSG interface{}` * 定义消息类型 `const (...)` ###pb.go ####描述 游戏服务器逻辑和protobuf的接口文件,封装内存数据和protobuf消息的转换 ####主要功能 * 业务逻辑消息编号 `const (...)` * 打包接口 `func encodeSCxxxx(){}` * 解包接口 `func decodePackage(){}` ###proto.go ####描述 消息序列化,为pb.go提供底层操作 ####主要功能 * 序列化 `func encode(){}` * 反序列化 `func decode(){}` ###player.go ####描述 受理玩家所有操作逻辑 ####主要功能 * player实例 * 定义player结构体 `type Player struct{}` * 初始化 `func newPlayer(){}` * 受理操作 `func (*Player)handleXXXX (){}` ###room.go ####描述 游戏房间逻辑服务 ####主要功能 * 房间管理者 * 类型定义 `type RoomGmr struct{}` * 房间 * 房间定义 `type Room struct{}` * 房间成员定义 `type RoomMember struct{}` * 创建房间 `func starRoom(){}` * 加入房间 `func (*Room)join() {}` * 离开房间 `func (*Room)leave() {}` * 开始游戏 `func (*Room)gameStart(){}` * 受理玩家房间操作 `func (*Room)handleXXX(){}s` ##Tools ###xxx.py ####描述 python 脚步文件,自动化生成model/xxx.go 文件 ####主要功能 * 调用模板编译工具 * 调用系统工具 ###xxx.tpl ####描述 go模板文件, 供模板工具批量生成目标代码 ####主要功能 * 定义model/xxx.go 文件模板 ##Utils ###reflect.go ###描述 interface反射接口辅助 ####主要功能 * json反射 `func Map2StructByJsonTag(){}` ###utls.go ####描述 辅助功能函数 ####主要功能 * 获取时间戳 `func NowSecond(){}` * 切分字符串转换数字 `func GetStrIntList(){}` * 数字切片转换字符串 `func GetStrFromIntList(){}` * 区间随机整数 `func RandBetween(){}` * 保留几位小数 `func Round(){}` ##Script ###build.py ####描述 项目编译脚步 ####主要功能 * 编译 `./build.py` * 编译protobuf,重新生成pb/*.go `./build.py -p` * 编译数据库结构,重新生成model/*.go `./build.py -r` * 重新编译pb和数据库 `./build.py -rp` ###cos_build.py ####描述 编译目标平台程序 ####主要功能 * 编译Linux `./cos_build.py linux` * 编译Windows `./cos_build.py windows `