skynet简单游戏服务器的迭代1

第一篇
第二篇

在前面两篇的基础框架上引入可供skynet服务间数据共享的库,灵感是之前用Erlang写游戏业务时候,经常会用到ets来存储共享数据。ets表 是 Erlang 提供的一种高效的数据存储机制,可以看作是一个键值存储,其中每个键可以唯一标识一个值,支持快速的访问和修改操作。

skynet本身也有提供了sharetable,sharedata等库可以操作共享数据,但是相比以往用Erlang的ets使用上会复杂一丢丢,当做学习和扩展,就封装一个简单的ets库,提供查询/插入/更新/删除/清表的几种操作,在不同服务间可共享和查询/更新,线程安全。

使用场景:

比如需要保存当前服所有在线玩家信息,每个玩家信息包含玩家id,玩家服务进程addr,登录时间三部分。那就需要一张表名online_users的表来保存信息列表,而保存的信息列表中,key就是玩家id,val则是{id = 玩家id, addr = 玩家服务进程, login_time = 登录时间}

代码示例:

A服务初始化和插入 (初始化只需要任意一个服务初始化一次即可)

local ets = require "db.ets"
--初始化表
ets.init("online_users")
--插入数据
local res = ets.insert("online_users", 玩家id(1001), {id = 玩家id, addr = 玩家服务进程1, login_time = 登录时间})
assert(res, "insert fail")
--更新数据
local res = ets.insert("online_users", 玩家id(1001), {id = 玩家id, addr = 玩家服务进程2, login_time = 登录时间})
assert(res, "update fail")
--查询数据
local res = ets.lookup("online_users", 玩家id(1001))
assert(res, "is nil")
print(res.id, res.addr, res.login_time)
--查询表所有数据
local res = ets.lookup_all("online_users")
for k, v in pairs(res) do
    print(v.id, v.addr, v.login_time)
end
--删除数据
local res = ets.delete("online_users", 玩家id(1001))
assert(res, "delete fail")
--清表
local res = ets.delete_all("online_users")
assert(res, "delete_all fail")

B服务直接查询和修改

local ets = require "db.ets"
--查询A数据插入的数据
local res = ets.lookup("online_users", 玩家id(1001))
assert(res, "is nil")
print(res.id, res.addr, res.login_time)

支持val的多层table嵌套

ets.insert("xx", 100304, {id = 100304, score_list = {math = 100, englist = 98, 
chemistry = 60}, other = {1, 2, 3}})

实现原理:

哈希表链表 搭配使用,源码在工程目录的lualib-srclua-etscache.c
ets表的键值数据用哈希表HashTable保存, 而当值为table的情况下则用链表形式保存HashNode->next_node

  1. 每个表用单独的哈希表保存;
typedef struct HashTable{
    char* name;                     //表名
    int capacity;                   //表容量,默认4096
    int size;                       //当前容量
    HashNode** table;               //哈希表
    pthread_mutex_t lock;           //锁
    struct HashTable * next;        //hash冲突的链表
}HashTable;
  1. 每个数据用单独节点保存,节点中包含数据,以及指向下一个节点的指针;
typedef struct{
    char* key;                      //key
    ValueType val_type;             //val数据类型
    Value val;                      //val数据
    struct HashNode * next;         //hash冲突的链表
    struct HashNode * next_node;    //val数据为table时, val.table_value使用链表
}HashNode;
  1. 节点的key目前只支持string和integer(integer插入时会转换成string,用来换算hash,查询时候再转换回integer返回);而val通过union支持不同类型,目前只支持integer,string和table三种数据类型,其中table用链表保存。
// 标识不同数据类型
typedef enum {
    TYPE_TABLE,
    TYPE_INT,
    TYPE_STRING
} ValueType;

// 存储不同类型的数据
typedef union {
    struct HashNode *table_value;      //存放table
    long int_value;
    char* string_value;
} Value;

性能:

浅浅在lua端调用压测了下,100w的插入耗时0.9s,100w的查询耗时0.3s.

额外:

简单练手的封装,一起学习用,可能运行有各种潜在问题或者报错,代码也写得粗暴和没在意细节,有问题的话请见谅或反馈

05-16
### 关于 Skynet Framework 的概述 Skynet 是一个高性能的分布式计算框架,最初由腾讯开发并开源。它主要用于构建大规模的游戏服务器其他高并发应用场景[^4]。该框架的核心设计理念是通过消息传递机制实现高效的进程间通信(IPC),从而支持分布式的任务调度服务管理。 #### 主要特性 - **轻量级架构**:Skynet 提供了一种基于 Lua 脚本语言的轻量化服务模型,开发者可以快速搭建复杂的业务逻辑。 - **高效的消息处理能力**:利用 C 实现底层性能优化的同时,允许上层应用采用易于维护的脚本语言编写业务逻辑[^5]。 - **灵活的服务扩展性**:支持动态加载模块以及跨节点之间的无缝协作,使得整个系统具备良好的可伸缩性鲁棒性。 以下是使用 Skynet 创建简单服务的一个基本例子: ```lua local skynet = require "skynet" function response.hello() return "world" end skynet.start(function() skynet.dispatch("lua", function(_, address, cmd, ...) local f = response[cmd] if f then skynet.ret(skynet.pack(f(...))) else error(string.format("Unknown command %s", tostring(cmd))) end end) end) ``` 此代码片段展示了如何定义一个简单的 `hello` 命令处理器,并将其注册到 Skynet 中以便其他组件调用[^6]。 --- ### 与其他系统的对比分析 尽管 SkyWalking Skynet 都属于分布式环境下的工具集,但它们的应用场景存在显著差异。SkyWalking 更侧重于追踪、监控诊断微服务架构中的运行状态;而 Skynet 则专注于提供低延迟、高吞吐量的基础平台来支撑实时交互型应用程序的发展需求[^7]。 对于硬件层面的支持情况,在某些特定条件下两者也可能有所交集——比如当涉及到嵌入式设备上的资源利用率监测或者远程调试功能时。不过总体而言,这些方面并不是 Skynet 的核心竞争力所在[^8]。 --- ### 开发者社区与生态建设 得益于其简洁的设计哲学以及活跃的贡献群体,围绕着 Skynet 已经形成了较为成熟的生态系统。除了官方文档外,还有许多第三方插件可供选用,进一步增强了它的适应范围技术优势[^9]。 例如,“thirdparty_intro”仓库中列举了一些辅助性的库文件链接地址,可以帮助用户更方便地集成额外的功能模块至自己的项目当中去[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值