编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Skynet中的并发模型

wxchong 2024-06-14 13:28:22 开源技术 10 ℃ 0 评论

本文主要介绍skynet的设计理念和特点,对于具体实现细节暂不展开。

skynet是什么?

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

skynet设计初衷

作为服务器,通常需要同时处理多份类似的业务。例如在网络游戏中,你需要同时向数千个用户提供服务;同时运作上百个副本,计算副本中的战斗、让 NPC 通过 AI 工作起来,等等。在单核年代,我们通常在 CPU 上轮流处理这些业务,给用户造成并行的假象。而现代计算机,则可以配置多达数十个核心,如何充分利用它们并行运作数千个相互独立的业务,是设计 skynet 的初衷。

并发编程模型解决方案

因此,skynet提供了一种多核并发的解决方案,充分利用了多核优势。

常见的多核并发解决方案有:多进程多线程csp模型actor模型。接下来简单介绍和对比这四种并发模型。

多进程并发模型

并发实体:进程

进程间通信方式:socket,共享内存,管道,信号量,unix域等。

优点隔离性好,因为每个进程都有自己独立的进程空间

缺点统一性差,即数据同步比较麻烦;解决方案(消息队列zeromq解决最终一致性问题,rpc解决强一致性问题,zookeeper解决服务协调的问题)

多线程并发模型

并发实体:线程

线程间通信方式:消息队列,管道,锁等

优点统一性强,因为线程都在同一个进程内(这里的多线程是指同一进程内的多线程)

缺点隔离性差,线程间共享了很多资源,并且可以轻易访问其他线程的私有空间,需要使用锁来进行控制。(锁的类型选择和粒度控制都是比较难的)

csp并发模型

描述两个独立的并发实体通过**共享的通讯 channel(管道)**进行通信的并发模型。

