在寫start-motan時(shí),已經(jīng)加入自動(dòng)注冊的功能,自然要考慮服務(wù)下線的功能,其在github上也寫如何優(yōu)化關(guān)機(jī),下面嘗試在start中加入該功能。
官方說:待關(guān)閉節(jié)點(diǎn)需要調(diào)用以下代碼,建議通過servlet或業(yè)務(wù)的管理模塊進(jìn)行該調(diào)用。
MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true)
同時(shí)官方在注解的例子中說:在使用注冊中心時(shí)要主動(dòng)調(diào)用下面代碼:
MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true);
注冊和反注冊調(diào)用的兩段代碼一樣....
進(jìn)去翻了下代碼,總嚼著反注冊怎么著也要傳個(gè)false進(jìn)來
public void onValueChanged(String key, Boolean value) {
if (key != null && value != null) {
if (value) { // 傳入值為true時(shí)執(zhí)行
available(null);
} else { // 傳入值為false時(shí)執(zhí)行
unavailable(null);
}
}
}
// 最終的操作
@Override
protected void doAvailable(URL url) {
try{
serverLock.lock();
if (url == null) {
availableServices.addAll(getRegisteredServiceUrls());
for (URL u : getRegisteredServiceUrls()) {
removeNode(u, ZkNodeType.AVAILABLE_SERVER);
removeNode(u, ZkNodeType.UNAVAILABLE_SERVER);
createNode(u, ZkNodeType.AVAILABLE_SERVER);
}
} else {
availableServices.add(url);
removeNode(url, ZkNodeType.AVAILABLE_SERVER);
removeNode(url, ZkNodeType.UNAVAILABLE_SERVER);
createNode(url, ZkNodeType.AVAILABLE_SERVER);
}
} finally {
serverLock.unlock();
}
}
@Override
protected void doUnavailable(URL url) {
try{
serverLock.lock();
if (url == null) {
availableServices.removeAll(getRegisteredServiceUrls());
for (URL u : getRegisteredServiceUrls()) {
removeNode(u, ZkNodeType.AVAILABLE_SERVER);
removeNode(u, ZkNodeType.UNAVAILABLE_SERVER);
createNode(u, ZkNodeType.UNAVAILABLE_SERVER);
}
} else {
availableServices.remove(url);
removeNode(url, ZkNodeType.AVAILABLE_SERVER);
removeNode(url, ZkNodeType.UNAVAILABLE_SERVER);
createNode(url, ZkNodeType.UNAVAILABLE_SERVER);
}
} finally {
serverLock.unlock();
}
}
下面測試下不同的傳值的實(shí)際結(jié)果
先加入一個(gè)關(guān)閉回調(diào),加個(gè)斷點(diǎn)。
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, false);
} catch (Exception e) {
e.printStackTrace();
}
}
});
通過測試,無論傳入的是true,還是false,服務(wù)都取消了。
只要執(zhí)行這個(gè)命令kill pid,即使不執(zhí)行setSwitcherValue方法,暴露的服務(wù)也給反注冊了。
查看zk命令行:
// 服務(wù)剛啟動(dòng)時(shí)
[zk: localhost:2181(CONNECTED) 24] ls /motan/default_rpc/com.github.chenxing2.demo.api.IMotanDemo/server
[192.168.1.100:8888]
// 執(zhí)行 kill pid時(shí),注冊的服務(wù)直接消失
[zk: localhost:2181(CONNECTED) 25] ls /motan/default_rpc/com.github.chenxing2.demo.api.IMotanDemo/server
[]
為啥會(huì)這樣?看打印信息是從spring發(fā)起的,后續(xù)看這塊代碼時(shí)再研究下。
到這的話,優(yōu)雅關(guān)機(jī)也能實(shí)現(xiàn)了。
kill pid時(shí),處理下線程池等相關(guān)的關(guān)閉;再獲取到本服務(wù)內(nèi)的剩余調(diào)用數(shù),等待現(xiàn)有的請(qǐng)求處理完。不知道Motan是否有直接拿到調(diào)用數(shù)的功能,還沒看管理后臺(tái)。
只是,通過這種方式關(guān)閉服務(wù),跟蹤代碼在doUnavailable方法中實(shí)際并未執(zhí)行任何有效代碼,所以還是按照官方說明的方法測試一下「建議通過servlet或業(yè)務(wù)的管理模塊進(jìn)行該調(diào)用」
偷個(gè)懶,來個(gè)一錘子買賣,在原有代碼中加點(diǎn)料,調(diào)用服務(wù)時(shí),先反注冊,然后再返回結(jié)果:
public String say(String val) {
MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, false);
return "hello " + val;
}
先上結(jié)果:
- 傳true,該服務(wù)可多次正常調(diào)用,毫無問題
// 服務(wù)啟動(dòng)時(shí)
[zk: localhost:2181(CONNECTED) 27] ls /motan/default_rpc/com.github.chenxing2.demo.api.IMotanDemo/server
[192.168.1.100:8888]
// 調(diào)用setSwitcherValue后(傳值為true)
[zk: localhost:2181(CONNECTED) 28] ls /motan/default_rpc/com.github.chenxing2.demo.api.IMotanDemo/server
[192.168.1.100:8888]
- 傳false,該服務(wù)可多次正常調(diào)用,毫無問題
// 服務(wù)啟動(dòng)時(shí)
[zk: localhost:2181(CONNECTED) 29] ls /motan/default_rpc/com.github.chenxing2.demo.api.IMotanDemo/server
[192.168.1.100:8888]
// 調(diào)用setSwitcherValue后(傳值為false)
[zk: localhost:2181(CONNECTED) 30] ls /motan/default_rpc/com.github.chenxing2.demo.api.IMotanDemo/server
[]
從結(jié)果可以看出來,優(yōu)雅關(guān)閉服務(wù),是需要傳入false的,這個(gè)應(yīng)該是官方文檔寫錯(cuò)了。
只是,在服務(wù)已消失的情況下,客戶端依然可以發(fā)起請(qǐng)求,并能正常收到結(jié)果。按我理解應(yīng)該是收到不到結(jié)果才對(duì),畢竟只配了一個(gè)服務(wù),該服務(wù)下線應(yīng)通知客戶端該服務(wù)不可用的,實(shí)際上還能使用,這是為什么....
然后又啟動(dòng)一個(gè)客戶端,此時(shí)報(bào)錯(cuò)了error_message: ClusterSupport No service urls for the refer,對(duì)于這個(gè)結(jié)果沒有任何問題,畢竟已無服務(wù)了。
難道是只有一個(gè)服務(wù)它就不通知了?那就啟動(dòng)兩個(gè)服務(wù),其中一個(gè)服務(wù)調(diào)用后反注冊,另一個(gè)不做處理,并且打印不同的消息以確定是哪個(gè)服務(wù)響應(yīng)。
// 啟動(dòng)兩個(gè)服務(wù)
[zk: localhost:2181(CONNECTED) 32] ls /motan/default_rpc/com.github.chenxing2.demo.api.IMotanDemo/server
[192.168.1.100:8888, 192.168.1.103:8888]
通過調(diào)用測試,當(dāng)其中一個(gè)服務(wù)反注冊后,后面的請(qǐng)求均發(fā)送到正常的服務(wù)器,也意味著,反注冊后的服務(wù)是不會(huì)再收到客戶端請(qǐng)求的。(只有一個(gè)服務(wù)時(shí)無論是否反注冊依然會(huì)收到請(qǐng)求)
- addShutdownHook,命令行關(guān)服務(wù)
- 通過jmx對(duì)外暴露
- 通過http等方法
綜合還是使用前兩個(gè)來實(shí)現(xiàn),命令行也要能優(yōu)雅關(guān)機(jī),然后也可通過jmx遠(yuǎn)程優(yōu)雅關(guān)機(jī)