IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:skynet

共 9 篇相关文章

IT 累计浏览 36

Skynet 升级到 Lua 5.5.0

Skynet 随 Lua 5.5.0 正式发布完成了版本升级。Skynet 维护的定制版 Lua 核心特性是允许跨虚拟机共享函数原型,以此节省服务初始化时间和内存。实现此功能的关键难点在于正确处理短字符串内部化(interning)与外部导入原型中字符串的共存问题,该问题通过专门的补丁解决,副产品是支持了跨虚拟机共享只读常量表(可通过 skynet.sharetable 使用)。然而,鉴于 Lua 5.5 引入的 external strings 特性已大幅提升字节码加载速度,建议新项目避免依赖该补丁功能,以降低维护成本。 Lua 5.5 基本兼容 5.4,大多数 Skynet 项目无需大改,但升级后务必充分测试,并使用 `make cleanall` 强制重新编译 Lua。此次升级带来了多项有益改进:新增 `global` 关键字有助于减少拼写错误;分代垃圾回收(GC)改为步进式执行,解决了过去处理大内存服务时的停顿问题;新的不定长参数语法 `...args` 允许以表格形式访问参数,能简化部分代码实现。

IT 累计浏览 1,566

代理服务和过载保护

这篇讲的是如何在skynet框架中,通过前置代理服务来解决热点服务的过载问题。作者指出,服务过载是并发环境下最常见也最棘手的问题之一,而代理服务能在不增加功能服务复杂度的前提下,提供有效的保护。 核心方案是为热点服务增加一个代理层。这个代理可以智能地调度请求:当检测到某服务请求过于频繁时,会优先处理其他请求以保证公平;同时能自动丢弃那些来自已退出服务的无效请求。更重要的是,它能感知后端功能服务的负载情况,当服务过忙时缓存新请求。这带来一个实际好处:线上排障时,通过调试控制台直接发送的控制指令能绕过拥堵的请求队列,得到更快的响应。 文章不仅给出了概念,还深入了实现细节。作者展示了如何利用 `skynet.forward_type` 编写高效的代理服务,通过直接传递消息指针来避免不必要的内存拷贝。此外,还介绍了两种关键的运维能力:如何通过 `debug ping` 协议快速检测目标服务的响应延迟以判断是否过载,以及如何利用 `debug link` 指令来感知服务退出,从而清理无效请求。整套方案从架构设计到代码实现,为处理并发环境下的服务保护问题提供了清晰的思路。

IT 累计浏览 1,743

skynet 里的 coroutine

这篇讲的是 Skynet 框架如何利用 Lua 协程,将基于回调的消息处理模型,巧妙地转换为开发者更熟悉的阻塞式 RPC 调用风格。 Skynet 本身是一个消息分发器,每个服务通过一个统一的回调函数处理消息。这种异步模型虽然高效,但写起来可能不够直观。文章深入剖析了框架内部的核心技巧:为每条进入的消息创建一个协程,并让消息处理函数运行在其中。当遇到如网络请求等需要阻塞的操作时,处理函数会通过 coroutine.yield 将控制权交还框架,并附带操作类型(如“CALL”)和会话ID。框架挂起该协程,等待结果消息到达后,再根据会话ID找到并恢复对应的协程继续执行。 文章还进一步探讨了更高级的场景:如果开发者想在消息处理中自己使用协程怎么办?此时,用户协程的 yield 会被自己的 resume 捕获,导致 Skynet 的阻塞 API 失效。为此,框架提供了 skynet.coroutine 库。它在用户 yield 的类型前加上一个“USER”标记,从而与框架的内部 yield 区分开来,确保两者能协同工作而不冲突。 作者最后分享了使用协程作为迭代器的实际案例:处理一个巨大的内存操作日志文件时,通过协程实现了流式读取和转换,避免了内存溢出,展示了这一机制在实际工程中的实用价值。

IT 累计浏览 1,842

对象到数字 ID 的映射

这篇讲的是如何用一个高效的数据结构,为对象分配并管理短生命周期的数字 ID。 在像 skynet 这样的并行系统中,直接使用 C 指针来标识服务对象是危险的,容易引发悬垂指针、误释放等问题。因此,通常会用数字 ID 来间接引用。作者提出了一个具体的需求:既要快速映射,又希望尽量不复用已释放的 ID(避免误用),这与操作系统常见的文件句柄复用策略不同。 为了满足这个需求,核心方案是设计一张专门的哈希表。每次分配新 ID 时,在上次值的基础上递增,并检查哈希表中对应位置是否冲突,若冲突则继续递增。这保证了 key 永不冲突,让查询速度最快,且实现相对简洁。 更进一步,作者将这部分实现从 skynet 中抽离出来,做成了一个独立的开源库。文章详细介绍了其提供的 5 个 API(创建、销毁、分配、抓取、释放),并重点说明了为实现线程安全而采用的读写锁策略:对表的修改加写锁,而对 ID 的抓取和释放操作则加读锁,允许并发。这份实现还适配了 Windows 的原子操作。 整体上,这是一个解决特定工程问题的精巧数据结构,其实现思路(如不复用 ID 的哈希策略、引用计数与读写锁结合)对需要管理对象生命周期的系统设计很有参考价值。

