Skip to content

huahua132/skynet_fly

Folders and files

NameName
Last commit message
Last commit date
Dec 12, 2024
Mar 6, 2025
Nov 18, 2024
Nov 16, 2024
Oct 25, 2024
Apr 3, 2025
Nov 30, 2024
Apr 3, 2025
Apr 3, 2025
Apr 1, 2025
Apr 3, 2025
Mar 6, 2025
Apr 1, 2025
Dec 2, 2024
Sep 25, 2024
Nov 21, 2024
Oct 25, 2023
Dec 3, 2024
Nov 20, 2024
Jan 4, 2024
Dec 27, 2023
Sep 28, 2024
Mar 6, 2025
Jan 4, 2024
Nov 21, 2024
Jan 19, 2025
Nov 12, 2024

Repository files navigation

skynet_fly(1)


致力于服务端对skynet的最佳实践 使用文档

觉得不错,不妨点个**星星**吧!你的星星是作者持续创作维护的最大动力!

技术交流群

QQ群号:102993581

windows 编译

参考 https://github.com/cloudfreexiao/pluto

基于 Visual Studio 2022 需要安装 CMake 和 Clang 模块.

openssl 链接出错

下载链接 请自行下载 openssl 对应系统版本, 替换win3rd/include 和win3rd/lib,lib使用MT的。

skynet_fly简介

skynet_fly是基于skynet扩展的可以快速开发web,游戏,和需要rpc调用的框架。
使用skynet_fly的好处:
* 支持不停服更新。
* 一键生成skynet的配置文件和skynet_fly的配置文件以及配套shell脚本。
* 对匹配房间类游戏做了gate,ws_gate的基础设施封装以及pb,json,sproto协议的支持,开发游戏只需要实现相关业务逻辑。
* 对redis,mysql,timer,log 使用封装。
* 支持远程rpc调用、远程sub/pub、远程subsyn/pubsyn。
* 支持服务发现。
* 支持http服务长连接。
* 支持http服务路由,中间件模式。
* 支持jwt鉴权。
* 内置日志分割。
* 支持快进时间。
* 支持orm(数据关系映射)目前适配了(mysql,mongo),数据库可无缝切换。
* 支持断点调试。
* 支持lua代码加密。
* 支持服务录像、录像重放。

第三方依赖来源

编译(请勿在共享的window文件夹下执行install,编译perl通常会失败)

编译skynet 参考了涵曦的 skynet_demo - git clone https://github.com/huahua132/skynet_fly - 根据系统安装一些依赖sh install_centos.sh 或者 sh install_ubuntu - 在skynet_fly目录下 make linux

快速开始 简单可热更服务 (运行examples/AB_question)

  • 构建服务

    • cd examples/AB_question/
    • sh ../../binshell/make_server.sh ../../
  • 运行服务 sh make/script/run.sh load_mods.lua 0

这个简单的示例是A服务B服务发送hello消息,得到回应后打印。

A服务消息发送内容

function CMD.send_msg_to_b()
    for i = 1,4 do
		--简单轮询负载均衡 (假如B有2个服务B_1,B_2 用balance_call调用2次,将分别调用到B1,B2)
        local ret = contriner_client:instance("B_m"):balance_call("hello")                  
        log.info("balance_call send_msg_to_b:", i, ret)
        --对应send发送方式 balance_send
    end
    for i = 1,4 do
		--模除映射方式  (用1模除以B_m的服务数量从而达到映射发送到固定服务的目的,不调用set_mod_num指定mod时,mod默认等于skynet.self())
        local ret = contriner_client:instance("B_m"):set_mod_num(1):mod_call("hello")
        log.info("mod_call send_msg_to_b:", i, ret)
        --对应send发送方式 mod_send
    end
	--给B_m所有服务发
    local ret = contriner_client:instance("B_m"):broadcast_call("hello")
    log.info("broadcast_call:", ret)
    --对应send发送方式 broadcast

    --by_name方式   相当于提供子名字,有时候相同的服务可能会划分不同的职责,比如一个游戏可能分为A玩法,B玩法。
	--大体逻辑相同,只有很小的区别,这时候可以用子名字,而不用再写一个可热更服务模块了。
    --by_name方式调用我们必须指定`instance_name`,调用API都是在后面加了_by_name

    for i = 1,4 do
		--简单轮询负载均衡 (假如B有2个服务B_1,B_2 用balance_call调用2次,将分别调用到B1,B2)会排除非test_one的服务。
        local ret = contriner_client:instance("B_m", "test_one"):balance_call_by_name("hello")  
        log.info("balance_call_by_name send_msg_to_b test_one:", i, ret)
        --对应send发送方式 balance_send_by_name
    end

    for i = 1,4 do
		--模除映射方式  (用1模除一B_m的服务数量从而达到映射发送到固定服务的目的,不用set_mod_num指定mod,mod默认等于skynet.self())
        local ret = contriner_client:instance("B_m", "test_two"):set_mod_num(1):mod_call_by_name("hello")       
        log.info("mod_call_by_name send_msg_to_b test_two:", i, ret)
        --对应send发送方式 mod_send_by_name
    end

	--给B_m 子名字为test_two所有服务发
    local ret = contriner_client:instance("B_m", "test_two"):broadcast_call_by_name("hello")                    
    log.info("broadcast_by_name:", ret)
    --对应dend发送方式 broadcast_by_name
