skynet中cluster和harbor,进程间通信方式的分析与对比

      skynet是开源社区中一个璀璨的明星,在设计上高屋建瓴,整个核心层代码数量非常少,深度嵌入lua语言,使得开发任何网络服务端的应用,都能很快的实现,并且非常方便后续的开发和维护。这里主要就网络服务端很常见的进程间通信的场景,对skynet是如何解决的作一番剖析。

      skynet提供的cluster模块,就是用于两个进程间通信的解决方案。cluster模块主要包含clusterd.lua、cluster.lua、clustersender.lua、clusteragent.lua、lua-cluster.c,还有一些公共模块。在节点(运行中的进程)运行时,clusterd.lua作为一个服务(通过snlua(99%的服务的宿主)动态库建立),cluster.lua向外提供操作接口,最终在clusterd服务里开启对一个端口的监听,同时,当有其他的节点发起对这个节点的网络连接时,通过clusterd会建立一个clusteragent服务,skynet进程间通信的消息都是由连接方(底层调用connect)主动(不会由建立clusteragent的节点主动发起通信)发起的。对另一个节点发起通信,会通过clusterd服务建立一个clustersender服务,然后通过clustersender向另一个节点发数据。这些都是skynet框架层提供的底层支持,应用层不需要修改(之前因为不满足我们项目的一个需求,做过一点修改)。通常是在一个服务A里对另一个节点的某个服务B发送数据,数据的流向是服务A->clustersender->服务A所在节点的网络层->服务B所在节点的网络层->clusteragent->服务B,如果需要等服务B返回数据,会在服务A、clustersender服务、clusteragent服务挂起协程,等服务B处理完业务,再由服务B->clusteragent->服务B所在节点的网络层->服务A所在节点的网络层->clustersender->服务A,中间挂起的协程都是通过session来唤醒的,过程比较复杂,实现上相对没有harbor优雅,但是比harbor可靠。中间任何一步有异常,服务A马上就能知道,这一点在网络服务端程序,是非常重要的。

       skynet提供的harbor模块,也是用于两个进程间通信的解决方案。harbor模块主要包含harbor.lua、cmaster.lua、cslave.lua、service_harbor.c、skynet_harbor.h、skynet_harbor.c,cmaster服务在一组节点中,只能在某一个节点创建一个,进行服务名字和服务id的管理,每一个节点都需要创建一个cslave服务、一个harbor服务,每一个节点分配一个harborid,默认为8位,我觉得不够(最多只能开256个节点,如果项目是游戏,每个游戏节点同时在线4000人,开了240个节点,96w的同时在线,绝对是一款火爆的产品),改造成了12位(最多开4096个节点)。每一个服务都有一个数字id,前12位标记是哪一个harbor,也就知道了某个服务id是不是本节点的。在创建服务的时候,需要通过harbor.lua->cslave->cmaster,绑定一个全局的名字和服务id,.开头字符串为节点内部的名字,:开头的16进制字符串是服务id的十六进制表示,其他的是全局服务名。在项目运行时,运行了许多服务,只有保证服务的全局名字不重复才不会出错,当然harbor也提供了接口来确认这一点。通常在一个服务A里对另一个节点里的服务B发送数据,数据的流向是服务A->harbor服务(缓存数据)->cslave服务->服务A所在节点的网络层->cmaster服务所在节点的网络层->cmaster服务(查询服务B的服务id)->cslave服务(返回服务B的服务id)->harbor服务(发送缓存里的数据)->服务B所在节点的网络层->服务B所在节点的harbor服务->服务B,过程非常复杂,整个过程做了封装,业务层用起来非常方便,但是如果在服务A里调用了一个不存在的服务,只会在服务A里挂起协程,需要等待返回,会有bug,数据像被丢进了黑洞,被吞噬了。我改造了这里的代码,当查询到不存在这个服务名时,立即返回服务A。使用这种模式,需要处理好一个服务被销毁,需要销毁cmaster、各个cslave、各个harbor服务中全局服务名和服务id的对应关系,缓存的地方很多,不可能同时销毁,会存在数据不一致的时候,当然每个节点服务id的分配时,会记录可用的服务id自增的下一个,一般也不会出现刚销毁的服务id马上被分配到下一个创建的服务的情况,如果长时间没有停止维护,服务id分配回绕是有可能存在,刚销毁的服务id,马上被下一个服务使用的情况。使用时,非常方便,向其他节点的某个服务发送数据和向本地节点的某个服务发送数据,使用的接口完全一样, 非常优雅。从可靠性的角度考虑,harbor是不如cluster方案的。

       最近看了skynet中的测试用例,对大部分都进行了验证和分析,其中有一个是分析skynet的性能的,在我的虚拟机上,20w的qps,表现还是非常出色的,没有打包和解包复杂的数据,相对于实际应用场景,要简单很多,这样的成绩还是非常有说服力的。任何事物,只要深入分析,都会有自己的长处和短处,没有绝对的完美,作了一点哲学上的想象。当然,只要把长处发挥到了极致,同时正视短处并且尽可能确保短处不会造成非常严重的问题,也能取得非常理想的结果。最近做了一些关于程序为何会有bug的思考,总结下来主要有这么几点,根据权重排名,1.对开发项目的语言,掌握程度不够2.没有系统化的抽象思维3.功能模块频繁的改动。

你可能感兴趣的:(skynet,lua,c语言)