Skynet入门(一)

概念

skynet 是一个为网络游戏服务器设计的轻量框架。但它本身并没有任何为网络游戏业务而特别设计的部分,所以尽可以把它用于其它领域。

设计初衷

如何充分利用它们并行运作数千个相互独立的业务。

模块设计建议

在 skynet 中,用服务 (service) 这个概念来表达某项具体业务,它包括了处理业务的逻辑以及关联的数据状态。使用 skynet 实现游戏服务器时,不建议把业务状态同步到数据库中,而是存放在服务的内存数据结构里。服务、连同服务处理业务的逻辑代码和业务关联的状态数据,都是常驻内存的。

可以把 skynet 理解为一个简单的操作系统,它可以用来调度数千个 lua 虚拟机,让它们并行工作。每个 lua 虚拟机都可以接收处理其它虚拟机发送过来的消息,以及对其它虚拟机发送消息。每个 lua 虚拟机,可以看成 skynet 这个操作系统下的独立进程,你可以在 skynet 工作时启动新的进程、销毁不再使用的进程、还可以通过调试控制台监管它们。skynet 同时掌控了外部的网络数据输入,和定时器的管理;它会把这些转换为一致的(类似进程间的消息)消息输入给这些进程。

网络

我们不建议你在 skynet 的服务中再使用任何直接和系统网络 api 打交道的模块,因为一旦这些模块被网络 IO 阻塞,影响的就不只是该服务本身,而是 skynet 里的工作线程了。skynet 会被配置成固定数量的工作线程,工作线程数通常和系统物理核心数量相关,而 skynet 所管理的服务数量则是动态的、远超过工作线程数量。skynet 内置的网络层可以和它的服务调度器协同工作,使用 skynet 提供的网络 API 就可以在网络 IO 阻塞时,完全释放出 CPU 处理能力

我们通常建议使用一个网关服务,专门监听端口,接受新连接。在用户身份确定后,再把真正的业务数据转交给特定的服务来处理。同时,网关还会负责按约定好的协议,把 TCP 连接上的数据流切分成一个个的包,而不需要业务处理服务来分割 TCP 数据流。业务处理的服务不必直接面对 socket 句柄,而由 skynet 正常的内部消息驱动即可。

运行原理

服务service运行的三个阶段

  1. 服务加载阶段,当服务的源文件被加载时,就会按 lua 的运行规则被执行到。这个阶段不可以调用任何有可能阻塞住该服务的 skynet api 。因为,在这个阶段中,和服务配套的 skynet 设置并没有初始化完毕。
  2. 服务初始化阶段,由 skynet.start 这个 api 注册的初始化函数执行。这个初始化函数理论上可以调用任何 skynet api 了,但启动该服务的 skynet.newservice 这个 api 会一直等待到初始化函数结束才会返回。
  3. 服务工作阶段,当你在初始化阶段注册了消息处理函数的话,只要有消息输入,就会触发注册的消息处理函数。这些消息都是 skynet 内部消息,外部的网络数据,定时器也会通过内部消息的形式表达出来。

从 skynet 底层框架来看,每个服务就是一个消息处理器。但在应用层看来并非如此。它是利用 lua 的 coroutine 工作的。当你的服务向另一个服务发送一个请求(即一个带 session 的消息)后,可以认为当前的消息已经处理完毕,服务会被 skynet 挂起。待对应服务收到请求并做出回应(发送一个回应类型的消息)后,服务会找到挂起的 coroutine ,把回应信息传入,延续之前未完的业务流程。

同一个 skynet 服务处理很多消息,处理这些消息的流程永远不会真正的并行,它们只是在轮流工作。一段业务会一直运行到下一个 IO 阻塞点,然后切换到下一段逻辑。你可以利用这一点,让多条业务线在处理时共享同一组数据,这些数据在同一个 lua 虚拟机下时,读写起来都比通过消息交换要廉价的多。

两次阻塞 API 调用之间,运行过程是原子的,利用这个特性,会比传统多线程程序更容易编写。如果一条用户线程永远不调用阻塞 API 让出控制权,那么它将永远占据系统工作线程。skynet 并不是一个抢占式调度器,没有时间片的设计,不会因为一个工作线工作时间过长而强制挂起它。

