skynet intro

Skynet是什么呢?

  • 轻量级游戏开发框架
  • 使用框架实现Actor模型

游戏服务器开发时希望能够充分利用多核优势,将不同的业务放在独立的执行环境中处理,协同工作。这个执行环境最早期望是利用操作系统的进程,后来发现如果必定采用嵌入式语言如Lua,那么独立的操作系统进程的意义不大。

LuaState已经提供了良好的沙盒,隔离不同执行环境,而多线程模式可以使得状态共享、数据交换更加高效。但是多线程模型又存在诸多弊病,比如复杂的线程锁、线程调度问题等。这些问题都可以通过减小底层的规模精简设计,最终把危害限制在很小的范围内。

早期的Skynet v0版本中,Skynet是使用Erlang+C driver开发的,Erlang中的多进程似乎是:每个玩家都有一个代理服务。当在40v40时,使用台式机测试时是存在困难的,于是Cloud滋生了重新考虑之前的设计的念头。由于之前的设计方案是:每个代理的状态都需要通知给其他代理,这造成了大量内部消息重复,这明显是可以优化的。

掂量下,如果设计一个共享无锁队列,避免了无谓复制,内部消息包可以降低90%,整体性能能提升15%左右。为了验证Skynet v0的性能,编写了一个简单的Skynet v1,v1完全使用C作底层通信框架,摒弃了之前ZeroMQ提供通信的部分,提供Lua接口编写应用服务,整体代理在4000多行的C代码和1000多行的Lua代码,完成了Skynet v0一样的功能。

  • Skynet提供了一个简洁、稳定、高效、高可用的分布式服务开发框架。
  • Skynet是一个轻量级通用的服务器基础框架
  • Skynet是基于C与Lua的开源服务端并发框架,使用单进程多线程Actor模型。
  • Skynet服务器支持10K+客户端接入和处理

Skynet当前规模是8K多行的C代码和2K多行Lua代码,实现了一个多线程高并发的在线游戏后台服务框架,提供定时器、开发调度、服务扩展框架、异步消息队列、命名服务等基础能力,支持Lua脚本。

Skynet是一个轻量级网络服务器架构而非完整的游戏服务端,它是服务端的最底层框架,和游戏业务相关的服务都是基于此框架之上开发的。其功能只是管理好服务(加载和调度)和服务之间的调用(请求和响应)。

什么是Actor模型

  • Actor模型主要用于处理并行计算
  • Actor模型中一个actor是一个最基本的计算单元
  • Actor模型是基于消息计算的
  • Actor模型中actor之间是相互隔离的

为什么要使用Skynet呢?

  • 逻辑高并发无需为多线程编程烦恼
  • 业务功能使用Lua语言开发
  • 逻辑同步而不阻塞

例如:C++服务端项目开发中会分为两种方式,一种是逻辑多线程,程序员需要维护锁。另一种是逻辑单线程,程序员无需考虑锁。在逻辑多线程中,由于程序员对锁的使用场景模糊造成逻辑开发困难,导致逻辑多线程并没有体现出它的优势。另外,对锁的粒度掌控不好。逻辑单线程开发虽然不用考虑锁,但限于单线程的处理能力,一般承载不高。Skynet框架采用的是逻辑多线程的方式,但并不需要考虑锁的问题。

Skynet框架为什么会采用Lua语言来开发呢?

Lua语言是一种脚本语言,数据结构简单。主要数据结构为table表,table可以是hash表,hash表中的键值对中键值可以是table表也可以是function。另外,table表提供了metatable元表,通过内置的属性来访问或设置table。

Lua自身提供了GC,一般的垃圾回收器都需要自己创建自己释放,在Lua中垃圾回收期会将没有引用的变量进行回收。无需为野指针头痛了。

Lua相当于C与C++的中间交集,因此Lua可以很好地和C和C++沟通 。由于Lua本身是使用C语言开发的,Lua和C或C++沟通主要是通过标准栈来实现(栈通信)。

Lua自身提供了GC,而C需要手动收回垃圾。当Lua和C通信时,是如何做到协同的呢?Lua提供了两种数据结构,分别是轻量用户数据(lightuserdata)和用户数据(userdata)。例如在C中使用userdata创建的变量,会交由Lua来管理生命周期。而使用lightuserdata创建的数据,则会由C来管理其生命周期。

Lua的function跟C或C++不同,Lua中的function实际上是由C中的function+upvalue共同组成的闭包。

Skynet框架为什么可以逻辑同步而不阻塞呢?

例如在C++中从Redis中读取一个数据时发送给客户端,首先服务器需要和Redis之间建立一条连接,然后在向Redis发送获取的消息。因此在C++单线程中很容易会发生阻塞逻辑线程,其他请求是没有办法进行处理的。而在Skynet中,所有的消息过来时,Lua会使用Coroutine来处理消息。当发送消息时会挂起当前Coroutine,当Redis返回数据时会唤醒当前Coroutine,将值返回给客户端。因此不会发生阻塞。在Skynet中实际上是采用同步的写法,最终运行是异步的实现。

