/// <summary> /// 通过代理类发送消息到远程服务器 /// </summary> /// <typeparam name="TIn"></typeparam> /// <typeparam name="TOut"></typeparam> /// <param name="input"></param> /// <param name="serviceName"></param> /// <param name="FlowControlCfgKey"></param> /// <param name="pathName"></param> /// <returns></returns> public async Task<TOut> SendAsync<TIn, TOut>(TIn input, string serviceName, string flowControlCfgKey, string pathName) where TOut : class { try { var configure = await _configureManager.GetBreakerConfigure(flowControlCfgKey); //流量控制 var ipendpoint = await _flowControlCenter.GetFlowControlEndPointByServicePath(serviceName, configure, _customerInfo.Ip); if (ipendpoint != null) { var channelKey = await _clientProvider.CreateClient(ipendpoint); if (channelKey != null) { return await _clientProvider.SendMessage<TOut>(channelKey, ipendpoint, flowControlCfgKey, configure, serviceName, pathName, input); } else { _oxygenLogger.LogError($"远程调用通道创建失败:{ipendpoint.ToString()}"); //强制熔断当前节点 await _configureManager.ForcedCircuitBreakEndPoint(flowControlCfgKey, configure, ipendpoint); } } } catch (Exception e) { _oxygenLogger.LogError($"远程调用失败:{e.Message},堆栈跟踪:{e.StackTrace.ToString()}"); } return await Task.FromResult(default(TOut)); }
/// <summary> /// 从tcp管道接受消息 /// </summary> /// <param name="context"></param> /// <param name="message"></param> public override void ChannelRead(IChannelHandlerContext context, object message) { try { if (message is RpcGlobalMessageBase <object> ) { _hander?.Invoke((RpcGlobalMessageBase <object>)message); } } catch (Exception e) { _logger.LogError("客户端回调处理异常: " + e.Message); } }
/// <summary> /// 从tcp管道接受消息 /// </summary> /// <param name="context"></param> /// <param name="message"></param> public override async void ChannelRead(IChannelHandlerContext context, object message) { try { if (message is RpcGlobalMessageBase <object> ) { var localHanderResult = await _localProxyGenerator.Invoke((RpcGlobalMessageBase <object>) message); if (localHanderResult != null) { await context.WriteAsync(localHanderResult); } } } catch (Exception e) { _logger.LogError("服务端消息处理异常: " + e.Message); } }
/// <summary> /// 通过配置组装熔断策略 /// </summary> /// <param name="config"></param> /// <returns></returns> public IAsyncPolicy <T> BuildPolicy <T>(string key, ServiceConfigureInfo configure, IPEndPoint endpoint) { if (_lazyDefPolicy.Value.TryGetValue($"{key}{endpoint.ToString()}", out dynamic cachepolicy)) { return(cachepolicy as IAsyncPolicy <T>); } else { var address = configure.GetEndPoints().FirstOrDefault(x => x.GetEndPoint().Equals(endpoint)); //定义默认策略 IAsyncPolicy <T> defPolicy = Policy <T> .Handle <Exception>().FallbackAsync(async(CancellationToken cancelToken) => { //请求失败,更新配置节并进行回退 address.ThresholdBreakeTimes += 1; tmpReqTime.Value.TryGetValue($"{key}{endpoint.ToString()}", out List <DateTime> time); time = time ?? new List <DateTime>(); //若错误次数超过阈值或者阈值比例则触发熔断 if (address.ThresholdBreakeTimes >= configure.DefThresholdBreakeTimes || time.Count() == 0 || (time.Count() > 0 && (double)configure.DefThresholdBreakeRatePerSec >= (double)address.ThresholdBreakeTimes / (double)time.Count(y => y >= DateTime.Now.AddSeconds(1)))) { _logger.LogError($"地址{address.GetEndPoint().ToString()}超过熔断阈值,强制熔断。详细信息{{当前IP熔断次数:{address.ThresholdBreakeTimes},成功请求次数:{time.Count()},熔断比率{(double)address.ThresholdBreakeTimes / (double)time.Count(y => y >= DateTime.Now.AddSeconds(1))}}}"); address.BreakerTime = DateTime.Now; } _logger.LogError($"地址{address.GetEndPoint().ToString()}请求出错,执行回退"); return(default);
/// <summary> /// 序列化 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="input"></param> /// <returns></returns> public byte[] Serializes <T>(T input) { if (input == null) { return(default(byte[])); } try { return(MessagePackSerializer.Serialize(input)); } catch (Exception e) { _logger.LogError($"序列化对象失败:{e.Message}"); } return(default(byte[])); }
/// <summary> /// 通过强类型创建代理 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public async Task <T> CreateProxy <T>() where T : class { if (_container.TryResolve(typeof(T), out var instance)) { return(instance as T); } else { var className = $"{typeof(T).Name.Substring(1, typeof(T).Name.Length - 1)}_ProxyClient"; var type = GetProxtClient(className); if (type != null) { return(Activator.CreateInstance(type) as T); } else { _oxygenLogger.LogError($"未找到远程代理实例:{typeof(T).Name}"); } } return(await Task.FromResult(default(T))); }
/// <summary> /// 根据服务名返回IP地址 /// </summary> /// <param name="serviceName"></param> /// <param name="flowControlCfgKey"></param> /// <param name="clientIp"></param> /// <returns></returns> public async Task <IPEndPoint> GetFlowControlEndPointByServicePath(string serviceName, ServiceConfigureInfo configure, IPEndPoint clientIp) { //根据服务返回健康地址 var healthNode = await _registerCenter.GetServieByName(serviceName); if (healthNode != null && healthNode.Any()) { if (configure != null) { //更新健康节点和缓存同步 configure.ReflushConfigureEndPoint(healthNode); //若配置流控,则进行熔断和限流检测 var point = await _breaker.CheckCircuitByEndPoint(configure, clientIp); if (point != null) { //将有效地址的熔断数据清空 configure.CleanBreakTimes(); return(point); } } else { //如果当前服务并未配置流控,则直接负载均衡返回节点 return(_endPointConfigure.GetServieByLoadBalane(healthNode, clientIp, LoadBalanceType.IPHash)); } } else { //删除所有地址并同步 if (configure != null) { configure.RemoveAllNode(); } _logger.LogError($"没有找到健康的服务节点:{serviceName}"); } return(null); }
/// <summary> /// 检查服务断路状态 /// </summary> /// <param name="pathName"></param> /// <param name="serviceInfo"></param> /// <param name="addr"></param> /// <returns></returns> public async Task <IPEndPoint> CheckCircuitByEndPoint(ServiceConfigureInfo configure, IPEndPoint clientEndPoint) { //根据配置抛弃断路状态地址 var useAddr = configure.GetEndPoints().Where(x => x.BreakerTime == null || (x.BreakerTime != null && x.BreakerTime.Value.AddSeconds(configure.DefBreakerRetryTimeSec) <= DateTime.Now)).ToList(); //若全部熔断 if (!useAddr.Any()) { _logger.LogError("服务被熔断,无法提供服务"); return(null); } else { //负载均衡有效地址 var addr = _endPointConfigure.GetServieByLoadBalane(useAddr, clientEndPoint, LoadBalanceType.IPHash, configure); //初始化令牌桶并判断是否限流 _tokenBucket.InitTokenBucket(configure.DefCapacity, configure.DefRateLimit); if (await _tokenBucket.Grant(configure)) { return(addr); } return(null); } }
/// <summary> /// 消息分发处理 /// </summary> /// <param name="message"></param> /// <returns></returns> public async Task <RpcGlobalMessageBase <object> > Invoke(RpcGlobalMessageBase <object> message) { if (message == null) { _logger.LogError($"订阅者消息分发不能为空消息"); return(default);