消息

组成

  • 消息类型:回应消息、网络消息、调试消息、文本消息、Lua 消息、错误。
  • session
  • 发起服务地址
  • 接收服务地址
  • 消息 C 指针
  • 消息长度
消息类型
  • 回应消息通常不需要特别处理,它由 skynet 基础库管理,用来调度服务内的 coroutine 。
  • 网络消息也不必直接处理它,skynet 提供了 socket 封装库,封装管理这类消息,改由一组更友好的 socket api 方便使用。
  • 调试消息已经被默认的 skynet 基础库处理了。它使得所有 skynet 服务都提供有一些共同的能力。
  • 真正的业务逻辑是由文本类消息和 Lua 类消息驱动的。它们的区别仅在于消息的编码形式不同,文本类消息主要方便一些底层的,直接使用 C 编写的服务处理,它就是简单字节串;而 Lua 类消息则可以序列化 Lua 的复杂数据类型。大多数情况下,我们都只使用 lua 类消息。
  • 接管某类消息需要在服务的初始化过程中注册该消息的序列化及反序列化函数,以及消息回调函数。

Actor模型

概念

一种用于实现并发计算的数学模型,核心思想是将计算过程视为一系列的Actor,每个Actor称为“服务”(service),是独立的逻辑执行单元‌,能够接收消息、创建新的Actor、发送消息,并决定如何响应接下来的消息‌。

特性

  • 服务隔离:每个服务(Actor)运行在独立的 Lua 虚拟机中,内存隔离,数据通过消息传递共享,避免直接内存操作。
  • 服务通信:服务间通过异步消息通信(skynet.call 同步调用、skynet.send 异步发送),消息由框架自动路由到目标服务的消息队列。
  • 动态服务管理:Actor可以在运行时创建更多的Actor,这种动态性使得Actor模型能够根据需要扩展系统‌。

组成

  • ID‌:每个Actor有一个唯一的标识符。
  • ‌状态‌:表示Actor的当前状态,如活跃、挂起等。
  • ‌消息队列‌:用于存储待处理的消息。
  • ‌回调函数‌:处理接收到的消息。

优势

  1. 简化并发编程

    • 无需锁机制:天然避免死锁、竞态条件。

    • 逻辑清晰:每个 Actor 仅关注自身状态和消息处理。

  2. 高容错性

    • 错误隔离:单个 Actor 崩溃不影响整体系统。

    • 监督策略:通过层级结构实现优雅恢复。

  3. 弹性扩展

    • 分布式友好:Actor 可部署在不同节点,通过消息传递协作。

    • 动态负载均衡:根据压力动态创建或迁移 Actor。

  4. 高性能

    • 轻量级:Actor 内存占用小(如 Erlang/Elixir 中每个 Actor 仅需 2-3KB)。

    • 高效调度:通过轻量级线程(如协程)实现高并发。

核心功能

消息调度机制

由于skynet中是用actor模型实现,各个actor模型相互隔离,因此skynet采取了消息的方式来实现各actor的数据共享。

  • 消息队列:每个服务拥有私有消息队列(次级队列),全局消息队列管理所有活跃服务的次级队列,工作线程从全局队列中轮询处理消息。

  • 协程调度:每个消息对应一个 Lua 协程,通过 skynet.fork 创建新协程,利用 skynet.sleep 挂起逻辑,避免阻塞主线程。

运行流程
  1. 消息投递:发送方将消息放入接收方 Actor 的队列。

  2. 消息调度:接收方 Actor 的消息队列按 FIFO 顺序处理消息。

  3. 行为执行:Actor 根据当前状态和消息内容,执行以下操作之一:

    • 修改自身状态。

    • 发送新消息。

    • 创建子 Actor。

    • 停止自身或子 Actor。
      在这里插入图片描述

