当前位置: 首页 > news >正文

skynet——服务发现学习

skynet创建一个新服务其他服务怎么知道他的地址并和他通信呢单进程本地服务管理localservice{}-- 存储所有注册的本地服务functioncmd.LAUNCH(service_name,subname,...)localrealnameread_name(service_name)returnwaitfor(service_name,skynet.newservice,realname,subname,...)endfunctioncmd.QUERY(service_name,subname)returnwaitfor(service_name)end这里service表维护了名字到句柄的映射。当服务启动时它会被注册到这个表中后续其他服务可以通过名字查询到对应的句柄。服务注册localfunctionglobalname(name,handle)localcstring.sub(name,1,1)assert(c~:)ifc.thenreturnfalseendassert(#name16)-- GLOBALNAME_LENGTH is 16, defined in skynet_harbor.hassert(tonumber(name)nil)-- global name cant be numberlocalharborrequireskynet.harborharbor.globalname(name,handle)returntrueendfunctionskynet.register(name)ifnotglobalname(name)thenc.command(REG,name)-- 调用C层注册endendfunctionskynet.name(name,handle)ifnotglobalname(name,handle)thenc.command(NAME,name.. ..skynet.address(handle))endendSkynet将服务名字分为两类——本地名字以.开头和全局名字不以.和:开头。本地名字通过C层的本地注册机制存储适合单进程内使用全局名字需要通过Harbor机制同步到其他节点。集群Cluster机制采用了去中心化的设计理念每个节点只需要配置其他节点的地址即可直接通信。名字服务注册--cluster.luafunctioncluster.register(name,addr)assert(type(name)string)assert(addrnilortype(addr)number)returnskynet.call(clusterd,lua,register,name,addr)endfunctioncluster.unregister(name)assert(type(name)string)returnskynet.call(clusterd,lua,unregister,name)end--clusterd.lualocalregister_name{}-- 本节点的名字注册表localnode_address{}-- 节点地址配置functioncommand.register(source,name,addr)assert(register_name[name]nil)addraddrorsourcelocalold_nameregister_name[addr]ifold_namethenregister_name[old_name]nilendregister_name[addr]name register_name[name]addr skynet.error(string.format(Register [%s] :%08x,name,addr))endfunctioncommand.queryname(source,name)skynet.ret(skynet.pack(register_name[name]))end跨节点地址发现Cluster 采用静态配置方式解决节点地址问题。每个节点在启动时读取配置文件-- clusterd.lua 第85-95行localfunctionloadconfig(tmp)iftmpnilthentmp{}ifconfig_namethen-- 从环境变量读取配置文件路径localfassert(io.open(config_name))localsourcef:read*af:close()assert(load(source,..config_name,t,tmp))()-- 执行配置文件endend-- ...forname,addressinpairs(tmp)doifname:sub(1,2)__then-- __开头的是特殊配置localoptname:sub(3)config[opt]addresselsenode_address[name]address-- name - IP:Port 映射endendend大致加载流程如下┌─────────────────────────────────────────────────────────────────┐ │ Node1 启动 │ ├─────────────────────────────────────────────────────────────────┤ │ skynet.init() │ │ ↓ │ │ clusterd 服务启动 │ │ ↓ │ │ loadconfig(cluster.conf) │ │ ↓ │ │ 加载配置: │ │ node_address { │ │ [node1] 127.0.0.1:7001, │ │ [node2] 127.0.0.1:7002, │ │ [node3] 192.168.1.100:7003, │ │ } │ └─────────────────────────────────────────────────────────────────┘完整服务调用流程┌─────────────────────────────────────────────────────────────────────────────┐ │ Cluster 服务调用完整流程 │ └─────────────────────────────────────────────────────────────────────────────┘ 1. 配置阶段启动时 ├── 所有节点加载 cluster.conf └── 每个节点知道所有其他节点的 IP:Port 2. 连接阶段首次通信时 ├── Node1 调用 cluster.call(node2, gate, open, ...) ├── 发现 sender[node2] nil ├── 创建 clustersender(node2) 服务 ├── clustersender 发起 TCP 连接到 127.0.0.1:7002 └── 保存 sender[node2] clustersender 3. 服务查询阶段 ├── 首次调用时通过 sender 发送名字查询 ├── Node2 的 clusterd 查询本地 register_name 表 └── 返回服务的内部句柄如 :00000005 4. 消息发送阶段 ├── 序列化请求skynet.pack ├── 通过 TCP 发送到 Node2 ├── Node2 的 clustersender 接收 ├── 转发给目标服务 :00000005 (gate) └── gate 处理请求并返回结果 5. 结果返回阶段 ├── gate 返回结果给 clustersender ├── clustersender 通过 TCP 发回 Node1 └── Node1 的调用协程被唤醒获取结果如何动态发现新增的服务结合cluster新增一个中继集群他负责维护全部服务的。┌─────────────────────────────────────────────────────────────────────────────┐ │ 中继集群架构图 │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Client A │ │ Client B │ │ Client C │ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ │ cluster.call │ │ │ │ └────────────────────┼────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ 中继集群 (Relay Cluster) │ │ │ │ ┌────────────────────────────────────────────────────────────┐ │ │ │ │ │ 服务注册表 (Registry) │ │ │ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ gate │ node1:001234 │ node2:005678 │ 3个 │ │ │ │ │ │ │ │ worker │ node1:003456 │ node2:007890 │ 5个 │ │ │ │ │ │ │ │ db_mgr │ node3:009ABC │ │ 1个 │ │ │ │ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ 负载均衡器 (Load Balancer) │ │ │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │ │ │Round │ │Least │ │Hash │ │Random │ │ │ │ │ │ │ │Robin │ │Load │ │ │ │ │ │ │ │ │ │ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │ │ │ │ └────────────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ cluster.call (转发) │ │ ┌────────────────────┼────────────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Node 1 │ │ Node 2 │ │ Node 3 │ │ │ │ │ │ │ │ │ │ │ │ gate │ │ gate │ │ db_mgr │ │ │ │ worker x 3 │ │ worker x 2 │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘设计方案┌─────────────────────────────────────────────────────────────────────────────┐ │ 服务同步模式对比 │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ 模式 │ 示意图 │ 特点 │ │ ───────────────────────────────────────────────────────────────────────── │ │ │ │ │ │ 集中式 │ ┌────────┐ │ 简单但中继节点压力大 │ │ (单中继) │ │ Master │ 所有注册 │ 单点风险 │ │ │ └───┬────┘ │ │ │ │ │ │ │ │ │ ┌────┴────┐ │ │ │ │ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ │ │ 节点1 节点2 节点3 │ │ │ │ │ │ │ ───────────────────────────────────────────────────────────────────────── │ │ │ │ │ │ 全复制 │ ┌────┐ ┌────┐ ┌────┐ │ 强一致性每个节点完整副本 │ │ (每个节点 │ │ 1 │ │ 2 │ │ 3 │ │ 但同步开销大 │ │ 完整副本) │ │全量│ │全量│ │全量│ │ │ │ │ └────┘ └────┘ └────┘ │ │ │ │ 同步──→同步──→同步 │ │ │ │ │ │ │ ───────────────────────────────────────────────────────────────────────── │ │ │ │ │ │ 分区 │ ┌────┐ ┌────┐ ┌────┐ │ 扩展性好负载分散 │ │ (按服务名 │ │ A │ │ B │ │ C │ │ 但查询复杂可能需要多跳 │ │ 分片) │ │-G │ │-W │ │-M │ │ │ │ │ └────┘ └────┘ └────┘ │ │ │ │ │ │ │ │ 节点1 节点2 节点3 │ │ │ │ │ │ │ ───────────────────────────────────────────────────────────────────────── │ │ │ │ │ │ Gossip │ ┌────┐ ┌────┐ ┌────┐ │ 最终一致适合大规模 │ │ (最终一致) │ │节点1│←→│节点2│←→│节点3│ │ 实现复杂有延迟 │ │ │ │ ↕ │ ↕ │ ↕ │ │ │ │ │ └────┘ └────┘ └────┘ │ │ │ │ 随机同步慢慢扩散 │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘
http://www.gsyq.cn/news/1400417.html

相关文章:

  • 腾讯元宝复制带符号文字怎么快速删改?手贱星人有救了!这款“AI导出鸭”气哭CTRL+C/V党
  • 用Unity和C#实现人群疏散模拟:手把手教你搭建社会力模型(附完整代码)
  • WSL2 吃掉我 25GB C 盘空间:一次完整的排查与回收记录
  • AI框架选型新指标:用行为承诺度量化项目健康度
  • UniApp 快速集成个推推送(UniPush2.0)完整实战教程
  • 谁在定义AI硬件的2026?
  • 告别命令行!ESP32-S3安全三件套(Flash加密+Secure Boot V2+NVS加密)的图形化工具配置避坑指南
  • 【Linux】Ext 系列文件系统
  • MTKClient 从入门到精通:联发科设备刷机与逆向工程完全指南
  • 新手避坑指南:在RHEL 6.10上安装Cadence IC618和Verdi 2018.09的完整流程(含依赖库检查)
  • 顺序统计量不等式:Bootstrap与保形预测的理论基石
  • 基于STCO框架构建类型安全提示工程,降低LLM幻觉率30%
  • 基于Whisper、Groq与Streamlit构建本地语音AI助手:从原理到实践
  • UVa 295 Fatman
  • 开发者如何克服完美主义陷阱,构建内在交付体系实现项目上线
  • 2026年5月北京十大装修公司排行榜推荐:十大专业公司评测夜间施工防噪音 - 品牌推荐
  • 为AI编码助手集成运行时日志:从日志采集到智能诊断的工程实践
  • 2026年Python学习指南:从零基础到实战项目,掌握核心语法与工具
  • 苏州可靠的宠物店怎么选 关键因素解析 - 品牌排行榜
  • Tomato-Novel-Downloader:三步构建你的个人小说图书馆
  • 深度解析:3步实现Wallpaper Engine资源逆向工程与高效提取
  • Linux系统重启后,Kubernetes集群核心服务kube-apiserver启动失败的排查与修复
  • 2026年4月国内比较好的AI无损测糖选果机品牌推荐,小柿子选果机/冬枣选果机,AI无损测糖选果机制造商哪家权威 - 品牌推荐师
  • EFM32开发板SWD通信故障排查与优化
  • Python循环不会写?for和while实战技巧大公开
  • 海外支付难的不是接渠道,而是让每一笔钱对得上
  • 告别命令行!用VSCode+PyQt5+QtDesigner,10分钟搞定你的第一个Python桌面应用
  • 突破《原神》60帧限制:安全高效的帧率解锁方案
  • LeetCode 10:正则表达式匹配 | 动态规划
  • Unity游戏配置表管理新思路:不写编辑器扩展,用ExcelDataReader+ScriptableObject实现数据热更新