对于 skynet 架构的理解
Intro
最近迷上了云风的 skynet 框架,但苦于 skynet 上手难度确实比较高,于是就萌生了搞清楚 skynet 的设计,然后自己拿 python 抄一个架构类似的游戏服务器的想法。
于是,就此机会,我从个人使用体验、文档、被到处转载的 blog 的基础上,稍微做了一些思考。
skynet 的消息机制
首先要提起的是 skynet 中服务的概念。
skynet 的服务是一个个 lua 文件,当然根据 wiki 的说法,也可以是其他任意一种随你喜欢的语言编写。
引用自wiki - GettingStarted
最后是服务工作阶段,当你在初始化阶段注册了消息处理函数的话,只要有消息输入,就会触发注册的消息处理函数。这些消息都是 skynet 内部消息,外部的网络数据,定时器也会通过内部消息的形式表达出来。
从 skynet 底层框架来看,每个服务就是一个消息处理器。
从这里可以看到,服务的主要用法是消息回调。skynet 框架分发消息给服务,服务是 consumer,但同时服务也可以发出消息,因此服务也是 producer。
skynet 的服务处理消息回调的方式是启动一个 co-routine,每个消息都分别启动一个 co-routine,然后在 co-routine 里调用使用skynet.dispatch
绑定的消息处理方法。
显然,用 co-routine 的处理方式是不够高效的,因为 co-routine 的计算并不是真正并行,所以在服务之上,还有多线程的调度器,允许多个Lua虚拟机里的 co-routine 同时运行。
注意是多个Lua虚拟机——所以虚拟机内的co-routine并不会出现数据竞争,service 之间以 actor 模式通信,线程间高效地传递数据,也就是服务间的消息机制。因此 skynet 的 wiki 文档才会说,单个进程内的 skynet 有最高效的并行性能。
大体来说,skynet的架构是这样子的。
层级 | 名称 | 责任 |
---|---|---|
调度层 | skynet进程 | 调度线程轮流执行lua虚拟机。 |
消息层 | 消息队列 | 分发消息给服务 |
服务层 | 服务 | 发布消息,设置消息处理回调 |
回调层 | 消息回调 | 每个消息回调都会启动一个新的 co-routine 执行回调函数 |
和云风演讲中提到的 skynet 就是个小的操作系统不谋而合。线程就是CPU,Lua虚拟机就是skynet这个“操作系统”下被调度的进程,轮流占用CPU。