IT 累计浏览 1,825

为什么 skynet 提供的包协议只用 2 个字节表示包长度

这篇讲的是 skynet 框架中一个经典设计决策:为什么它的 netpack 库坚持使用 2 字节(最大 64KB)来表示 TCP 数据包长度,而不是更“灵活”的 4 字节。 作者从游戏客户端网络通信的实际场景出发,解释了这并非简单的技术限制,而是一种有意的引导。核心原因在于,在单个 TCP 连接中允许过大的数据包(比如 100KB)是一个糟糕的设计。这会在弱网环境下长时间阻塞整个通信信道,连带心跳包等需要及时响应的小数据包也被延迟,严重影响实时性。更进一步,4 字节的长度头还存在被恶意攻击耗尽服务器内存的安全风险。 因此,作者主张正确的做法不是放宽包长度限制,而是在“长度+内容”协议之上增加一层,将大数据块分片传输。这个设计看似“绕”,但它强制开发者去思考和解决数据传输的阻塞问题,最终能实现单个 TCP 连接承载多个逻辑信道的能力,比如区分高优先级的心跳/关键指令和低优先级的聊天信息或大文件分片。 所以,skynet 这个看似限制性的选择,其实是在用简洁的接口引导使用者构建更健壮、响应更及时的网络架构。

IT 累计浏览 4,006

一个 Lua 内存泄露检查工具

这篇讲的是作者团队遇到服务器内存一夜暴增8G的紧急情况,通过快速自制的Lua内存快照工具定位泄露的故事。 问题出在一张地图的Lua State中,有对象持续生成却未释放引用。作者懒得搜索现有工具,自己用半天时间写了一个名为“snapshot”的开源库。它的巧妙之处在于:不对整个Lua State序列化,而是只记录table、thread等复杂对象间的引用关系,并且用C直接调用API遍历,避免了用Lua实现时“观察即改变”的干扰。 核心方法是对比两个时间点的快照,新增的内存和其引用链一目了然。工具返回的虽然是一堆指针和字符串,但足够定位到具体是哪行代码的哪个变量导致了泄露,比如示例中清晰地指向了dump.lua第7行的tmp和S1变量。 这个临时工具已经成功帮他们快速锁定了故障点,展示了在紧急问题下“轮子虽小但能快速解决问题”的实用主义思路。

IT 累计浏览 2,861

记录一个并发引起的 bug

这篇讲的是作者在Skynet项目中遇到的一个由多线程并发引发的消息处理bug。作者坦言,完全把多线程程序写对是一件非常困难的事,而这次经历让他再次深刻体会到了这一点。文章并没有深入探讨具体的修复细节,而是聚焦于问题的发现与记录本身。 作者从实际开发中遇到的挑战出发,记录下了这个由并发导致的典型问题。这不仅仅是一个技术故障的报告,更像是一份开发者笔记,反映了多线程编程中那些容易遗漏的陷阱和调试的复杂性。字里行间透露出的经验之谈,对于同样在并发领域摸索的开发者而言,或许能带来一些共鸣与提醒——即便是经验丰富的开发者,也需要时刻对并发问题保持警惕。

IT 累计浏览 2,111

Skynet 的一些改进和进展

作者近期将重心完全放到了Skynet框架的开发与演进上。作为一款轻量级、高并发的游戏服务器框架,Skynet的持续改进一直是社区关注的焦点。 这篇内容并非泛泛而谈,而是聚焦于框架在实际迭代中发生的数项具体改进。作者从近期的工作出发,分享了在多个方向上的进展,其中既可能包含对核心调度模型的优化,也可能涉及关键模块的功能增强与性能提升。文章以第一手的开发视角,阐述了为何要做这些改动、设计思路如何,以及改进后的初步效果,为理解框架的演进脉络提供了直接线索。 对于关注游戏服务器与高并发系统架构的读者而言,这篇分享提供了宝贵的工程实践参考,展示了如何在一个成熟的开源框架上进行持续优化。

IT 累计浏览 2,831

Skynet 集群及 RPC

这篇讲的是作者在游戏服务器框架 Skynet 上进行的一次实战开发。他将前几天因会议而拖慢的进度赶了回来,最终完成了集群模块与 RPC 协议的设计与实现。 Skynet 本身以轻量和高性能著称,但其原生设计更偏向单机。作者这次的工作,正是为了解决分布式环境下的节点通信问题。他分享了从零开始,在 Skynet 架构中融入网络集群与远程过程调用(RPC)的关键步骤,这涉及到底层协议的封装与上层服务调用逻辑的整合。 对于关注服务器架构的开发者而言,这篇文章的价值在于呈现了一个具体的“从点到面”的扩展过程:如何让一个成熟的单机框架,通过模块化的设计,具备支撑起分布式集群的能力。作者没有停留在理论阐述,而是结合了实际编码中的取舍与思考,这对于需要处理类似技术挑战的读者,会是一份详实的参考。