当前位置: 首页 > news >正文

Go EASY游戏框架 之 RPC Guide 03

1 Overview

easy解决服务端通信问题,同样使用了RPC技术。easy使用的ETCD+GRPC,直接将它们打包组合在了一起。随着服务发现的成熟,稳定,简单,若是不用,甚至你也并不需要RPC来分解你的架构。

GRPC 有默认resovler 解决服务发现的方案,只需要完成resolver,watch等,可以轻易实现,RPC的负载均衡。只不过这种只适合,对服务器ID信息等不敏感,比如说数据服务,和业务服务。不关心是哪台服务器完成的,只要数据处理完即可。

在游戏的应用场景中,登陆你可能使用的http,进入游戏用的游戏服务器,那么登陆服务需要知道用户在哪台游戏服务器中,使用token判定登陆,传输用户信息等走RPC通道,需要明确知道是哪台服务器。默认的服务发现就不满足我们的需求了。因此我们需要改造下,将游戏的这种具有耦合性质的负载也要支持才行。

2 传送门

go get github.com/slclub/easy/rpc

  • rpc/etcd  ETCD简单封装
  • rpc/cgrpc. GRPC 原生服务发现的封装实现,以及指定方式负载的服务发现

测试项目地址:github.com/slclub/easy/examples/rpc

3 传输协议编码Protobuf

我们直接使用grpc官网的helloworld。我们简单点直接上proto文件的描述语言。致于protoc等工具,以及go的依赖proto就不详细赘述了


syntax = "proto3";option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";package helloworld;// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}

4 GRPC服务端

4.1 helloworld 接口


// server is used to implement helloworld.GreeterServer.
type hello struct {helloworld.UnimplementedGreeterServer
}// SayHello implements helloworld.GreeterServer
func (s *hello) SayHello(ctx context.Context, in *helloworld.HelloRequest) (*helloworld.HelloReply, error) {log.Info("Received: %v", in.GetName())return &helloworld.HelloReply{Message: "Hello " + in.GetName()}, nil
}

SayHello接口会自动依据protobuf 生成的helloworld_grpc.pb.go 文件代码去接收客户端来的请求。

4.2 ETCD client初始化

etcd.NewWithOption(option.OptionWith(nil).Default(option.OptionFunc(func() (string, any) {return "Endpoints", strings.Split(etcdAddr, ";")})),)

etcdAddr 是 用分号链接起来的,etcd的监听地址字符串。ETCD 在整个服务发现体系仅仅需要这理论的一行代码足够了。演示项目我们没有配置账号和密码。实际项目需要主要服务安全。

4.3  服务端grpc 

  • 第一部分grpc初始化
  • 第二部分proto接口注册
  • 第三部分就一个函数调用Serv启动服务监听
// New 一个rpc 监听服务server := cgrpc.NewServer(option.OptionWith(&cgrpc.Config{PathName:  "server1",Addr:      serverAddr,Namespace: namespace,//TTL:       15,}).Default(option.DEFAULT_IGNORE_ZERO,option.OptionFunc(func() (string, any) {return "ID", "abluo"}),option.OptionFunc(func() (string, any) {return "AddrToClient", "127.0.0.1:18080"}),))// 绑定业务接口到 rpc服务// 可以被多次使用RegisterService,我们用的appendserver.RegisterService(func(server *grpc.Server) {helloworld.RegisterGreeterServer(server, &hello{})},)// 监听;如果您有主监听,那么可以用go 并发运行server.Serv()

其中AddrToClient 是针对游戏服务提供给游戏客户端的监听地址,对于grpc来说不是必须的。这里仅仅是从顺便使用grpc 的服务端注册到ETCD中,完成游戏端的服务发现。可以做到任何游戏服不停服的扩展性,动态添加或减少服务端的机器。

这里我们可以发现使用option.Assignment初始化的优势,演示代码的时候不需要写完整的配置参数,还能人为控制的保证参数的默认值。处理默认值都是统一的格式,流程化代码。

当然option.Assignment是有局限性的,仅仅适合服务类的对象,或者仅仅LoadOnce的逻辑部分使用。在业务代码不建议使用,因使用了reflect反射会性能低下。

4.4 grpc客户端

  • ETCD初始化;
  • grpc.Client初始化;
  • Client启动我们分开了,多了一行启动过程,一个函数调用Start();
  • handle 绑定调用接口proto;
  • client.Wait() 为测试而生的函数,实际项目中用不到;
  • client.Close() 不严谨的情况可以不用,严谨的话,在项目工程服务关闭后调用;
	// plan2 using the default value setting function.etcd.NewWithOption(option.OptionWith(nil).Default(option.OptionFunc(func() (string, any) {return "Endpoints", strings.Split(etcdAddr, ";")}),))client := cgrpc.NewClient(option.OptionWith(&struct {PathName  stringNamespace string}{"server1", namespace}))client.Start()// do your thingshandle(client.ClientConn)// just for testclient.Wait()// closeclient.Close()

5 启动

为了启动测试命令随时可以手敲,笔者没有将ETCD,GRPC地址通过flag传递给应用工程。直接写到代码里了。运行前,请下修改代码中的监听地址变量的值。

5.1 启动服务端

$  cd 到 examples/rpc/server 

go build && ./server

5.2 启动客户端

$  cd 到 examples/rpc/client

go build && ./client

6 Output

首先双方通信正常OK。

启动服务后,笔者模拟,任意一端崩掉用(CTRL+C),再启动崩掉的端,整体服务立刻回复正常。

其他的测试情况就不一一再往这上面粘贴了。

服务端

断开gprc服务端再启动

客户端

7 总结

构建一个完整架构的游戏服务器,仅仅靠服务发现,rpc等虽然还不足够。但是这么简单的实现服务端通信,还是让人很愉快。后续再有其他的服务组件,我们可以一一加入进去。同时给出测试项目。

go讲究毕竟是精简,笔者也不是弄个大杂烩,而是设计好package,需要什么我们就用什么。虽说做不到EASY在手天下我有,但是弄一个小体系,还是能节省我们很多项目时间。

最后欢迎大家互相交流学习,有好东西互相分享下。有兴趣的通许可以通过传送门去github,给EASY来个小小的star。因压力测试还不到位,不全,所以笔者一直没有发布一个Stable版本,希望大家谅解。

相关文章:

  • 【Mars3d】关于locationBar等控件的css样式冲突处理问题
  • Vue学习笔记-Vue3中的shallowReactive和shallowRef
  • 通过异步序列化提高图表性能 Diagramming for WPF
  • ohpm : 无法将“ohpm”项识别为 cmdlet、函数...
  • docker---网络
  • 如何使用Java在Excel中添加动态数组公式?
  • ES查询语句中,match和term有什么区别?
  • EasyRecovery2024苹果电脑mac破解版安装包下载
  • Express中使用Swagger
  • 数据结构与算法-动态规划- 最长递增子序列
  • 智能优化算法应用:基于纵横交叉算法3D无线传感器网络(WSN)覆盖优化 - 附代码
  • 前端vue3——实现二次元人物拼图校验
  • 在Ascend昇腾硬件用npu加速paddleLite版本ocr(nnadapter)
  • 【KCC@南京】KCC南京“数字经济-开源行”活动回顾录
  • DSP外部中断笔记
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • 4. 路由到控制器 - Laravel从零开始教程
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • Android交互
  • ComponentOne 2017 V2版本正式发布
  • es6--symbol
  • IDEA 插件开发入门教程
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 官方解决所有 npm 全局安装权限问题
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • 网络应用优化——时延与带宽
  • 学习JavaScript数据结构与算法 — 树
  • ionic入门之数据绑定显示-1
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • #LLM入门|Prompt#3.3_存储_Memory
  • (27)4.8 习题课
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (rabbitmq的高级特性)消息可靠性
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • .NET 4.0中的泛型协变和反变
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .NET Framework与.NET Framework SDK有什么不同?
  • .Net IE10 _doPostBack 未定义
  • .net MVC中使用angularJs刷新页面数据列表
  • .Net Redis的秒杀Dome和异步执行
  • .NET 快速重构概要1
  • .Net程序猿乐Android发展---(10)框架布局FrameLayout
  • .NET建议使用的大小写命名原则
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • @四年级家长,这条香港优才计划+华侨生联考捷径,一定要看!
  • [2023年]-hadoop面试真题(一)