Golang 借用CSP模型仅仅是借用了 processchannel这两个概念来实现自己的并发模型,process是在go语言上的表现就是 goroutine ,也是go并发执行的实体,每个实体之间是通过channel通讯来实现数据共享。(可理解为加强版多线程解决方案

actor模型

并发实体当然是actor。那么actor是什么呢?其实actor是从语言层面抽象出来的进程概念erlang是从语言层面来实现actor模型。(可理解为加强版多进程解决方案

actor模型有以下特点:

  • 用于并行计算
  • actor最基本的计算单元
  • 基于消息计算
  • actor之间相互隔离,通过消息进行沟通

那么skynet也采用了actorr模型,不过,不同于erlangskynet是通过框架来实现actor模型。skynet使用内存块lua虚拟机来进行环境隔离actor之间通过消息队列进行沟通,通过指针传递即可达到通信目的。

那么actor模型有哪些优势呢?我们可以启动上千万个actor并发实体,而进程/线程模型中并发实体个数是有限的。

skynet中actor的隔离与通信

其实actor就是skynet中的服务,服务分为c服务****和lua服务(比如,main.lua就是一个actor),actor的结构组成如下:

  • 隔离环境,内存块或lua虚拟机
  • 回调函数,用于执行actor,消费消息
  • 消息队列,用于存储消息

隔离

对于c服务隔离环境为内存块lua服务隔离环境为lua虚拟机

// service_logger.c 
// c服务隔离环境为内存块
struct logger {
 FILE * handle;
 char * filename;
 uint32_t starttime;
 int close;
};

// service_snlua.c 
// lua服务隔离环境为lua虚拟机
struct snlua {
 lua_State * L;
 struct skynet_context * ctx;
 size_t mem;
 size_t mem_report;
 size_t mem_limit;
 lua_State * activeL;
 volatile int trap;
};

// skynet_server.c
// context上下文隔离环境
struct skynet_context {
 void * instance;
 struct skynet_module * mod;
 void * cb_ud;
 skynet_cb cb;
 struct message_queue *queue;
  ...
};

lua一般用来做业务开发(lua服务),c一般实现底层框架以及一些计算密集型的业务(c服务)。**可以将skynet理解为一个简单的操作系统,可以用来调度数千个lua虚拟机(进程),让他们并行工作。**每个lua虚拟机都可以接收其他虚拟机发送过来的消息,以及对其他虚拟机发送消息。

通信

skynetactor的运行和通信都通过消息来驱动:

  • 全局消息队列:存储有消息的actor消息队列指针
  • actor消息队列:存储专属actor的消息队列

如下图:

skynet_msg

工作流程:

  • 从全局消息队列中取出actor消息队列,(这一步需要加锁,采用自旋锁,尽可能不让worker线程休眠,榨干cpu
  • actor消息队列取出消息,并通过回调函数处理(消费actor中的消息);因此不用担心一个服务同时被多个线程处理,即单个服务的执行,不存在并发,也即线程安全
  • 如果actor消息队列还有消息,将actor消息队列放入全局消息队列的队尾,起到公平调度

消息生产方式主要为

  • actor之间通信产生;
  • 网络中产生
  • 定时器产生

消息的消费方式只有一种:,通过回调函数进行消费。

因为actor之间通信直接通过指针传递,因此服务间的通信非常高效

注意:actor之间发送消息是不需要唤醒worker条件变量的,因为actor之间发送消息,则至少有一个worker线程在工作。

skynet每个服务均有一个协程池lua服务收到消息时,会优先去池子里取一个协程出来,即,就视为收到一个消息,就创建一个协程吧

skynet中的线程

  • timer线程:运行定时器
  • socket线程,进行网络数据的收发
  • worker线程:负责对消息队列进行调度
  • monitor线程:用于检测节点内的消息是否堵住

线程创建

// skynet_start.c
// skynet启动是会创建以上四种线程
static void
start(int thread) {
 ...
 create_thread(&pid[0], thread_monitor, m);  // monitor线程
 create_thread(&pid[1], thread_timer, m);  // timer线程
 create_thread(&pid[2], thread_socket, m);  // socket线程
 // 根据权重创建worker线程
 static int weight[] = { 
  -1, -1, -1, -1, 0, 0, 0, 0,
  1, 1, 1, 1, 1, 1, 1, 1, 
  2, 2, 2, 2, 2, 2, 2, 2, 
  3, 3, 3, 3, 3, 3, 3, 3, };
 struct worker_parm wp[thread];
 for (i=0;i<thread;i++) {
  wp[i].m = m;
  wp[i].id = i;
  if (i < sizeof(weight)/sizeof(weight[0])) {
   wp[i].weight= weight[i];
  } else {
   wp[i].weight = 0;
  }
  create_thread(&pid[i+3], thread_worker, &wp[i]);
 }
}

线程间使用管道进行通信。其中socket线程worker线程通过pipe进行通信。

服务模块将数据,通过socket发送给客户端时,并非将数据写入消息队列,通过pipeworker线程发送给socket线程,并交由socket转发

skynet作为游戏服务器时,我们编写的不同的业务逻辑,独立运行在不同的上下文环境,并且能通过某种方式,相互协作,共同服务于玩家。

skynet 业务是由lua来开发,与底层沟通以及计算密集的都需要用c。

skynetepoll进行注册:connected, clients, listened, pipe读端worker线程往管道写端写数据,socket线程在管道读端读数据)

skynet中内存分配采用jemalloc

以上,是为一个初学者对skynet的理解。

参考

skynet Wiki:https://github.com/cloudwu/skynet/wiki

云风BLOG:https://blog.codingnow.com/2012/09/the_design_of_skynet.html

skynet源码欣赏:https://manistein.github.io/blog/post/server/skynet/skynet%E6%BA%90%E7%A0%81%E8%B5%8F%E6%9E%90/

Golang CSP:https://www.jianshu.com/p/36e246c6153d

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表