# ngws-go-template_game_leafserver_grpc **Repository Path**: mjpApp/ngws-go-template_game_leafserver_grpc ## Basic Information - **Project Name**: ngws-go-template_game_leafserver_grpc - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-03-05 - **Last Updated**: 2024-04-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README server-game-wsWeb Leaf server =========== # 优化调整 - [] 实现了登录流程 - [] 使用Protobuf 数据格式传输 : https://blog.csdn.net/ouzhengai/article/details/81050692 - [] log日志:采用zap/zapcore 和natefinch/lumberjack.v2,参考文章 - [] redis:采用go-redis,对set和Hset进行封装,支持单机和集群 - [] Token方案:基于jwt-go 实现 - [] orm:采用gorm 连MySQL - [] 定时器:封装了robfig/cron - [] 调用grpc和微服务注册 - [] http服务 - A game server based on [Leaf framework](https://github.com/name5566/leaf). https://www.jianshu.com/p/8e33823f2479 - internal具体实现 - external给外部调用的接口 # Leaf --------- Leaf 是一个使用 Go 语言开发的开源游戏服务器框架,注重运行效率 并追求极致的开发效率。Leaf 适用于几乎所有的游戏类型。其主要的特性: * 良好的使用体验。Leaf 总是尽可能的提供简洁和易用的接口,尽可能的提升开发的效率 * 稳定性。Leaf 总是尽可能的恢复运行过程中的错误,避免崩溃 * 多核支持。Leaf 通过模块机制和 leaf/go 尽可能的利用多核资源,同时又尽量避免各种副作用 * 良好的模块支持。 一个 Leaf 开发的游戏服务器由多个模块组成(例如 LeafServer),模块有以下特点: * 每个模块运行在一个单独的 goroutine 中 * 模块间通过一套轻量的 RPC 机制通讯(leaf/chanrpc) Leaf 不建议在游戏服务器中设计过多的模块。 游戏服务器在启动时进行模块的注册,例如: leaf.Run( ~~game.Module,~~ gate.Module, login.Module, ) 复制 这里按顺序注册了 game、gate、login 三个模块。每个模块都需要实现接口: type Module interface { OnInit() OnDestroy() Run(closeSig chan bool)} 复制 Leaf 首先会在同一个 goroutine 中按模块注册顺序执行模块的 OnInit 方法,等到所有模块 OnInit 方法执行完成后则为每一个模块启动一个 goroutine 并执行模块的 Run 方法。最后,游戏服务器关闭时(Ctrl + C 关闭游戏服务器)将按模块注册相反顺序在同一个 goroutine 中执行模块的 OnDestroy 方法。 # 单机服务器 Leaf 源码概览 * leaf/chanrpc 提供了一套基于 channel 的 RPC 机制,用于游戏服务器模块间通讯 * leaf/db 数据库相关,目前支持 MongoDB * leaf/gate 网关模块,负责游戏客户端的接入 * leaf/go 用于创建能够被 Leaf 管理的 goroutine * leaf/log 日志相关 * leaf/network 网络相关,使用 TCP 协议,可自定义消息格式,目前 Leaf 提供了基于 protobuf 和 JSON 的消息格式 * leaf/recordfile 用于管理游戏数据 * leaf/timer 定时器相关 * leaf/util 辅助库 # 实现分布式 1. 部署多个leaf , 端口都一样,ip不一样, 注册到 consul 2. 客户端请求接口 nginx + consul 3. https://www.cnblogs.com/wikiz/p/10725072.html 4. 实时监控且重启nginx upstream ocelot { consistent_hash $remote_addr {{range service "apigateway"}} server {{ .Address }}:{{ .Port }}; {{ end }} } server { listen 8105; location / { proxy_pass http://ocelot ; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_cache_bypass $http_upgrade; } } 5. 客户端会话保持 1.使用nginx的ip_hash,根据客户端的IP,将请求分配到对应的IP上(服务数量不一致的时候会导致ip_hash重新算的) 6. 解决方法nginx负载均衡之ip_hash 和 一致性Hash 7. ngx_http_upstream_consistent_hash 需要安装 8. consistent_hash $remote_addr:可以根据客户端ip映射 consistent_hash $request_uri:根据客户端请求的uri映射 consistent_hash $args:根据客户端携带的参数进⾏映 2.基于服务端的session会话共享(NFS,MySQL,memcache,redis,file) # 可以自己写定时脚本 9. consul-template --consul-addr 192.168.1.23:8500 --template "/consul/nginx-template/nginx.ctmpl:/consul/nginx-template/vhost.conf:service nginx restart" --log-level=info # ws 优化服务器内核 docker的 --sysctl 参数的白名单 docker run --sysctl key=value IMAGE:TAG CMD docker run -it --sysctl kernel.acpi_video_flags=0 hub.c.163.com/public/debian:7.9 bash https://segmentfault.com/a/1190000009225126 sysctl -a ## 参数 net.core.wmem_max=12582912 net.core.rmem_max=12582912 net.core.netdev_max_backlog = 655360 // 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目,对重负载服务器而言,该值需要调高一点。 net.ipv4.conf.default.rp_filter = 1 // 控制系统是否开启对数据包源地址的校验 0关闭 1开启严格校验 2松散校验 net.ipv4.conf.default.accept_source_route = 0 // 是否接受含有源路由信息的ip包。参数值为布尔值,1表示接受,0表示不接受。安全着想,建议设置为0 net.ipv4.tcp_syncookies = 1 // SYNcookie就是将连接信息编码在ISN(initialsequencenumber)中返回给客户端,这时server不需要将半连接保存在队列中,而是利用客户端随后发来的ACK带回的ISN还原连接信息,以完成连接的建立,避免了半连接队列被攻击SYN包填满 net.ipv4.tcp_tw_reuse = 1 // 快速复用处于 TIME_WAIT 状态的 TCP 连接 net.ipv4.tcp_tw_recycle = 1 // 快速回收处于TIME_WAIT状态的socket net.ipv4.ip_local_port_range = 1024 64000 // 定义网络连接可用作其源(本地)端口的最小和最大端口的限制,适用于TCP和UDP连接。 net.ipv4.tcp_max_tw_buckets = 55000 // 用于调整内核中管理TIME_WAIT状态的数量,当ECS实例中处于TIME_WAIT状态的连接数,加上需要转换为TIME_WAIT状态的连接数之和超过net.ipv4.tcp_max_tw_buckets参数值时,/var/log/messages日志中就会出现“kernel: TCP: time wait bucket table overflow”错误信息,此时,系统内核将会关闭超出参数值的部分TCP连接。 net.ipv4.tcp_abort_on_overflow = 1 // 当TCP连接已经建立,并塞到程序监听backlog队列时,如果检测到backlog队列已经满员后,TCP连接状态会回退到 SYN+ACK 状态,假装TCP三次握手第三次客户单的 ACK 包没收到,让客户端重传 ACK ,以便快速进入 ESTABLISHED 状态。 net.ipv4.tcp_rmem= 10240 87380 12582912 // 接收缓存区大小,缓存从对端接收的数据 net.ipv4.tcp_wmem= 10240 87380 12582912 // 发送缓存区大小,缓存应用程序的数据,有序列号被应答确认的数据会从发送缓冲区删除掉 fs.nr_open = 20480000 fs.file-max = 20480000 net.nf_conntrack_max=55536000 // 最大连接跟踪数 如果通过服务器的流量很大,但表太小,那么 NAT-server 就会开始丢弃数据包,中断会话。 net.ipv4.tcp_max_syn_backlog = 655350 - // 处于SYN_RECV的TCP最大连接数,当处于SYN_RECV状态的TCP连接数超过tcp_max_syn_backlog后,会丢弃后续的SYN报文