同主機運行ZeroRPC Client和Server時端口搶占問題的解決

如果你使用ZeroRPC;
如果你買不起服務器或者拿不到服務器用;
如果你決定把好多服務都放在一個物理主機上跑;

那你很有可能會遇到這個問題,當你的server進程因為某些意外掛了,而client還在不斷有請求過來時,你會發(fā)現(xiàn)有一定可能server無法重新啟動,理由是端口已被占用,看一下就會發(fā)覺被client給占了。這很氣人,如果不把client全殺了server就起不來,而server起不來client就會一直卡著端口,重啟client又不一定那么容易。

真實環(huán)境下這個問題真的坑到我一次,于是我決定花點時間解決一下這個問題,所以就做了個workaround。
原理其實很簡單,如果client發(fā)現(xiàn)心跳包發(fā)不出去或者remote超時了,就把自己的連接給關了,下次再調用的時候重新連接。

多數(shù)情況下并不需要這套機制,重新建立tcp連接帶來的開銷是不小的,如果在線上環(huán)境請謹慎使用。

[python client]
import zerorpc

class RPCProxy(object):

    def __init__(self, connect_to=None, context=None, timeout=30, heartbeat=5,
                 passive_heartbeat=False):
        self._client = zerorpc.Client(connect_to, context,
                                      timeout, heartbeat, passive_heartbeat)
        self.endpoint = connect_to
        self.context = context
        self.timeout = timeout
        self.heartbeat = heartbeat
        self.passive_heartbeat = passive_heartbeat

    def connect(self, endpoint, resolve=True):
        self.endpoint = endpoint
        return self._client.connect(endpoint, resolve)

    def bind(self, endpoint, resolve=True):
        self.endpoint = endpoint
        return self._client.bind(endpoint, resolve)

    def __call__(self, method, *args, **kwargs):
        if self._client._events._socket.closed:
            self._client = zerorpc.Client(self.endpoint, self.context, self.timeout,
                                          self.heartbeat, self.passive_heartbeat)
        try:
            result = self._client(method, *args, **kwargs)
            return result
        except zerorpc.exceptions.LostRemote, e:
            self._client.close()
            raise e
        except zerorpc.exceptions.TimeoutExpired, e:
            self._client.close()
            raise e

    def __getattr__(self, method):
        return lambda *args, **kargs: self(method, *args, **kargs)

夸一句,python里 __getattr____call__配合使用真是精妙,很簡單就模仿了local代碼的調用方式。

[node.js client]
var zerorpc = require('zerorpc');

var rpcproxy = function _rpcproxy (endpoint){
    this.client = new zerorpc.Client();
    this.client.connect(endpoint);
    this.endpoint = endpoint;
    return this;
};

rpcproxy.prototype.invoke = function() {
    if (this.client.closed()){
        this.client = new zerorpc.Client();
        this.client.connect(this.endpoint);
    }
    var hasCallabck = arguments.length && typeof(arguments[arguments.length-1]) == 'function';
    if (hasCallabck){
        this.callerCallback = arguments[arguments.length-1];
    }
    var argList = [];
    for (var i = 0; i < hasCallabck?arguments.length-1:arguments.length; i++){
        argList.push(arguments[i]);
    }
    eval('this.client.invoke('+this.makeArgListString(argList)+',this._callback.bind(this));');
};

rpcproxy.prototype.makeArgListString = function(argList){
    var argString = []
    for (var i in argList){
        argString.push('argList['+i+']');
    }
    return argString.join(',');
};

rpcproxy.prototype._callback = function(err, res, more){
    if (err && err.name == 'HeartbeatError' || err.name == 'TimeoutExpired') {
        this.client.close();
    }
    if (this.callerCallabck){
        this.callerCallback(err, res, more);
    }
};

js的實現(xiàn)使用了比較邪惡的eval方法,不過也不用擔心不安全,因為組織后的字符串是由argList[0], argList[1]...組成的,并不包含實際的值,不會被執(zhí)行一些奇怪的東西。

如有錯誤,歡迎指正。以上。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,711評論 19 139
  • 名詞延伸 通俗的說,域名就相當于一個家庭的門牌號碼,別人通過這個號碼可以很容易的找到你。如果把IP地址比作一間房子...
    楊大蝦閱讀 20,833評論 2 56
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,290評論 6 342
  • 風清云閑鶴 草長木飛鶯 誰曉無情夜 渾水來摸魚
    光影腹黑閱讀 260評論 1 2
  • 比較優(yōu)勢沒有說明:它的來源與基礎,以及貿易對兩國要素收入的影響。要素稟賦理論探討了此問題。 由于跟我生產要素的稟賦...
    忽爾今至閱讀 228評論 0 0

友情鏈接更多精彩內容