网络通信

  • 多协议支持:内置 TCP/UDP 网络层,通过 socketdriver 模块处理连接、粘包(如包头长度解析)。

  • 协议编解码:集成 Sproto 协议库,支持定义结构化消息格式(嵌套类型、数组),优化高频字段顺序以减少编解码开销。

高性能与扩展性

  • 线程池模型:启动多个工作线程(数量通常等于 CPU 核心数),线程按权重从全局队列中获取任务,避免线程饥饿。

  • 模块化设计:C 模块(如数据库驱动)与 Lua 服务解耦,通过动态库(.so)加载,支持热更新。

集群与分布式支持

  • 多节点通信:通过 harbor 配置节点 ID,支持跨进程通信,但主要优化单节点内的高并发,分布式需结合额外逻辑。

  • 数据共享:提供 sharedata 模块实现进程内数据共享,跨节点需通过消息或第三方存储(如 Redis)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/71401.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

threejs:用着色器给模型添加光带扫描效果

第一步:给模型添加光带 首先创建一个立方体,不进行任何缩放平移操作,也不要set position。 基础代码如下: 在顶点着色器代码里varying vec3 vPosition;vPosition position;获得threejs自动计算的顶点坐标插值(也就…

【时序预测】在线学习:算法选择(从线性模型到深度学习解析)

——如何为动态时序预测匹配最佳增量学习策略? 引言:在线学习的核心价值与挑战 在动态时序预测场景中(如实时交通预测、能源消耗监控),数据以流式(Streaming)形式持续生成,且潜在的…

Spring Boot如何利用Twilio Verify 发送验证码短信?

Twilio提供了一个名为 Twilio Verify 的服务,专门用于处理验证码的发送和验证。这是一个更为简化和安全的解决方案,适合需要用户身份验证的应用。 使用Twilio Verify服务的步骤 以下是如何在Spring Boot中集成Twilio Verify服务的步骤: 1.…

【Linux操作系统】VM17虚拟机安装Ubuntu22.04,图文详细记录

1.双击桌面的 VMware Workstation17 Player,点击“创建新虚拟机”,如下图所示。 2.选择“稍后安装操作系统”,点击“下一步”。如下图所示。 3.客户机操作系统选择“Linux”,版本选择“ Ubuntu 64位”,然后点击“下一…

软件工程---净室软件工程

净室软件工程是一种软件开发方法,旨在通过形式化的数据和严格的测试来提高软件的可靠性和减少缺陷的数量。它的核心思想是在软件开发过程中最小化或消除软件缺陷,从而提高软件的质量和可靠性。这种方法强调在软件生命周期的早期阶段使用形式化方法进行规…

迷你世界脚本区域接口:Area

区域接口:Area 彼得兔 更新时间: 2023-12-18 11:35:14 具体函数名及描述如下: 序号 函数名 函数描述 1 createAreaRect(...) 创建矩形区域 2 createAreaRectByRange(...) 创建矩形区域(通过范围) 3 destroyArea(...) 销毁区域 4 getAre…

C# 牵手DeepSeek:打造本地AI超能力

一、引言 在人工智能飞速发展的当下,大语言模型如 DeepSeek 正掀起新一轮的技术变革浪潮,为自然语言处理领域带来了诸多创新应用。随着数据隐私和安全意识的提升,以及对模型部署灵活性的追求,本地部署 DeepSeek 成为众多开发者和…

Linux--基础命令3

大家好,今天我们继续学习Linux的基础命令 mv命令 mv命令是move的缩写,可以用来移动文件或者将文件改名 move(rename) files,经常⽤来备份⽂件或者目录 语法: mv [ 选项 ] 源⽂件或目录 目标⽂件或目录 mv src[文件、目录] dst[路径、文…

【每日八股】计算机网络篇(三):IP

目录 DNS 查询服务器的基本流程DNS 采用 TCP 还是 UDP,为什么?默认使用 UDP 的原因需要使用 TCP 的场景?总结 DNS 劫持是什么?解决办法?浏览器输入一个 URL 到显示器显示的过程?URL 解析TCP 连接HTTP 请求页…

探究DeepSeek R1与OpenAI模型文本相似度背后的秘密

摘要 一项由Copyleaks进行的新研究显示,DeepSeek R1生成的文本在风格上与OpenAI模型的相似度高达74.2%。这一发现引发了对DeepSeek训练数据来源和独特性的质疑。Copyleaks作为专业检测文本抄袭和AI生成内容的平台,其研究结果具有重要参考价值。此相似度揭…

【实战 ES】实战 Elasticsearch:快速上手与深度实践-2.2.3案例:电商订单日志每秒10万条写入优化

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 Elasticsearch批量写入性能调优实战:2.2.3 案例:电商订单日志每秒10万条写入优化1. 原始架构与瓶颈分析1.1 初始集群配置1.2 性能瓶颈定位 2. 全链路…

统计Excel列中某值出现的次数

统计Excel列中某值出现的次数: 1、COUNTIF 函数用于计算满足特定条件的单元格数量。假设要统计 A 列中值为 “苹果” 出现的次数,在其他单元格中输入公式:COUNTIF(A:A,“苹果”)。其中,A:A表示要统计的范围是 A 列,&q…

nnUNet报错

nnUNet报错处理 Traceback (most recent call last):File "/opt/conda/envs/nnunet/lib/python3.11/threading.py", line 1045, in _bootstrap_innerself.run()File "/opt/conda/envs/nnunet/lib/python3.11/threading.py", line 982, in runself._target…

Compose Multiplatform+Kotlin Multiplatfrom 第四弹跨平台

文章目录 引言功能效果开发准备依赖使用gradle依赖库MVIFlow设计富文本显示 总结 引言 Compose Multiplatformkotlin Multiplatfrom 今天已经到compose v1.7.3,从界面UI框架上实战开发看,很多api都去掉实验性注解,表示稳定使用了!…

(十一)基于vue3+mapbox-GL实现模拟高德实时导航轨迹播放

要在 Vue 3 项目中结合 Mapbox GL 实现类似高德地图的实时导航轨迹功能,您可以按照以下步骤进行: 安装依赖: 首先,安装 mapbox-gl 和 @turf/turf 这两个必要的库: npm install mapbox-gl @turf/turf引入 Mapbox GL: 在组件中引入 mapbox-gl 并初始化地图实例: <templ…

智慧园区大数据云平台建设总体方案,平台方案架构-智慧园区大数据平台(320页原件Word)

第一章 项目建设背景及现状 1.1. 项目建设背景 1.2. 项目建设必要性 1.3. 项目建设目标 1.4. 建设原则 第二章 园区创新发展趋势 2.1园区经济向生态型转变 2.2 园区企业向高新型转变 2.3园区管理向城市化转变 第三章 工业园区大数据存在的问题 3.1信息化配套设施及服…

NeurIPS24 Oral!多模态融合+目标检测全新里程碑!

最近发现多模态融合目标检测实在太热了&#xff01;顶会频出&#xff01;像是NeurIPS24 Oral上端到端算法E2E-MFD&#xff1b;ECCV24上性能提升30.8&#xff05;的FRN&#xff1b;TPAMI24上推理效率狂飙270&#xff05;倍的FSF…… 主要在于&#xff1a;一方面&#xff0c;其能…

网络编程——http

在Linux系统中使用C语言实现HTTP客户端或服务器通常涉及使用套接字编程和一些HTTP协议的基本知识。下面是一个简单的示例&#xff0c;展示了如何用C语言实现一个HTTP客户端&#xff0c;向一个HTTP服务器发送请求并接收响应。 1. HTTP客户端示例 (C语言) 这个例子展示了如何用C…

【Go语言快速上手】第一部分:数据类型(数组、切片、映射)与控制语句

文章目录 一、复合类型Ⅰ 数组1. 语法2. 示例3. 特点4. 数组的传递 Ⅱ 切片1. 定义2. 语法3. 示例4. 特点5. 切片的创建6. 切片的操作切片的扩展切片的拷贝 Ⅲ 映射1. 定义2. 语法3. 示例4. 特点5. 映射的创建6. 映射的操作示例&#xff1a;插入、访问和删除判断键是否存在示例…