end

B服务

function CMD.hello()
    return "HEELO A I am is " .. skynet.address(skynet.self())
end

执行结果解析

balance_call 调用4次分别发给了服务地址为:0000000f,:00000010,:00000011,:00000012 mod_call 调用4次一直发给服务地址为:00000010 broadcast_call 调用发给了所有B_m服务。 balance_call_by_name 调用四次轮询发给了:0000000f,:00000010,因为:00000011,:00000012子名字是test_two所以排除了。 mod_call_by_name 调用四次一直发给了:00000012(B_m子名字为test_two中的一个)。 broadcast_call_by_name 调用发给了所有B_m子名字为test_two的服务中。

[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:49]"balance_call send_msg_to_b:" 1 "HEELO A I am is :0000000f"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:49]"balance_call send_msg_to_b:" 2 "HEELO A I am is :00000010"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:49]"balance_call send_msg_to_b:" 3 "HEELO A I am is :00000011"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:49]"balance_call send_msg_to_b:" 4 "HEELO A I am is :00000012"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:54]"mod_call send_msg_to_b:" 1 "HEELO A I am is :00000010"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:54]"mod_call send_msg_to_b:" 2 "HEELO A I am is :00000010"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:54]"mod_call send_msg_to_b:" 3 "HEELO A I am is :00000010"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:54]"mod_call send_msg_to_b:" 4 "HEELO A I am is :00000010"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:59]"broadcast_call:" {
        [15] =  {
                [1] = "HEELO A I am is :0000000f",
        }
        [16] =  {
                [1] = "HEELO A I am is :00000010",
        }
        [17] =  {
                [1] = "HEELO A I am is :00000011",
        }
        [18] =  {
                [1] = "HEELO A I am is :00000012",
        }
}

[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:67]"balance_call_by_name send_msg_to_b test_one:" 1 "HEELO A I am is :0000000f"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:67]"balance_call_by_name send_msg_to_b test_one:" 2 "HEELO A I am is :00000010"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:67]"balance_call_by_name send_msg_to_b test_one:" 3 "HEELO A I am is :0000000f"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:67]"balance_call_by_name send_msg_to_b test_one:" 4 "HEELO A I am is :00000010"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:73]"mod_call_by_name send_msg_to_b test_two:" 1 "HEELO A I am is :00000012"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:73]"mod_call_by_name send_msg_to_b test_two:" 2 "HEELO A I am is :00000012"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:73]"mod_call_by_name send_msg_to_b test_two:" 3 "HEELO A I am is :00000012"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:73]"mod_call_by_name send_msg_to_b test_two:" 4 "HEELO A I am is :00000012"
[:0000000e][20240523 17:12:01 70][info][A_m][./module/A_m.lua:78]"broadcast_call_by_name:" {
        [17] =  {
                [1] = "HEELO A I am is :00000011",
        }
        [18] =  {
                [1] = "HEELO A I am is :00000012",
        }
}

热更

B_m.lua随意加个空格,再执行sh make/script/check_reload.sh load_mods.lua,此时会热更B_m服务,旧的B_m服务将被通知到可以退出了。 旧的B_m将会十分钟检查一次,直到没有访问者,CMD.check_exit()也是同意退出的,再调用CMD.exit(),如果返回true,服务将会在十分钟后调用skynet.exit() 而A服务将会切换访问到新启动的B_m服务。

function CMD.check_exit()
    log.error("检查退出")
    return true
end

function CMD.exit()
    log.error("退出")
    return true
end

结果解析

可以看到热更后访问的服务地址都已经改变了。

[:0000000f][20240523 17:14:41 89][error][B_m][./module/B_m.lua:14]"预告退出"
[:00000010][20240523 17:14:41 89][error][B_m][./module/B_m.lua:14]"预告退出"
[:00000011][20240523 17:14:41 89][error][B_m][./module/B_m.lua:14]"预告退出"
[:00000012][20240523 17:14:41 89][error][B_m][./module/B_m.lua:14]"预告退出"
[:00000013][20240523 17:14:41 89]LAUNCH snlua hot_container B_m 1 2024-05-23[17:14:41] 1716455681 2
[:00000014][20240523 17:14:41 90]LAUNCH snlua hot_container B_m 2 2024-05-23[17:14:41] 1716455681 2
[:00000015][20240523 17:14:41 90]LAUNCH snlua hot_container B_m 3 2024-05-23[17:14:41] 1716455681 2
[:00000016][20240523 17:14:41 91]LAUNCH snlua hot_container B_m 4 2024-05-23[17:14:41] 1716455681 2
[:0000000f][20240523 17:14:41 91][error][B_m][./module/B_m.lua:23]"确认要退出"
[:00000010][20240523 17:14:41 91][error][B_m][./module/B_m.lua:23]"确认要退出"
[:00000011][20240523 17:14:41 91][error][B_m][./module/B_m.lua:23]"确认要退出"
[:0000000e][20240523 17:14:41 91][info][A_m][./module/A_m.lua:14]"updated B_m"
[:00000012][20240523 17:14:41 91][error][B_m][./module/B_m.lua:23]"确认要退出"
[:0000000d][20240523 17:14:41 91]127.0.0.1:34774 disconnect
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:49]"balance_call send_msg_to_b:" 1 "HEELO A I am is :00000013"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:49]"balance_call send_msg_to_b:" 2 "HEELO A I am is :00000014"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:49]"balance_call send_msg_to_b:" 3 "HEELO A I am is :00000015"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:49]"balance_call send_msg_to_b:" 4 "HEELO A I am is :00000016"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:54]"mod_call send_msg_to_b:" 1 "HEELO A I am is :00000014"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:54]"mod_call send_msg_to_b:" 2 "HEELO A I am is :00000014"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:54]"mod_call send_msg_to_b:" 3 "HEELO A I am is :00000014"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:54]"mod_call send_msg_to_b:" 4 "HEELO A I am is :00000014"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:59]"broadcast_call:" {
        [21] =  {
                [1] = "HEELO A I am is :00000015",
        }
        [19] =  {
                [1] = "HEELO A I am is :00000013",
        }
        [20] =  {
                [1] = "HEELO A I am is :00000014",
        }
        [22] =  {
                [1] = "HEELO A I am is :00000016",
        }
}

[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:67]"balance_call_by_name send_msg_to_b test_one:" 1 "HEELO A I am is :00000013"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:67]"balance_call_by_name send_msg_to_b test_one:" 2 "HEELO A I am is :00000014"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:67]"balance_call_by_name send_msg_to_b test_one:" 3 "HEELO A I am is :00000013"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:67]"balance_call_by_name send_msg_to_b test_one:" 4 "HEELO A I am is :00000014"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:73]"mod_call_by_name send_msg_to_b test_two:" 1 "HEELO A I am is :00000016"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:73]"mod_call_by_name send_msg_to_b test_two:" 2 "HEELO A I am is :00000016"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:73]"mod_call_by_name send_msg_to_b test_two:" 3 "HEELO A I am is :00000016"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:73]"mod_call_by_name send_msg_to_b test_two:" 4 "HEELO A I am is :00000016"
[:0000000e][20240523 17:14:42 85][info][A_m][./module/A_m.lua:78]"broadcast_call_by_name:" {
        [21] =  {
                [1] = "HEELO A I am is :00000015",
        }
        [22] =  {
                [1] = "HEELO A I am is :00000016",
        }
}

加速时间

由于我们想测试旧服务退出,又不想改代码,又不想等太久,我们可以利用加速时间的方式来做到。 首先通过debug_console调用gc 快速消除对旧服务地址的引用。 nc 127.0.0.1 8888 gc gc

然后调用快进时间快进1个小时 sh make/script/fasttime.sh load_mods.lua '2023:05:23 18:00:00' 1 然后在用debug_console看看还有哪些服务在 nc 127.0.0.1 8888 mem

:00000004       115.50 Kb (snlua cdummy)
:00000006       107.77 Kb (snlua datacenterd)
:00000007       135.83 Kb (snlua service_mgr)
:00000008       109.16 Kb (snlua service_provider)
:00000009       107.21 Kb (snlua service_cell ltls_holder)
:0000000b       121.97 Kb (snlua monitor_exit)
:0000000c       138.60 Kb (snlua contriner_mgr)
:0000000d       219.57 Kb (snlua debug_console 8888)
:0000000e       254.48 Kb (snlua hot_container A_m 1 2024-05-23[17:14:09] 1716455649 1)
:00000013       201.17 Kb (snlua hot_container B_m 1 2024-05-23[17:14:41] 1716455681 2)
:00000014       192.19 Kb (snlua hot_container B_m 2 2024-05-23[17:14:41] 1716455681 2)
:00000015       186.07 Kb (snlua hot_container B_m 3 2024-05-23[17:14:41] 1716455681 2)
:00000016       177.21 Kb (snlua hot_container B_m 4 2024-05-23[17:14:41] 1716455681 2)

可以看到,只存在版本二的B_m服务了。

快速开始 房间类游戏服务 (运行examples/digitalbomb)

  • 构建服务

    • cd examples/digitalbomb/
    • sh ../../binshell/make_server.sh ../../
  • 运行服务 sh make/script/run.sh load_mods.lua 0

基于tcp长连接实现不停服更新 digitalbomb 数字炸弹游戏。 除了登录 login 服不能热更。 hall 大厅服。 alloc 分配服。 table 桌子服都是可行的。 内置了客户端,可以直接看到效果。

  • 业务解耦登录大厅匹配游戏,还有协议都完成了解耦,开发新游戏只需要实现对应的插件接口即可。

  • 热更新 client_m 表写了测试用例,可以用来验证热更新。 也可以通过make/script/check_reload.sh的方式,不过你先修改好文件,然后开始执行。

  • 游戏热更新原理 新服替换旧服务的方案。 旧连接跟旧服务通信。 新连接跟新服务通信。 适合用于玩一把游戏就退出的微服务架构。

快速开始 http服务 (运行examples/webapp)

  1. 构建skynet_config, webapp运维脚本
    • cd examples/webapp/
    • sh ../../binshell/make_server.sh ../../
    • 如果一些顺利的话将会生成make/script文件夹,文件夹下有:
      • run.sh 运行并配置日志分割
      • stop.sh 停止
      • restart.sh 重启
      • reload.sh 热更某个可热更模块。
      • kill_mod.sh 干掉某个可热更模块(不是强行kill,是通知服务可以退出了)
      • check_reload.sh 检测可热更模块是否有文件或者配置修改,有就更新。
      • fasttime.sh 快进时间。 sh make/script/fasttime.sh load_mods.lua "2023:11:19 11:10:59" 1
      • try_again_reload.sh 当热更失败,可以解决相关错误之后进行重试热更。
      • check_hotfix.sh 检测刷热更脚本。
      • hotfix.sh 刷热更脚本。
    • 还会生成webapp_config.lua,也就是skynet启动用的配置文件。
  2. 运行
    • sh make/script/run.sh load_mods.lua 0
    • load_mods.lua是指启动用的配置文件。
    • 0表示不用后台运行。不传就是后台运行。sh make/script/run.sh load_mods.lua
    • 后台运行,日志会写入log文件。
  3. 访问
    • 浏览器打开 x.x.x.x:8688
    • 如果一切顺利的话,网页将会显示内容。
  4. 热更
    • 修改 webapp/lualib/webapp_dispatch.lua 中的任意代码。
    • 之后执行 sh make/script/check_reload.sh load_mods.lua
    • 再次访问网站就更新了。
    • 也可以观察webapp/logs/server.log

如何远程rpc调用

具体使用例子可以参照examples/frpc_client examples/frpc_server

完整项目示例