Skynet特点的什么

  • 少量C代码和大量Lua代码组成
  • 基于Actor模型,天然多线程。
  • 天然集成网络、数据库访问功能
  • 使用Lua的协程处理消息永不堵塞
  • 自带集群功能
  • 官方只支持Linux

Skynet的优点是什么

  • 高低级语言配合

Skynet是融合了低级语言C消息框架和高级动态语言Lua的混合体,这种结构称为hybird framework混合框架,使用运行高效的C来编写服务节点,使用Lua开发高效且安全隔离的上层业务。

  • 组件化能力

Skynet内核(C部分)自身支持加载模块*.so,可使用C语言编写性能有要求的服务节点,通过消息与其他节点配合。而Lua又是对C语言极为友好的动态语言,所以可找到很多Lua的C扩展。

Skynet核心是什么

  • C实现的消息循环和组件加载机制
  • Lua实现的以消息为中心的进入退出协程的包装层

Skynet核心解决什么问题呢?

作为核心功能,Skynet仅解决一个问题:把符合规范的C模块从动态库(.so文件)中启动起来,绑定一个永不重复(即使模块退出)的数字ID作为其处理器handle。这里我们称模块为服务service,服务之间可以自由发送消息,每个模块可以向Skynet框架注册一个回调函数callback,用来接收发给它的消息。每个服务都是一个个消息包驱动,当没有包到来时,它们就会处于挂起状态,对CPU资源零消耗。如果需要自主逻辑则可利用Skynet提供的timeout消息定期触发。

Skynet提供了名字服务,可以给特定的服务起一个易读的名字,而不是使用ID来指代。因为ID和运行时状态相关,无法保证每次启动服务都有一致的ID,当名字却可以。

Skynet核心不解决什么问题?

Skynet的消息传递都是单向的,以数据包为单位传递。并没有定义类似于TCP连接的概念,也没有约定RPC调用的协议。不规定数据包的编码方式,也没有提供一致的复杂数据结构的列集API。

Skynet进程框架

Skynet原则上主张所有服务器都在同一个操作系统进程上协作完成,所以在核心层内部考虑跨机器通讯机制。Skynet不为单独服务的崩溃、重启提供支持,和普通的单线程程序一样,你要为你代码中的bug和意外负责。和操作系统不同的是:操作系统会认为用户进程都是不可靠的,它不会让一个用户进程的错误影响到另一个进程。但Skynet内所有的服务都有统一的目的,为游戏的最终客户服务。因此某个环节出了错误都可能是致命的,因此没有必要被问题隔离开。

简单来说,Skynet只负责把一个数据包从一个服务内发送出去,让同一进程内的另一个服务接收然后调用对应的callback函数处理。Skynet保证模块的初始化过程时,每个独立的callback都是相互线程安全的。编写服务的人不需要特别的为多线程环境考虑任何问题,专心处理发送给它的一个个数据包即可,其实这就是Erlang的Actor模型。

为了提供高效的服务间通讯,Skynet并不关心数据包是怎样被打包的,它甚至不要求这个数据包内的数据是连续的,虽然这样做很危险,在跨机通讯中除非你保证你所有的数据包绝对不被传递到当前所在进程中。因为它仅仅是把数据包的指针以及声明的数据包长度传递出去。由于服务都是在同一个进程内,因此接收方取得这个指针后就可以直接处理其引用的数据了。这个机制在必要时,可以保证绝对的零拷贝,几乎等于在同一线程内做一次函数调用的开销,当然这只是Skynet提供性能上可能性。推荐一种更为可靠但性能略低的解决方案:约定每个服务发送出来的包都复制到用malloc分配出来的连续内存。接收方在处理完这个数据块,也就是在处理的callback函数调用完毕时,会默认调用free函数释放掉所占用的内存空间。简单来说就是:发送方申请内存而接收方释放内存。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 引言: 一直都是从事客户端的开发工作,最近抽了点时间想了解一下服务器开发的相关知识,一番博客瞎逛之后,发现了一个不...
    linshuhe1阅读 5,177评论 0 10
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,733评论 0 38
  • 写在前面 这篇文章是分析skynet框架,自己“用”skynet已经有一年,项目中是以它为底层框架,上层使用lua...
    fooboo阅读 13,031评论 1 14
  • 一、简历准备 1、个人技能 (1)自定义控件、UI设计、常用动画特效 自定义控件 ①为什么要自定义控件? Andr...
    lucas777阅读 5,186评论 2 54
  • 刚刚结束了期中考试,4月26日邀请到中国家校合作教育指导师,北京四中的王利娜老师就“如何帮助孩子增强动力,提高成绩...
    善默勤容阅读 364评论 0 0