为skynet_fly新增远程调用方式
前言
目前skynet_fly的远程调用方式,是采用了封装skynet的cluster 集群方式,每个连接都会有一个服务端有一个clusteragent 接收代理,客户端有一个sender 发送代理服务。再加上我封装的cluster_server和cluster_client,这样发送端和接收端就分别存在了2个代理服务。也就是说调用一个rpc请求会经过非常多次的打包解包流程。
发送者->cluster_client_m 一次打包解包。
cluster_client_m->clustersender 二次打包解包。
clustersender->clusteragent 三次打包解包。
clusteragent->clusterserver 4次解包。
clusterserver->接收者 4次打包,5次解包。
这一次远程rpc调用需要经过4次打包,5次解包,效率大大折扣。
而且基于cluster 的集群调用方式,并不好监听到建立连接,断开连接等等回调,没有这些机制,并不好做集群之间的数据同步。还有可靠的RPC和数据发送(没有连接断开的等待机制)。
实现方案
我会去掉clusteragent 和 clustersender两个服务。clusterserver作为服务端作为远程连接的入口,监听和管理所有的连接以及连接的rpc调用请求。clusterserver会解开大包,大包中包含着调用到哪个xx_m服务,用什么方式调用,之后在把小包传递到接收的服务进行解包,这样实现之后的流程就变成。
发送者->cluster_client_m 发送者打一次小包,再打一次大包
cluster_clinet->cluster_server 解析一次大包
cluster_server->接收者 解析一次小包
总共2次打包,2次解包 能提升一倍以上的效率,并且过程中的小包详细数据不必被反复打包解包了。
然后再cluster_client 中 实现 集群服务建立连接、断开连接的通知,再增加可靠的PRC、和send调用接口,这样就是一个比较完善的集群架构了。
关键词定义:
- 客户端 指rpc的调用方,以c为简称
- 服务端 指rpc的接收方,以s为简称
- cs2 表示客户端调用服务端
- s2c 表示服务器回应客户端
send call 等待连接建立后发送(可配置超时时间)
skynet cluster mode 方式,call 方法有个一直等待直到回应,感觉太粗暴了,不敢用,万一s端挂比了,c端也会因为大量累计call消息导致内存暴涨而挂逼,而且这种方式send并不支持。
集群中难免会遇到先启动服务却道调用后启动的服务,这时候往往会调用失败。
新增 sub/pub 机制的支持
服务之间往往需要同步一些数据
监听结点建立连接,断开连接(被动)
通常,业务层需要根据回调做一些事情,比如重新挂载sub监听,主动发送一些数据过去
大包分包处理
本来skynet cluster也支持
身份验证支持
集群组网,不一定都搭建在一个内网段中,如果端口对外开放,还是需要一定的身份验证支持来保证安全性
加密传输支持
端口对外开放,想进一步保证安全,防止篡改消息包,还需要加上加密传输支持
最终实现
首次实现
实现了
- send call 等待连接建立后发送(可配置超时时间)
- 大包分包处理
frpc的打包方式借鉴了skynet cluster的打包方式,使其更适合skynet_fly,初版的frpc完全适配了之前的cluster-server的接口调用方式,可以做到无缝切换,在skynet_fly_demo进行切换时,只是全局替换了 cluster_server-frpc_server
, cluster_client-frpc_client
, cluster_client_m->frpc_client_m
,就可以了。
提供了一个握手过程,可用于后续支持身份验证支持,加密传输支持。
后续打算先实现 身份验证支持, 加密传输支持。
再考虑 新增 sub/pub 机制的支持, 监听结点建立连接,断开连接(被动)。
二次加强
实现了
- 身份验证支持
- 加密传输支持
关于 新增 sub/pub 机制的支持, 监听结点建立连接,断开连接(被动) 实现的思考
对于实现功能,不能凭空想象去实现,这样往往达不到好用,或者根本用不上,所以先准备思考,想出一些应用场景,根据应用场景觉得,这两个功能该如何实现。
监听结点建立连接,断开连接(被动)
- 场景1 比如 admin server 中监听各个服务的状态就能通过这个机制来知道服务是不是可用的,而不必通过ping消息去检测。
- 场景2 admin server 中会定时请求各个服务拿取服务的内存、cpu等等信息进行打点统计,通过这个机制,我们不必给不可用的服务发送,减少错误信息打印。
实现方案
- 方案一
可以利用我之前实现的watch_syn同步机制来实现。
新增 sub/pub 机制的支持
比如服务状态的同步 一般登录服都需要监听玩家大厅服的状态,开启中,停服维护中,仅开启中,才允许玩家登录,这个状态都需要比较及时的同步。通常简单的方式就是使用简单轮询的方式去同步状态,这种方式会存在一定的时间误差(误差=请求间隔+网络传输时间+消息处理时间),服务较多的情况下,会额外消耗占用一定的网络资源。如果使用订阅通知的方式,只有状态改变的时候才发送消息,可以最大程度的减少时间误差(误差=网络传输时间+消息处理时间),减少了额外的网络消息请求。
事件通知 以游戏常见的任务系统为例子,任务完成都需要满足一些条件触发完成,所有任务系统都需要监听一些事件才行,比如任务是在象棋游戏中使用炮干掉对方马,任务系统是做在玩家大厅服,当触发该事件的时候,我们需要发消息,通知玩家大厅服,通常能想到的做法是,象棋游戏服直接发消息给玩家大厅服,但是这种方式有一个弊端就是,如果不只有玩家大厅服需要知道此事件呢?比如玩家行为日志服要记录玩家的游戏操作,这样岂不是象棋游戏服又得给玩家行为日志服发一遍,又得改象棋游戏服代码不是。所以这里最好的方式还是用订阅通知的方式。玩家大厅服,和玩家行为日志服,只需要监听此事件,象棋游戏服发布事件即可。
实现方案
可以模仿redis的sub/pub机制,不过需要扩展同步协议。
在frpc 协议中增加,监听,取消监听,监听同步,取消监听同步。再扩展出以通配符监听的方式。比如游戏结束的,可能有*game:1,game:2,有些服务可能只需要监听game:1,而有些服务需要监听所有的游戏结束事件。