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活 ...
随机推荐
- 高效的DDoS攻击探测与分析工具——FastNetMon
一.简介 FastNetMon这是一个基于多种抓包引擎(NetFlow, IPFIX, sFLOW, netmap, PF_RING, PCAP)的DoS/DDoS攻击高效分析工具,可以探测和分析网络 ...
- 使用IndexReader.repen提高搜索速度
1,使用indexreader创建indexsearcher. 2,indexsearcher在使用完了以后不要关闭. 3.使用indexreader.isCurrent()判断索引是否被indexw ...
- Queueing in the Linux Network Stack !!!!!!!!!!!!!!!
https://www.coverfire.com/articles/queueing-in-the-linux-network-stack/ Queueing in the Linux Networ ...
- [转] 剖析 epoll ET/LT 触发方式的性能差异误解(定性分析)
http://blog.chinaunix.net/uid-17299695-id-3059078.html PS:Select和Poll都是水平触发,epoll默认也是水平触发 ET模式仅当状态发生 ...
- Linux磁盘管理:LVM逻辑卷的创建及使用
一.创建LVM逻辑卷 事先添加了三块虚拟物理磁盘/dev/sdb 1G, /dev/sdc 2G, /dev/sdd 3G 使用fdisk –l命令查看: [root@localhost ~]# fd ...
- Linux基础系列—Linux内核源码目录结构
/** ****************************************************************************** * @author 暴走的小 ...
- CDOJ 92 – Journey 【LCA】
[题意]给出一棵树,有n个点(2≤N≤105),每条边有权值,现在打算新修一条路径,给出新路径u的起点v,终点和权值,下面给出Q(1≤Q≤105)个询问(a,b)问如果都按照最短路径走,从a到b节省了 ...
- POJ 1011 sticks 搜索
Sticks Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 125918 Accepted: 29372 Descrip ...
- shell 求总分
求总分并且输出: 文件a.txt 学号 姓名 性别 年龄 张三 男 赵四 男 李丽 女 文件b.txt 学号 语文 数学 英语 方法1: #!/bin/sh paste a.txt b.txt ccc ...
- MsSql省市联动表
drop table area CREATE TABLE [dbo].[Area] ( , ) NOT NULL , ) COLLATE Chinese_PRC_CI_AS NOT NULL , ) ...