Treasure / skynet 服务器框架简介

Created Mon, 20 Jun 2022 00:00:00 +0000
1490 Words

工作中曾经开发了一个cobweb的分布式服务器框架(基于golang,c),但是在实际开发过程中代码难以维护以及更新,主要是每次都需要跨平台进行编译,特别是cgo 往往需要指定平台的系统库,而且一些不规范的使用方式造成无法充分发挥多核的优势,可以参见 关于Go协程的思考 虽然1.16 支持抢占式,但错误的使用方式依然造成了cpu过高的问题。,后续重新设计了skynet 是一个actor模型分布式服务框架,使用go编写。

尽管Actor模型和CSP模型各有所有长,为什么不采用CSP主要有以下方面考虑。

  1. CSP模式使用尽管很简单,但是一个致命的问题是无法控制消息的优先级,当然若只处理一个Channel那可以规避,那么为啥还需要使用CSP,而且像go channel 本身是基于互斥锁(1.16)实现,且无法进行优化和更加精细的控制,只能依赖于runtime的调度。(网上所说什么时候触发调度,我认为channel不能包含其中,它本质也是加锁导致切换)

  2. 隔离性太弱,后续一些新的channel引入也会造成破坏性修改。

  3. select-case模式会随着等待数量的增加性能会慢慢减弱。

  4. channel 多大合适?

它是一个年轻的框架,仅仅经历了两款项目的迭代 现在版本为 v1.6.0 2023-05-28 重启了 v2 版本

与skynet的差异

  1. 增加了独占进程的概念,对于一些性能敏感的服务可以绕过公平调度的原则。 (公平调度是一个很普遍但并非最优解的调度策略,但对于需要偏占资源较多的场景就显得无力)

  2. 使用协程而非线程,一个好处是对于一些假死服务我们可以重新启动它,其它代价远小于线程(尽管协程的开销很低,但我们尽量保证不会被滥用)

  3. 一个简单的二进制文件,skynet修改了lua部分虚拟机源码,而且大部分实现都是基于lua实现,而我设计的是一个将脚本语言作为可选项的插件。

  4. 所有库都是底层语言的实现方式,可控制力和性能更好,完全将业务和底层区分方便同时进行维护

  5. 无感的集群交互方式,调用其他服务(无论在不在本地)就像普通消息那样简单,不需要像skynet需要显示调用cluster

  6. 进程支持错误重启且消息不会丢失 (beta)

  7. 支持后续的DSL (鸽了两年,还是没写完~)

  8. 在2024/03我正计划重新用C实现了一版以提供更好的性能和更底层的控制

特性

  1. 支持纯Lua开发,方便更快的开发业务。

  2. mysql,redis client支持,值得注意的是这些库都是作为插件实现,跟主库关联不大,需要编译时指定tags

  3. native网络支持,对于golang的网络模型而言它不是一个高性能的解决方案,尤其是对大量长连接的情况,可参见golang的协程思考

  4. 内置集群组件 sktpmd,易于实现分布式

  5. 隐藏的数据编码,对业务不透明,提供比protobuf-v3 更快的编码 kproto

  6. 高性能,完全摒弃interface{}以及各种抽象,无任何类型断言,满足cache-line的结构设计

  7. 基于slab算法实现的无锁内存分配器zmalloc,比sync.Pool更快

优势

  • skynet 是过程式以及低抽象的架构。纯函数也更贴合职责单一的原则,也方便后续运行时替换,而低抽象是因为go interface 并非零成本抽象,它有一定的性能代价。所以整个skynet 没有任何接口定义。

  • skynet仅需要一个执行文件,大小仅仅5.78mb,默认运行内存仅仅 2.2mb

  • 65535 Lua服务仅占用1.8GB,也就是每个 Lua服务 仅占用 28.8kb

  • 65535 纯go服务仅占用120mb,每个pure go服务仅占用 1.9kb

  • 更快的zmalloc内存分配器

  • native网络支持,支持 windows,linux,macos,其他平台未测试。 (需要注意的是windows是一个残血版本,仅作为调试)

目录大纲

scheduler

eventbus

sktpmd

zmalloc