前言
提起中国的lua产品,就不得不想到skynet,一款针对游戏,但又不仅限于游戏的服务端架构。skynet充分利用了lua的特性,并且在此基础上易扩展HTTP、HTTPS、WebSocket等模块,因此由skynet入手理解lua原理以及服务端架构是一个非常不错的选择。
通过skynet,我们可以构建许多小巧而高性能、高可用的应用。废话不多说,让我们一起来探索skynet架构吧~
skynet通信原理与源码分析
服务端架构中,不同子服务的通信调度是核心功能。因此,我们以单点(standalone)的skynet实例为例,由外而内,逐步剖析。
要介绍skynet的通信原理,首先要提到lua中的一个概念——lua_State。lua_State是lua的运行时(runtime),是一个原生隔离的、高性能的运行环境,若在多核并行运行lua_State,其性能一定不会差。lua作为嵌入式语言,以C为基础,可以实现操作系统粒度级的lua_State调度,因此skynet也就如同lua_State管理器一样了。
每一种业务可以看作一个service,而每一个service中,都会有一个lua_State充当执行业务逻辑的环境。举个例子,在实际开发当中,比如做一个HTTP服务的话,我们需要自己预先配置好的skynet service主入口lua文件中,写上skynet.uniqueservice("app")启动一个独特的名为app的服务,而后在其中的逻辑中,根据每一个HTTP连接,解析其中的数据包。并调用skynet.newservice动态创建单独的上下文服务ctx来处理这个请求。ctx服务还有可能需要查询数据库中的数据,并返回结果,因此我们可能还需要通过skynet.uniqueservice("db")预先创建数据库服务db二次封装skynet内置mongo、mysql库的功能,然后再通过skynet.call来与db服务通信,获得db服务某个函数执行的返回结果,再在ctx服务的处理逻辑中写入HTTP Response,从而完成整个处理过程。在这一过程中,具体业务逻辑的处理都会在各个service所拥有的lua_State中运行,但调度通信的逻辑,则就是底层的活了。
因此在skynet底层中,不仅需要支持多个lua_State的运转,而且相对更有挑战性的是,如何让service之间能够相互交流。为了解决这个问题,我们可以看到,在底层中,每一个service都属于snlua类型。snlua除了包括自己的lua_State之外,还维护了一个称之为context的运行状态: