skynet学习笔记之http服务搭建2

8 篇文章 1 订阅

前言

前不久尝试了 http 服务的搭建,现在为它搭建一个网关。看了 skynet wiki 中的几篇涉及 master/slave 的文章,以及 lualib/cmaster.lua 和 lualib/cslave.lua 的代码后,实现了第一个方案,gate 和 game 处于一个集群中,gate 和 game 间通过 slave/harbor 服务来间接通信。

思路

大致架构图:
在这里插入图片描述
设计方案:

  1. 利用 skynet 的 master/slave 机制,master 作为 gate,slave 作为 game。
    在这里插入图片描述
  2. 单独一个集群作为 gate,另一个集群作为 game。
  3. 尝试 skynet 的 cluster 服务。

本文用第一个方案搭建。方案二 使用了 skynet 自带的 gate 服务,有兴趣可以看看。

目录结构

在这里插入图片描述

  1. 启动 gate:./skynet game/etc/config_web_master
  2. 启动 game:./skynet game/etc/config_web_slave

代码

masterweb.lua 和 slaveweb.lua 从 examples/simpleweb.lua 复制出来修改成两个服务。

  • config_web_master 作为集群的 master 的配置,以下几项需要关注:

    harbor = 1 -- 集群中节点 id,0 被保留,1 ~ 255 可以使用
    address = "127.0.0.1:2526" -- slave 服务的监听地址,即便是 master 服务所在进程,也会启动一个 slave 服务
    master = "127.0.0.1:2013"  -- master 服务的监听地址,用于 slave 连接
    start = "service_web/masterweb"	-- main script
    bootstrap = "snlua bootstrap"	-- The service for bootstrap
    standalone = "0.0.0.0:2013"  -- master 服务的监听地址,开放给 slave 来连接
    
  • config_web_slave 作为集群的 slave 的配置,以下几项需要关注:

    harbor = 2 -- 集群中节点 id,与 master 拥有的 id 区分开
    address = "127.0.0.1:2527" -- slave 服务的监听地址
    master = "127.0.0.1:2013"  -- master 服务的监听地址,用于 slave 连接
    start = "service_web/slaveweb"	-- main script
    bootstrap = "snlua bootstrap"	-- The service for bootstrap
    --standalone = "0.0.0.0:2013" -- 注释掉,该项存在则表示是 master 服务
    
  • masterweb.lua 启动 gate 接收客户端连接,20个 agent 服务来承接连接,接收客户端数据,并且转发给 game 服务,然后展示 game 服务的返回结果。

    local skynet = require "skynet"
    local socket = require "skynet.socket"
    local httpd = require "http.httpd"
    local sockethelper = require "http.sockethelper"
    local urllib = require "http.url"
    local table = table
    local string = string
    
    local mode, protocol = ...
    protocol = protocol or "http"
    
    if mode == "gate" then
     ... -- 省略没有修改的内容
    game_svr_addr = game_svr_addr
    
    skynet.start(function()
    	skynet.dispatch("lua", function (_,_,id)
    		socket.start(id)
    		local interface = gen_interface(protocol, id)
    		if interface.init then
    			interface.init()
    		end
    		-- limit request body size to 8192 (you can pass nil to unlimit)
    		local code, url, method, header, body = httpd.read_request(interface.read, 8192)
            -- 1. 拿到 game 服务的地址
            --   发消息给 .cslave 获取地址
            -- 2. 将 http 消息内容转发给 game
            -- 3. 将 game 回复的内容转发给 client
            LOG("find game_addr from slave begin")
            if not game_svr_addr then
            	-- 向 .cslave 服务查询 game 服务地址
                game_svr_addr = skynet.call(".cslave", "lua", "QUERYNAME", "game")
            end
            LOG("find game_addr from slave, game_addr,%s", game_svr_addr)
            local code, msg = skynet.call(game_svr_addr, "lua", code, url, method, header, body)
            --skynet.wait()
            LOG("callback, code,%s, url,%s", code, url)
    		if code then
    		    response(id, interface.write, code, msg)
    		else
    			if url == sockethelper.socket_error then
    				skynet.error("socket closed")
    			else
    				skynet.error(url)
    			end
    		end
    		socket.close(id)
    		if interface.close then
    			interface.close()
    		end
    	end)
    end)
    
    else
    ... -- 省略没有修改的内容
    end
    
  • slaveweb.lua 注册 lua 消息的处理函数,将 gate 发过来的 http 消息内容构造成显示数据回传给 gate 服务;启动后,在集群中注册自己为 game 服务,以便于 gate 可以通过 game 这个名字查询到远程服务。

    local skynet = require "skynet"
    local table = table
    local string = string
    
    skynet.dispatch("lua", function (session, addr, code, url, method, header, body)
        LOG("i am slave, received a msg, session,%s, addr,%s", session, addr)
        local msg
        if code == 200 then
            local tmp = {}
            if header.host then
                table.insert(tmp, string.format("host: %s", header.host))
            end
            local path, query = urllib.parse(url)
            table.insert(tmp, string.format("path: %s", path))
            if query then
                local q = urllib.parse_query(query)
                for k, v in pairs(q) do
                    table.insert(tmp, string.format("query: %s= %s", k,v))
                end
            end
            table.insert(tmp, "-----header----")
            for k,v in pairs(header) do
                table.insert(tmp, string.format("%s = %s",k,v))
            end
            table.insert(tmp, "-----body----\n" .. body)
            msg = table.concat(tmp,"\n")
        end
        skynet.ret(skynet.pack(code, msg))
    end)
    
    skynet.start(function()
        skynet.send(".cslave", "lua", "REGISTER", "game", skynet.self())
    end)
    
    
  • 执行表现:
    在这里插入图片描述

结语

借助这个简易 gate 的搭建,加深了对 master/slave 的了解。

  1. 后续实现方案2 和 方案3 的搭建。
  2. 目前是在 gate 中对 http 消息做了解析,后续将这一步放到 game 来做,gate 只做数据包的转发。

参考文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tobybo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值