应用场景: 用于复杂计算的服务,可伸缩的控制服务的数量,比如高峰期到来时开启更多的服务,高峰过后需要回收的服务。
这里只演示无状态的服务,有状态的服务处理更复杂。
- 给一堆相同的无状态服务(calculate)用个管理器(calculate_mng)管理起来
- calculate_mng 作为入口供其他服务器调用
- calculate_mng 对 calculate 服务有生杀大权
如何正确的退出服务?
这里有讲到退出服务的接口 Skynet 服务的启动和退出
skynet.exit() 用于退出当前的服务。skynet.exit 之后的代码都不会被运行。而且,当前服务被阻塞住的 coroutine 也会立刻中断退出。这些通常是一些 RPC 尚未收到回应。所以调用 skynet.exit() 请务必小心。
skynet.kill(address) 可以用来强制关闭别的服务。但强烈不推荐这样做。因为对象会在任意一条消息处理完毕后,毫无征兆的退出。所以推荐的做法是,发送一条消息,让对方自己善后以及调用 skynet.exit 。注:skynet.kill(skynet.self()) 不完全等价于 skynet.exit() ,后者更安全。
为了正确的退出服务,需要选用 skynet.exit()
,而且要确保没有挂起的 RPC。
我们这里的例子是无状态服务,服务也比较简单,只做复杂计算,不会再发起 RPC 去其他地方请求数据(比如去数据库读取数据)。所以只需要这样写退出函数就行了。
function CMD.exit()
skynet.error("slave exit.")
skynet.ret()
skynet.exit()
-- exit() 之后的代码是不会执行的
end
负载均衡?
用数组 slave
把服务的地址存起来,然后在每调用一次计算接口 calculate
就换下一个服务。
local slave = {}
local balance = 1
-- 找一个 slave 帮忙做点复杂的计算
function CMD.calculate(a, b)
local s = slave[balance]
balance = balance + 1
if balance > #slave then
balance = 1
end
return skynet.call(s, "lua", "calculate", a, b)
end
动态伸缩服务数量?
取当前服务的数量 #slave
, 数量相同就跳过,服务数量不够就开启新的服务,服务数量多了就干掉多余的服务。
function CMD.set_slave_count(cnt)
local now_cnt = #slave
if now_cnt == cnt then
skynet.error(string.format("slave count is:%d", now_cnt))
return
end
balance = 1
if now_cnt > cnt then
local kill_cnt = now_cnt - cnt
for _=1,kill_cnt do
local s = slave[#slave]
skynet.call(s, "lua", "exit")
table.remove(slave)
end
skynet.error(string.format("slave old_cnt:%d, new_cnt:%d", now_cnt, #slave))
return
end
if now_cnt < cnt then
local add_cnt = cnt - now_cnt
for _=1,add_cnt do
table.insert(slave, skynet.newservice(SLAVE_SERVICE_NAME))
end
skynet.error(string.format("slave old_cnt:%d, new_cnt:%d", now_cnt, #slave))
return
end
end
自动伸缩?
这个我就没写代码了,一般就是用启动心跳定时去监测服务的繁忙情况。
完整代码在这里: Skynet 动态控制无状态服务的数量