Treasure / scheduler

Created Fri, 22 Jul 2022 00:00:00 +0000
1195 Words

简介

skynet 实现了一套调度器机制,用以调度 process, 与云风大佬不同的是,sched 支持公平模式以及独占模式,独占模式主要是为了解决特性场景下业务的响应速度,从而提升体验感, 其次,不一定需要按照每个 process 对应一条协程,减少runtime调度以及内存的开销

Sched

一个伪线程的逻辑处理器概念,它分为独占和负载两种模式。

  • 独占是为了更好的处理实时性更高的业务,它不会被其他任务抢占

  • 负载又可分为两种运行态,均匀的处理业务以及从其他process上偷窃任务,尽量保证Processor不会过于闲置,除此之外,负载Processor可随着任务的变动而增加(不会超过最大设定值),特别的当某个任务陷入”死循环”或者是超出设定运行阈值的时候会重新创建一个Processor`,并让之前的挂起(在C版本中将会被强制关闭)。

  • 多数时候协程过多会造成系统压力。

C版本和Go版本调度和设计上差异不大,但一些细节上的处理可能不同,因为C可以提供更多的底层控制

Process

process 是一种用户态的伪概念,用于描述一个 actor的具体实现方式,也是 skynet最小调度单元,这种概念对于分布式而言更友好,无关乎process在哪,只需要知道 PID 或者 Alias 即可向其投送消息。 主要是对业务几乎无侵入

Message

messageskynet 基础消息承载结构

服务的消息队列

Actor 模型最重要的的概念是 mailbox,它代表了一个实体需要处理的队列容器,

得益于go的简单性,可以使用 channel 来实现,但这种方式的实现性能不高,因为 channel 底层的结构使用的是互斥锁,

所以我采用了mpsc 实现了无锁队列,性能更优于 channel

TODO: 吞吐量对比

消息的接受和发送

  • 发送

用户不需要构建这个结构体,仅仅需要指定 dest 以及需要发送的数据,而且 skynet 消息投递被设计成不允许发送 nil 因为这是无任何意义的,相反它还会消耗服务投递的性能,如果确实有这种需求,可以发送 struct{}{}

至于这个节点是再本地,还是其他地方并不重要

  • 接收

接受回调只包含5个关键参数 context,addr,session,mtype,msg,size

  • context 其实就是创建process指定的结构指针,用于表示处理上下文

  • addr 即为投递者的Pid,(需要注意的是,skynet支持redirect 以及 fake模式,所以这地址需要在发送的时候明确)

  • session 主要的作用是用以区分这条消息是否是同步请求, 如若大于0,则其值就是请求序列号,只需要通过 skynet.ret(msg) 返回即可

  • mtype 仅仅是一个消息类别的区分,类似于消息号,用户可自行定义,可作为rpc消息类型

  • argument 才是真实的数据,它可以是任意值,特别的,在lua中这个值是会被解构,在跨节点通讯这个值恒为 []byte当不需要时记得 skynet.free 1.4.0 这个由底层回收,用户不用关心

异步消息

异步消息通过 skynet.send的方式进行投递,它只在乎这个消息有没有正确投递出去,而不关心是否能被对点服务正确处理

由于是基于mailbox 所有消息都是异步处理的,意味着时延性平均略高于同步

同步消息

说是同步消息 其实本质上还是异步,这个不属于skynet的底层内容而是在上层基于业务需求而封装的 同步