def __invoke(self, reqmsg): """ @brief: 远程过程调用 @param reqmsg: 请求数据 @type reqmsg: ReqMessage @return: 调用成功或失败 @rtype: bool """ tarsLogger.debug("ServantProxy:invoke, func: %s", reqmsg.request.sFuncName) ret = self.__object.invoke(reqmsg) if ret == -2: errmsg = ("ServantProxy::invoke fail, no valid servant," + " servant name : %s, function name : %s" % ( reqmsg.request.sServantName, reqmsg.request.sFuncName, )) raise TarsException(errmsg) if ret == -1: errmsg = ("ServantProxy::invoke connect fail," + " servant name : %s, function name : %s, adapter : %s" % ( reqmsg.request.sServantName, reqmsg.request.sFuncName, reqmsg.adapter.getEndPointInfo(), )) raise TarsException(errmsg) elif ret != 0: errmsg = ("ServantProxy::invoke unknown fail, " + "Servant name : %s, function name : %s" % ( reqmsg.request.sServantName, reqmsg.request.sFuncName, )) raise TarsException(errmsg) if reqmsg.type == ReqMessage.SYNC_CALL: reqmsg.lock.acquire() reqmsg.lock.wait(self.__timeout()) reqmsg.lock.release() if not reqmsg.response: errmsg = ("ServantProxy::invoke timeout: %d, servant name" ": %s, adapter: %s, request id: %d" % ( self.tars_timeout(), self.tars_name(), reqmsg.adapter.trans().getEndPointInfo(), reqmsg.request.iRequestId, )) raise exception.TarsSyncCallTimeoutException(errmsg) elif reqmsg.response.iRet == ServantProxy.TARSSERVERSUCCESS: return reqmsg.response else: errmsg = "servant name: %s, function name: %s" % ( self.tars_name(), reqmsg.request.sFuncName, ) self.tarsRaiseException(reqmsg.response.iRet, errmsg)
def __updateConHashProxyWeighted(self): tarsLogger.debug('AdapterProxyManager:updateConHashProxyWeighted') lock = LockGuard(self.__newLock) if len(self.__regAdapterProxyDict) == 0: raise TarsException("the adapter proxy is empty") self.__lastConHashPrxList = sorted(self.__regAdapterProxyDict.items(), key=lambda item: item[0]) nodes = [] for var in self.__lastConHashPrxList: nodes.append(var[0]) if self.__consistentHashWeight is None: self.__consistentHashWeight = ConsistentHashNew(nodes) else: theOldActiveNodes = [ var for var in nodes if var in self.__consistentHashWeight.nodes ] theOldInactiveNodes = [ var for var in self.__consistentHashWeight.nodes if var not in theOldActiveNodes ] for var in theOldInactiveNodes: self.__consistentHashWeight.removeNode(var) theNewActiveNodes = [ var for var in nodes if var not in theOldActiveNodes ] for var in theNewActiveNodes: self.__consistentHashWeight.addNode(var) self.__consistentHashWeight.nodes = nodes pass
def __getNextValidProxy(self): ''' @brief: 刷新本地缓存列表,如果服务下线了,要求删除本地缓存 @return: @rtype: EndPointInfo列表 @todo: 优化负载均衡算法 ''' tarsLogger.debug('AdapterProxyManager:getNextValidProxy') lock = LockGuard(self.__newLock) if len(self.__adps) == 0: raise TarsException("the activate adapter proxy is empty") sortedActivateAdp = sorted(self.__adps.items(), key=lambda item: item[1][2]) # self.refreshEndpoints() # self.__lock.acquire() sortedActivateAdpSize = len(sortedActivateAdp) while sortedActivateAdpSize != 0: if sortedActivateAdp[0][1][1].checkActive(): self.__adps[sortedActivateAdp[0][0]][2] += 1 # 返回的是 adapterProxy return self.__adps[sortedActivateAdp[0][0]][1] sortedActivateAdp.pop(0) sortedActivateAdpSize -= 1 # 随机重连一个可用节点 adpPrx = self.__adps.items()[random.randint(0, len(self.__adps))][1][1] adpPrx.checkActive() return None
def parseConnAddr(self, connAddr): ''' @brief: 解析connAddr字符串 @param connAddr: 连接地址 @type connAddr: str @return: 解析结果 @rtype: dict, key是str,val里name是str, timeout是float,endpoint是EndPointInfo的list ''' tarsLogger.debug('Communicator:parseConnAddr') connAddr = connAddr.strip() connInfo = {'name': '', 'timeout': -1, 'endpoint': []} if '@' not in connAddr: connInfo['name'] = connAddr return connInfo try: tks = connAddr.split('@') connInfo['name'] = tks[0] tks = tks[1].lower().split(':') parser = argparse.ArgumentParser(add_help=False) parser.add_argument('-h') parser.add_argument('-p') parser.add_argument('-t') for tk in tks: argv = tk.split() if argv[0] != 'tcp': raise TarsException( 'unsupport transmission protocal : %s' % connInfo['name']) mes = parser.parse_args(argv[1:]) try: ip = mes.h if mes.h is not None else '' port = int(mes.p) if mes.p is not None else '-1' timeout = int(mes.t) if mes.t is not None else '-1' connInfo['endpoint'].append(EndPointInfo( ip, port, timeout)) except Exception: raise TarsException('Unrecognized option : %s' % mes) except TarsException: raise except Exception, exp: raise TarsException(exp)
def tars_invoke(self, cPacketType, sFuncName, sBuffer, context, status): ''' @brief: TARS协议同步方法调用 @param cPacketType: 请求包类型 @type cPacketType: int @param sFuncName: 调用函数名 @type sFuncName: str @param sBuffer: 序列化后的发送参数 @type sBuffer: str @param context: 上下文件信息 @type context: ServantProxy.mapcls_context @param status: 状态信息 @type status: @return: 响应报文 @rtype: ResponsePacket ''' tarsLogger.debug('ServantProxy:tars_invoke, func: %s', sFuncName) req = RequestPacket() req.iVersion = ServantProxy.TARSVERSION req.cPacketType = cPacketType req.iMessageType = ServantProxy.TARSMESSAGETYPENULL req.iRequestId = 0 req.sServantName = self.tars_name() req.sFuncName = sFuncName req.sBuffer = sBuffer req.iTimeout = self.tars_timeout() reqmsg = ReqMessage() reqmsg.type = ReqMessage.SYNC_CALL reqmsg.servant = self reqmsg.lock = threading.Condition() reqmsg.request = req reqmsg.begtime = time.time() # # test reqmsg.isHash = True reqmsg.isConHash = True reqmsg.hashCode = 123456 rsp = None try: rsp = self.__invoke(reqmsg) except exception.TarsSyncCallTimeoutException: if reqmsg.adapter: reqmsg.adapter.finishInvoke(True) raise except TarsException: raise except: raise TarsException('ServantProxy::tars_invoke excpetion') if reqmsg.adapter: reqmsg.adapter.finishInvoke(False) return rsp
def __getConHashProxyForNormal(self, hashCode): tarsLogger.debug('AdapterProxyManager:getConHashProxyForNormal') lock = LockGuard(self.__newLock) if len(self.__regAdapterProxyDict) == 0: raise TarsException("the adapter proxy is empty") if self.__consistentHashWeight is None or self.__checkConHashChange( self.__lastConHashPrxList): self.__updateConHashProxyWeighted() if len(self.__consistentHashWeight.nodes) > 0: conHashIndex = self.__consistentHashWeight.getNode(hashCode) if conHashIndex in self.__regAdapterProxyDict and self.__regAdapterProxyDict[ conHashIndex][ 1].activatestateinreg and self.__regAdapterProxyDict[ conHashIndex][1].checkActive(): self.__regAdapterProxyDict[conHashIndex][2] += 1 if conHashIndex in self.__adps: self.__adps[conHashIndex][2] += 1 elif conHashIndex in self.__iadps: self.__iadps[conHashIndex][2] += 1 return self.__regAdapterProxyDict[conHashIndex][1] else: if len(self.__adps) == 0: raise TarsException("the activate adapter proxy is empty") activeProxyList = self.__adps.items() actPrxSize = len(activeProxyList) while actPrxSize != 0: hashNum = hashCode % actPrxSize if activeProxyList[hashNum][1][1].checkActive(): self.__adps[activeProxyList[hashNum][0]][2] += 1 return self.__adps[activeProxyList[hashNum][0]][1] activeProxyList.pop(hashNum) actPrxSize -= 1 # 随机重连一个可用节点 adpPrx = self.__adps.items()[random.randint( 0, len(self.__adps))][1][1] adpPrx.checkActive() return None pass else: return self.__getHashProxyForNormal(hashCode)
def __getHashProxyForNormal(self, hashCode): tarsLogger.debug('AdapterProxyManager:getHashProxyForNormal') # self.__lock.acquire() lock = LockGuard(self.__newLock) regAdapterProxyList = sorted(self.__regAdapterProxyDict.items(), key=lambda item: item[0]) allPrxSize = len(regAdapterProxyList) if allPrxSize == 0: raise TarsException("the adapter proxy is empty") hashNum = hashCode % allPrxSize if regAdapterProxyList[hashNum][1][ 1].activatestateinreg and regAdapterProxyList[hashNum][1][ 1].checkActive(): epstr = regAdapterProxyList[hashNum][0] self.__regAdapterProxyDict[epstr][2] += 1 if epstr in self.__adps: self.__adps[epstr][2] += 1 elif epstr in self.__iadps: self.__iadps[epstr][2] += 1 return self.__regAdapterProxyDict[epstr][1] else: if len(self.__adps) == 0: raise TarsException("the activate adapter proxy is empty") activeProxyList = self.__adps.items() actPrxSize = len(activeProxyList) while actPrxSize != 0: hashNum = hashCode % actPrxSize if activeProxyList[hashNum][1][1].checkActive(): self.__adps[activeProxyList[hashNum][0]][2] += 1 return self.__adps[activeProxyList[hashNum][0]][1] activeProxyList.pop(hashNum) actPrxSize -= 1 # 随机重连一个可用节点 adpPrx = self.__adps.items()[random.randint(0, len( self.__adps))][1][1] adpPrx.checkActive() return None
def tars_invoke_async(self, cPacketType, sFuncName, sBuffer, context, status, callback): ''' @brief: TARS协议同步方法调用 @param cPacketType: 请求包类型 @type cPacketType: int @param sFuncName: 调用函数名 @type sFuncName: str @param sBuffer: 序列化后的发送参数 @type sBuffer: str @param context: 上下文件信息 @type context: ServantProxy.mapcls_context @param status: 状态信息 @type status: @param callback: 异步调用回调对象 @type callback: ServantProxyCallback的子类 @return: 响应报文 @rtype: ResponsePacket ''' tarsLogger.debug('ServantProxy:tars_invoke') req = RequestPacket() req.iVersion = ServantProxy.TARSVERSION req.cPacketType = cPacketType if callback else ServantProxy.TARSONEWAY req.iMessageType = ServantProxy.TARSMESSAGETYPENULL req.iRequestId = 0 req.sServantName = self.tars_name() req.sFuncName = sFuncName req.sBuffer = sBuffer req.iTimeout = self.tars_timeout() reqmsg = ReqMessage() reqmsg.type = ReqMessage.ASYNC_CALL if callback else ReqMessage.ONE_WAY reqmsg.callback = callback reqmsg.servant = self reqmsg.request = req reqmsg.begtime = time.time() rsp = None try: rsp = self.__invoke(reqmsg) except TarsException: raise except Exception: raise TarsException('ServantProxy::tars_invoke excpetion') if reqmsg.adapter: reqmsg.adapter.finishInvoke(False) return rsp
def __getWeightedProxy(self): tarsLogger.debug('AdapterProxyManager:getWeightedProxy') lock = LockGuard(self.__newLock) if len(self.__adps) == 0: raise TarsException("the activate adapter proxy is empty") if self.__update is True: self.__lastWeightedProxyData.clear() weightedProxyData = {} minWeight = (self.__adps.items()[0][1][0]).getWeight() for item in self.__adps.items(): weight = (item[1][0].getWeight()) weightedProxyData[item[0]] = (weight) if minWeight > weight: minWeight = weight if minWeight <= 0: addWeight = -minWeight + 1 for item in weightedProxyData.items(): item[1] += addWeight self.__update = False self.__lastWeightedProxyData = weightedProxyData weightedProxyData = self.__lastWeightedProxyData while len(weightedProxyData) > 0: total = sum(weightedProxyData.values()) rand = random.randint(1, total) temp = 0 for item in weightedProxyData.items(): temp += item[1] if rand <= temp: if self.__adps[item[0]][1].checkActive(): self.__adps[item[0]][2] += 1 return self.__adps[item[0]][1] else: weightedProxyData.pop(item[0]) break # 没有一个活跃的节点 # 随机重连一个可用节点 adpPrx = self.__adps.items()[random.randint( 0, len(self.__adps))][1][1] adpPrx.checkActive() return None
def getNode(self, key): """ 返回这个字符串应该对应的node,这里先求出字符串的hash值,然后找到第一个小于等于的虚拟节点,然后返回node 如果hash值大于所有的节点,那么用第一个虚拟节点 :param : hashNum or keyStr :return: """ keyStr = '' if isinstance(key, int): keyStr = "the keyStr is %d" % key elif isinstance(key, type('a')): keyStr = key else: raise TarsException("the hash code has wrong type") if self.__sortListForKey: key = self.__genKey(keyStr) for keyItem in self.__sortListForKey: if key <= keyItem: return self.__nodeDict[keyItem] return self.__nodeDict[self.__sortListForKey[0]] else: return None