Skynet:特性收集
基于云风的 blog,收集 skynet 的特性以便将来在代码中一一验证。
“ ... ” 部分节选自云风的 BLOG。
1. 基于 Erlang-Actor 模式的 C 实现
“把一个符合规范的 C 模块,从动态库(so 文件)中启动起来,绑定一个永不重复(即使模块退出)的数字 id 做为其 handle 。模块被称为服务(Service),服务间可以自由发送消息。每个模块可以向 Skynet 框架注册一个 callback 函数,用来接收发给它的消息。每个服务都是被一个个消息包驱动,当没有包到来的时候,它们就会处于挂起状态,对 CPU 资源零消耗。如果需要自主逻辑,则可以利用 Skynet 系统提供的 timeout 消息,定期触发。”
“Skynet 原则上主张所有的服务都在同一个 OS 进程中协作完成。Skynet 只负责把一个数据包从一个服务内发送出去,让同一进程内的另一个服务收到,调用对应的 callback 函数处理。它保证,模块的初始化过程,每个独立的 callback 调用,都是相互线程安全的。”
2. skynet 不予解决的问题
“Skynet 的消息传递都是单向的,以数据包为单位传递的。并没有定义出类似 TCP 连接的概念。也没有约定 RPC 调用的协议。不规定数据包的编码方式,没有提供一致的复杂数据结构的列集 API 。”
3. 服务间通信的优化
如果有必要,数据包在处理过程中可以实现零拷贝:“Skynet 并不关心数据包是怎样被打包的。它仅仅是把数据包的指针,以及你声称的数据包长度(并不一定是真实长度)传递出去。由于服务都是在同一个进程内,接收方取得这个指针后,就可以直接处理其引用的数据了。”
当然,绝大多数应用场景应该有必要采用另外一种方案:“Skynet 推荐的是一种更可靠,性能略低的方案:它约定,每个服务发送出去的包都是复制到用 malloc 分配出来的连续内存。接收方在处理完这个数据块(在处理的 callback 函数调用完毕)后,会默认调用 free 函数释放掉所占的内存。”,这样至少是直接访问内存,而不是用消息通讯的方式。
服务间通信 session:服务内对其他不同服务回调的区分;type:消息类型;
4. 进程间通信:
“单个 skynet 进程内的服务数量被 handle 数量限制。handle 也就是每个服务的地址,在接口上看用的是一个 32 位整数。但实际上单个服务中 handle 的最终限制在 24bit 内,也就是 16M 个。高 8 位是保留给集群间通讯用的。我们最终允许 255 个 skynet 节点部署在不同的机器上协作。每个 skynet 节点有不同的 id 。这里被称为 harbor id 。”
“每个消息包产生的时候,skynet 框架会把自己的 harbor id 编码到源地址的高 8 位。这样,系统内所有的服务模块,都有不同的地址了。从数字地址,可以轻易识别出,这个消息是远程消息,还是本地消息。”
“所有的消息包在发送时,skynet 识别出这是一个远程消息包时,都会把它转发到 harbor 服务内。harbor 服务会建立 tcp 连接到所有它认识的其它 skynet 节点内的 harbor 服务上。”
“skynet 目前支持一个全局名字服务,可以把一个消息包发送到特定名字的服务上。这个服务不必存在于当前 skynet 节点中。这样,我们就需要一个机构能够同步这些全局名字。为此,我实现了一个叫做 master 的服务。它的作用就是广播同步所有的全局名字,以及加入进来的 skynet 节点的地址。”
5. 服务间广播:
广播包引用计数:“skynet 会识别消息的 type 是否为 PTYPE_MULTICAST
,然后有不同的生命期管理策略,并把组播包交给组播服务处理。”
“组播服务并不解决分熟在不同集群节点上的服务归组的问题。即,每个分组内的成员都必须在同一系统进程内。这可以极大的简化设计。用户可以让不同的服务 handle 归属一个组号。向 skynet 索取这个组号对应的 handle 。向这个组的 handle 发送消息,就等同于向组内所有 handle 发送消息。”
跨进程分组:“首先,提供了一个简单的,用 C 编写的服务,叫做 tunnel 。它可以把发送给它的消息,无条件的转发到另一个 handle 上。这个转发 handle 可以是在不同 skynet 节点上的。”,“我用 lua 编写了一个全局的分组管理器,协调在不同节点上,创建出相同组名的分组来。然后用 tunnel 服务连接不同节点上的同一分组就够了。”
6. 基础服务的流程控制:
“skynet 提供了一个叫做 skynet_command
的 C API ,作为基础服务的统一入口。它接收一个字符串参数,返回一个字符串结果。你可以看成是一种文本协议。但 skynet_command
保证在调用过程中,不会切出当前的服务线程,导致状态改变的不可预知性。”
7. 消息调度
“在 Skynet 启动时,建立了若干工作线程(数量可配置),它们不断的从主消息列队中取出一个次级消息队列来,再从次级队列中取去一条消息,调用对应的服务的 callback 函数进行出来。为了调用公平,一次仅处理一条消息,而不是耗净所有消息(虽然那样的局部效率更高,因为减少了查询服务实体的次数,以及主消息队列进出的次数),这样可以保证没有服务会被饿死。”
从业务需求出发,核心在于每次业务处理是否会对同一个数据块进行写操作,如何会的话,服务之间就要进行同步协调,那么不如用单个服务轮询的方式好处理。
我的业务需求是聊天室。公共聊天室的话,启动多个服务,每个服务需要做2件事:1. 收到广播消息后向其他用户广播 - 用户信息要保存在进程中。2. 将广播消息写入一个缓存队列。在此基础上,需要实现一个定时将缓存队列中的新数据持久化的服务。
如果用 skynet 做聊天服务器的话,为了充分利用消息调度的机制 与 skynet 对多核的利用,可以采用 “skynet 服务池” 来处理所有玩家的聊天请求。
8. Gate
"它的特征是监听一个 TCP 端口,接受连入的 TCP 连接,并把连接上获得的数据转发到 skynet 内部。Gate 可以用来消除外部数据包和 skynet 内部消息包的不一致性。"
9. Connection
"Connection 分两个部分,一部分用于监听不同的系统 fd 的可读状态,这是用 epoll 实现的。如果在没有 epoll 支持的环境(比如 freebsd 下),可以很轻松的实现一个替代品。它收到这个连接上的数据后,会把所有数据不做任何分包,转发到另一个服务里去处理。"
"使用提供好的 lua 模块,可以轻松的对这些数据分包(读一个指定字节数的数据块,或是读一个以回车结束的文本行)。Lua 的 coroutine 支持,可以轻松的在数据包并不完整时挂起,却不打断执行流程。"
10. Lua 层
“Lua 的 coroutine 可以帮助我们把一个个在 C 层面分离的 callback 调用串成逻辑上连续的线索。当 Lua 编写的服务接收到一个外部请求时,对应的底层 callback 函数被调用,既而转发到 Lua 虚拟机中。skynet 的 lua 层会为每个请求创建一个独立的 coroutine 。一旦在处理这个请求的 coroutine 中发生远程调用,即发出一个消息包,coroutine 会挂起。在 C 层面,这次 callback 函数正常返回了。但在 Lua 中,则是记录下这个发出的消息包的 session ,记录 session 和挂起的 corutine 在一张对应表中。之后,一但收到回应包里有相同的 session ,对应的 coroutine 则被唤醒 resume 。”
Skynet:特性收集的更多相关文章
- delphi 各新版本特性收集
delphi 各新版本特性收集 http://www.cnblogs.com/dreamszx/p/3602589.html
- C# 6.0 新特性收集
先来看一段Json.Net的代码 public JObject ToJson() { var result = new JObject(); result["X"] = X; re ...
- Java 5/Java 6/Java7/Java 8新特性收集
前言: Java 8对应的JDK版本为JDK8,而官网下载回来安装的时候,文件夹上写的是JDK1.8,同一个意思.(而这个版本命名也是有规律的,以此类推) 一.Java 5 1.https://seg ...
- C# 7.0 新特性收集
1.out-variables(Out变量) 2.Tuples(元组) 3.Pattern Matching(匹配模式) 4.ref locals and returns (局部变量和引用返回) 5. ...
- java8新特性全面解析
在Java Code Geeks上有大量的关于Java 8 的教程了,像玩转Java 8--lambda与并发,Java 8 Date Time API 教程: LocalDateTime和在Java ...
- java8 新特性
[转载]:http://www.importnew.com/11908.html 本文由 ImportNew - 刘 家财 翻译自 javacodegeeks.欢迎加入翻译小组.转载请见文末要求. 编 ...
- delphi 各版本的特性
delphi 各新版本特性收集 Delphi XE6新增了一些特性并增强了原有的功能,主要有以下几个方面: IDE(整合开发环境) Internet XML(扩展标记语言) Compiler( ...
- C#反射与特性(六):设计一个仿ASP.NETCore依赖注入Web
目录 1,编写依赖注入框架 1.1 路由索引 1.2 依赖实例化 1.3 实例化类型.依赖注入.调用方法 2,编写控制器和参数类型 2.1 编写类型 2.2 实现控制器 3,实现低配山寨 ASP.NE ...
- ATDD
什么是ATDD 首先,ATDD不是一种测试方法论,而是一种开发方法论. UTDD涉及的人员仅仅是开发人员,那么ATDD仅仅涉及测试人员吗?不是,产品.开发.测试都需要参与到ATDD中来. 在ATDD活 ...
随机推荐
- openStack ceilometer API
1.概述 Ceilometer是OpenStack中的一个子项目,它像一个漏斗一样,能把OpenStack内部发生的几乎所有的事件都收集起来,然后为计费和监控以及其它服务提供数据支撑.Ceilomet ...
- Selenium webdriver 操作chrome 浏览器
Step1: 下载chromedriver. 下载路径: http://chromedriver.storage.googleapis.com/index.html 选择一个合适的下载即可.我下载的是 ...
- Rational Rose与UML教程
在学UML的过程中,Rational Rose的角色无比重要.现在能找到的大多数是2003的,但下面连接是2007. http://blog.csdn.net/skl_TZ/article/detai ...
- [置顶] ruby变量详解(收集+整理)
ruby的变量有局部变量,全局变量,实例变量,类变量,常量. 1.局部变量 局部变量以一个小写字母开头或下划线开头 局部变量有局部作用域限制(比如一个block内),它的作用域起始于声明处,结束于该声 ...
- Android FastJson解析
1.导包 compile 'com.alibaba:fastjson:1.2.21' public static final Object parse(String text); // 把JSON文本 ...
- 开启.htaccess重写之前先来看看mod_rewrite(转)
Apache的Mode Rewrite模块提供了一个基于正则表达式分析器的重写引擎来实时重写URL请求.在大多数情况下,它和.htaccess文件配合使用.就是说,.htaccess文件的一个主要功能 ...
- PHP安全编程:不要让不相关的人看到报错信息(转)
没有不会犯错的开发者,PHP的错误报告功能可以协助你确认和定位这些错误,可以提供的这些错误的详细描述,但如果被恶意攻击者看到,这就不妙了.不能让大众看到报错信息,这一点很重要.做到这一点很容易,只要关 ...
- QT 内存泄露 检测
一:问题出现 最近几天在做一个QT程序,IPX的检测控制程序.需要全天候运行.自己做完了,然后就运行.使用 top|grep TP2 来动态检测程序的CPU,内存占用律.不幸的是,一晚 ...
- 通过GitHub Pages建立个人站点(详细步骤)
1 Git简介 2 为什么使用Github Pages 3 创建Github Pages 3.1 安装git工具. 3.2 两种pages模式 3.3 创建步骤 3.4 常用命令 4 使用Jekyll ...
- discuz! X3.2 自定义后台门户模块模板里的标签
这里只提供对源码的修改, 至于插件, 暂不考虑... 想在首页里展示一些自定义字段的内容, 奈何dz无此功能, 无奈去扒源码. 首先切到 source 文件夹下 1. 在 class/block/po ...