skynet 阅读笔记
时间: 2015-08-20来源:OSCHINA
前景提要
https://github.com/cloudwu/skynet
skynet 整体代码分为3个部分: 1: skynet-src 核心网络层 2: service-src 服务层 3: service 使用lua实现的服务
skynet 实现是一套Actor模式的网络架构,Actor 中核心的概念包括: Worker 工作执行器 Actor 封装了上下文的相关服务实现 master 调度分配器
在skynet的核心网络层中,主要包含: worker的实现 module的加载, 用于支持actor的实现 网络分发和监听 以及相关worker的调度
module加载采用dlsym 的字符串加载方式,优点便于配置,缺点阅读代码查找相关实现比较麻烦。
module加载的service_snlua 服务将用于 加载执行lua代码,并将上下文环境保存到lua虚拟机中,从而构成一个Actor
在skynet_start.c 中的 thread_worker 是工作执行器的实现,
通过从消息队列中获取消息,并将消息分发出去交给service来执行。
当没有消息的时候 worker线程将会等在一个条件变量上。
分配器的实现
Skynet 存在一个全局消息队列的队列 global_queue,每个worker 从 global_queue 中获取一个消息队列,接着执行当前消息队列的上下文中的回调函数。
skynet_context_new 函数用于分配一个新的上下文,并且生成一个新的消息队列,而每个上下文相当于一个Actor, 而上下文对应的消息队列 相当于一个 mailbox, 这也就解释了 在 thread_worker 线程中为什么依次去 取不同的消息队列的消息,防止某个Actor被饿死。
在skynet 存在一个 command_func cmd_funcs 里面包含了所有的服务器命令,总共18条,分别为 { "TIMEOUT", cmd_timeout } { "REG", cmd_reg }, { "QUERY", cmd_query }, { "NAME", cmd_name }, { "NOW", cmd_now }, { "EXIT", cmd_exit }, { "KILL", cmd_kill }, { "LAUNCH", cmd_launch }, { "GETENV", cmd_getenv }, { "SETENV", cmd_setenv }, { "STARTTIME", cmd_starttime }, { "ENDLESS", cmd_endless }, { "ABORT", cmd_abort }, { "MONITOR", cmd_monitor }, { "MQLEN", cmd_mqlen }, { "LOGON", cmd_logon }, { "LOGOFF", cmd_logoff }, { "SIGNAL", cmd_signal },
当某处代码调用LAUNCH 命令的时候就会新建一个上下文,同时分配一个新的消息队列给该上下文,这样Worker就可以执行消息的分发了。
而skynet_send 以及 skynet_sendname 函数实现了向消息队列投递消息;
这样整个调度基本流程就清晰了: 首先通过LAUNCH 命令启动一个上下文,创建一个消息队列 接着通过skynet_send 向消息队列中投递消息 Worker线程在合适的时机将消息分发给对应上下文的 处理函数
启动流程
在skynet_start 启动函数中, 通过执行 snlua bootstrap 命令,执行系统初始化
snlua bootstrap表示执行 bootstrap.lua 脚本来具体初始化。
bootstrap 中将会注册需要的一些 lua服务。
而调用 skynet_socket_init 将会启动socket服务器
消息的分类
skynet中消息分为两类: 服务器内部各个Actor之间互相投递消息 通过socket 消息投递
thread_socket 为socket线程主循环,主要函数是skynet_socket_poll ,
存在两个方向数据:即从socket接受到的网络数据,和从内部向外发送的网络数据。 从网络接受的数据通过 forward_message 推送给合适的消息队列,通过 skynet_context_push 函数。 发送给网络的数据 skynet_socket_send 接口来发送
skynet_socket是一个基础,在之上构建的服务实例也是一个Actor, 例如service_gated 服务, 以及lua的 gateserver 服务。
这样当内部服务需要通过socket向外部发送消息的时候,首先将message 投递给gate,接着由gate来调用实际的socket接口向外发送消息。
一个例子如下: 首先启动gate 客户端连接gate gate 根据消息创建对应的 Actor Agent 来处理 Agent 可以通过gate 来向对应客户端投递消息, 客户端消息也可以通过gate 传递给agent
Actor 的实现
lua层中通过实例化一个服务来构建一个新的lua状态机,从而构建一个独立的Actor。 lua中的接口为 skynet.newservice 最终调用skynet_context_new 来构建新的Actor。
每当socket 需要接受或者发送数据,或者timer定时器时间到了,都会调用wakeup, 这样worker线程就会去获取消息队列数据. 系统存在一个Monitor线程, 用于监控所有其它线程,包括socket线程,timer线程,worker线程。
Timer 实现
skynet_timer 有一个 skynet_timeout API, 在skynet_server 中存在一个 TIMEOUT命令,当接受到TIME_OUT命令的时候,就会增加一个新的timer。
lua层接口为 skynet.timeout。
Timer主要应用: 某些Actor需要定期执行,通过skynet.timeout 创建一个协程定期调用函数。
lua协程
skynet lua接口中有一个 co_create 用于创建协程。在以下几种情况下创建: 增加一个timeout 定时器, 定时后执行协程 fork 一个函数,用于创建一个新的 协程,将协程加入到fork_queue中,在下次分发消息的时候执行该协程 raw_dispatch_message 当分发消息的时候将会将对应的消息处理函数放入协程中
协程可以等在特定的事件上,当事件发生的时候,唤醒对应协程的执行,这个通过一个suspend函数实现的,将session, 事件以及对应的协程保存起来,当事件发生,找到对应的协程,接着执行协程即可。
skynet的协议以及投递消息寻址方式
skynet 中发送消息的接口主要两个 skynet_send 和skynet_sendname.
lua层接口 skynet.send
发送消息的时候一般需要提供,当前发送服务的上下文,消息投递来源,消息目标服务接受者,消息类型,消息会话id,消息数据和消息数据大小。
参考样例:watchdog.lua 和agent.lua
在watchdog.lua中,close_agent 调用skynet.send(目标服务对象agent, 协议类型lua, 数据内容disconnect)
这样就通过lua打包协议,将disconnect 字符串发送给了 一个agent服务对象。
在agent.lua中,skynet.start( skynet.dispatch("lua" ))
对通过lua协议分发来的消息,注册相关的处理函数。在skynet.lua 的 raw_dispatch_message 函数中,当收到新的消息,则根据协议类型lua 找到处理函数.
而agent.lua 中调用skynet.ret()含义为,将函数执行的结果按原路yield返回给请求方。
而调用agent.lua 的分发处理函数的 raw_dispatch_message 中以协程方式调用该函数,因此在suspend 函数中将会收到,RETURN 命令,而将函数调用结果返回给watchdog.lua
在watchdog.lua 的socket.OPEN 函数中,调用了skynet.call 这个接口和skynet.send不同在于call 需要等待请求的服务方的返回。
skynet.call实现使用了 yield_call函数,将会将目标服务和session匹配起来,接着yield一个call命令, 当对方服务的RESPONSE 发送回来的时候,会带上相关的会话id,接着在raw_dispatch_message 中检测到协议为 RESPONSE, 根据会话id 去除watchdog.lua 的挂起的协程,继续执行watchdog的协程。
skynet 的网络模型
skynet 底层只有skynet_send 标准接口用于向目标投递消息,不同的通讯模型建立在这个基础之上。 request response lua层skynet.call 将启动一个会话,并将lua协程等在该会话上,当response发送回来之后则重启协程执行 request lua 层skynet.send 直接调用c接口,发送数据包 push 每当skynet raw_dispatch_message 时,都会启动一个协程来处理对应的消息, 也就是每个消息对应一个协程, 在同一个Actor中可以同时存在多个协程
skynet 消息类型 协议类型

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

热门排行