skynet框架應用 (四) 服務類型

4 服務類型

​ skynet中的服務分爲普通服務與全局唯一服務。第3節啓動方式就是一個普通服務,而全局唯一服務顧名思義就是在skynet中只能生成一個服務實例。

4.1 普通服務

​ 每調用一次創建接口就會創建出一個對應的服務實例,可以同時創建成千上萬個,用唯一的id來區分每個服務實例。使用的創建接口是:


--[[
1. 用於啓動一個新的 Lua 服務,luaServerName是腳本的名字(不用寫 .lua 後綴)。
2. 只有被啓動的腳本的 start 函數返回後,這個 API 纔會返回啓動的服務的地址,這是一個阻塞 API 。
3. 如果被啓動的腳本在初始化環節拋出異常,skynet.newservice 也會執行失敗。
4. 如果被啓動的腳本的 start 函數是一個永不結束的循環,那麼 newservice 也會被永遠阻塞住。
--]]
skynet.newservice(luaServerName, ...)
  1. 啓動一個test服務

    testnewservice.lua


local skynet = require "skynet" 

--調用skynet.start接口,並定義傳入回調函數
skynet.start(function()
    skynet.error("My new service")
    skynet.newservice("test")
    skynet.error("new test service")
end)

​ 啓動main.lua,並且輸入testnewservice


$ ./skynet examples/config #默認啓動main.lua服務
testnewservice
[:01000010] LAUNCH snlua testnewservice  #通過main服務,啓動testnewservice服務
[:01000010] My new service           
[:01000012] LAUNCH snlua test           #再啓動test服務
[:01000012] Server First Test
[:01000010] new test service
  1. 啓動兩個test服務

    testnewservice2.lua


local skynet = require "skynet" 

--調用skynet.start接口,並定義傳入回調函數
skynet.start(function()
 skynet.error("My new service")
 skynet.newservice("test")
 skynet.error("new test service 0")
 skynet.newservice("test")
 skynet.error("new test service 1")
end)

​ 啓動main.lua,並且輸入testnewservice


$ ./skynet examples/config  #默認啓動main.lua服務
testnewservice          #終端輸入
[:01000010] LAUNCH snlua testnewservice  #通過main服務,啓動testnewservice服務
[:01000010] My new service
[:01000012] LAUNCH snlua test     #啓動一個test服務
[:01000012] Server First Test
[:01000010] new test service 0
[:01000019] LAUNCH snlua test     #再啓動一個test服務
[:01000019] Server First Test
[:01000010] new test service 1

4.2 全局唯一服務

全局唯一的服務等同於單例,即不管調用多少次創建接口,最後都只會創建一個此類型的服務實例,且全局唯一。

  • 創建接口:

    
    skynet.uniqueservice(servicename, ...) 
    skynet.uniqueservice(true, servicename, ...) 

    當帶參數 true 時,則表示此服務在所有節點之間是唯一的。第一次創建唯一服,返回服務地址,第二次創建的時候不會正常創建服務,只是返回第一次創建的服務地址。

  • 查詢接口: 假如不清楚當前創建了此全局服務沒有,可以通過以下接口來查詢:

    
    skynet.queryservice(servicename, ...) 
    skynet.queryservice(true, servicename, ...) 

    如果還沒有創建過目標服務則一直等下去,直到目標服務被(其他服務觸發而)創建。

    當參數 帶true 時,則表示查詢在所有節點中唯一的服務是否存在。

4.2.1 測試skynet.uniqueservice接口

示例:testunique.lua


local skynet = require "skynet" 

local args = { ... }
if(#args == 0) then
    table.insert(args, "uniqueservice")
end

skynet.start(function()
    local us
    skynet.error("test unique service")
    if ( #args == 2 and args[1] == "true" )  then
        us = skynet.uniqueservice(true, args[2])
    else
        us =skynet.uniqueservice(args[1])
    end
    skynet.error("uniqueservice handler:", skynet.address(us))
end)

示例:uniqueservice.lua


local skynet = require "skynet" 

skynet.start(function()
    skynet.error("Server First Test")
    --skynet.exit() 不要嘗試服務初始化階段退出服務,唯一服會創建失敗
end)

運行結果:


$ ./skynet examples/config
testunique   #終端輸入
[:01000010] LAUNCH snlua testunique
[:01000010] test unique service
[:01000012] LAUNCH snlua uniqueservice  #第一次創建全局唯一服uniqueservice成功
[:01000012] unique service start
[:01000010] uniqueservice handler: :01000012
testunique  #終端輸入
[:01000019] LAUNCH snlua testunique 
[:01000019] test unique service
[:01000019] uniqueservice handler: :01000012  #第二次創建並沒有創建全局唯一服

4.2.2 測試skynet.queryservice接口

示例:testqueryservice.lua


local skynet = require "skynet" 

local args = { ... }
if(#args == 0) then
    table.insert(args, "uniqueservice")
end
skynet.start(function()
    local us
    skynet.error("start query service")
    --如果test服務未被創建,該接口將會阻塞,後面的代碼將不會執行
    if ( #args == 2 and args[1] == "true" )  then
        us = skynet.queryservice(true, args[2])
    else
        us = skynet.queryservice(args[1])  
    end
    skynet.error("end query service handler:", skynet.address(us))
end)

運行結果:

如果不啓動test全局唯一服務,直接執行查詢函數


$ ./skynet examples/config
testqueryservice   #終端輸入
[:01000010] LAUNCH snlua testqueryservice
[:01000010] start query service            #阻塞住,不再執行後面的代碼

啓動test全局唯一服務,再執行查詢函數


$ ./skynet examples/config
testunique  #終端輸入
[:01000010] LAUNCH snlua testunique
[:01000010] test unique service
[:01000012] LAUNCH snlua uniqueservice #第一次創建全局唯一服成功
[:01000012] Server First Test
[:01000010] uniqueservice handler: :01000012
testqueryservice
[:01000019] LAUNCH snlua testqueryservice   #再啓動查詢
[:01000019] start query service
[:01000019] end query service handler: :01000012 #skynet.queryservice將會返回

注意:

​ 當調用uniqueservice只傳一個服務名時,表示創建當前skynet節點的全局唯一服務。當第一個參數傳遞true,第二個參數傳遞服務名時,則表示所有節點的全局唯一服務。

​ 調用queryservice時,也可以選擇是否傳遞第一個參數true, 表示查詢的是當前skynet節點的全局唯一服,還是所有節點的全局唯一服。這兩種全局唯一服作用範圍是不同,所有可以同時存在同名的但作用範圍不同的全局唯一服。

4.3 多節點中的全局服務

4.3.1 啓動兩個skynet節點

​ 首先,我們先啓動兩個節點出來。copy兩個份examp/configconfig1config2, config1中修改如下:

config1:


include "config.path"

-- preload = "./examples/preload.lua"   -- run preload.lua before every lua service run
thread = 2 
logger = nil
logpath = "."
harbor = 1      --表示每個節點編號
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "console"   -- main script 只啓動一個console.lua服務
bootstrap = "snlua bootstrap"   -- The service for bootstrap
standalone = "0.0.0.0:2013" --主節點纔會用到這個,綁定地址
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

config2:


include "config.path"

-- preload = "./examples/preload.lua"   -- run preload.lua before every lua service run
thread = 2 
logger = nil
logpath = "."
harbor = 2      --編號需要改
address = "127.0.0.1:2527"   --改一個跟config1不同的端口
master = "127.0.0.1:2013"   --主節點地址不變
start = "console"   -- main script
bootstrap = "snlua bootstrap"   -- The service for bootstrap
--standalone = "0.0.0.0:2013" --作爲從節點,就註釋掉這裏
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

啓動兩個終端分別啓動如下:

節點1啓動:


./skynet examples/config1 
[:01000001] LAUNCH logger 
[:01000002] LAUNCH snlua bootstrap
[:01000003] LAUNCH snlua launcher
[:01000004] LAUNCH snlua cmaster  #啓動主節點cmaster服務
[:01000004] master listen socket 0.0.0.0:2013  #監聽端口2013
[:01000005] LAUNCH snlua cslave #主節點也要啓動一個cslave,去連接cmaster節點
[:01000005] slave connect to master 127.0.0.1:2013 #cslave中一旦連接完cmaster就會啓動一個harbor服務
[:01000004] connect from 127.0.0.1:47660 4 
[:01000006] LAUNCH harbor 1 16777221 #cslave啓動一個Harbor服務 用於節點間通信
[:01000004] Harbor 1 (fd=4) report 127.0.0.1:2526 #報告cmaster cslave服務的地址
[:01000005] Waiting for 0 harbors #cmaster告訴cslave還有多少個其他cslave需要連接
[:01000005] Shakehand ready         #cslave與cmaster握手成功
[:01000007] LAUNCH snlua datacenterd
[:01000008] LAUNCH snlua service_mgr
[:01000009] LAUNCH snlua console
[:01000002] KILL self
[:01000004] connect from 127.0.0.1:47670 6 #cmaster收到其他cslave連接請求
[:01000004] Harbor 2 (fd=6) report 127.0.0.1:2527  #其他cslave報告地址
[:01000005] Connect to harbor 2 (fd=7), 127.0.0.1:2527 #讓當前cslave去連接其他cslave

節點2啓動:


./skynet examples/config2 
[:02000001] LAUNCH logger 
[:02000002] LAUNCH snlua bootstrap
[:02000003] LAUNCH snlua launcher
[:02000004] LAUNCH snlua cslave
[:02000004] slave connect to master 127.0.0.1:2013 #cslave去連接主節點的cmaster服務
[:02000005] LAUNCH harbor 2 33554436 #cslave也啓動一個harbor服務
[:02000004] Waiting for 1 harbors   #等待主節點的cslave來連接
[:02000004] New connection (fd = 3, 127.0.0.1:37470) #cslave與主節點cslave連接成功
[:02000004] Harbor 1 connected (fd = 3)
[:02000004] Shakehand ready   #cslave與cmaster握手成功
[:02000006] LAUNCH snlua service_mgr
[:02000007] LAUNCH snlua console
[:02000002] KILL self

4.3.2 測試全節點全局唯一服

在第一個節點中啓動testunique.lua服務,然後第二個節點中啓動testqueryservice.lua服務查詢

節點1:


testunique true uniqueservice #所有節點全局唯一服方式啓動
[:0100000b] LAUNCH snlua testunique true uniqueservice
[:0100000b] test unique service
[:0100000c] LAUNCH snlua uniqueservice
[:0100000c] Server First Test
[:0100000b] uniqueservice handler: :0100000c

節點2:


testqueryservice true uniqueservice
[:02000012] LAUNCH snlua testqueryservice true uniqueservice
[:02000012] start query service
[:02000012] end query service handler: :0100000b#節點1中已經啓動了,所以節點2中

4.3.3 本地全局唯一服與全節點全局唯一服區別

節點2還可以創建一個同腳本的本地全局唯一服:


testunique uniqueservice
[:0100000c] LAUNCH snlua testunique 
[:0100000c] test unique service
[:0100000d] LAUNCH snlua uniqueservice
[:0100000d] Server First Test
[:0100000c] uniqueservice handler: :0100000d #創建了一個本地全局唯一服

但是無法創建一個新的全節點全局唯一服:


testunique true uniqueservice
[:0100000e] LAUNCH snlua testunique true uniqueservice
[:0100000e] test unique service
[:0100000e] uniqueservice handler: :0100000b #還是節點1的全局唯一服句柄

發佈了101 篇原創文章 · 獲贊 117 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章