/// <summary> /// 释放连接回到连接池,回到连接池的连接都是可用的, /// 连接只有在用的时候才会检查状态 /// </summary> /// <param name="client"> 客户端</param> public static void ReleaseClient(ISuperGMSRpcClient client) { if (client.Item.Pool > 0) { client.Close(); return;// 关闭连接池,连接不在放回,直接释放掉 } string key = GetConnectionPoolKey(client.Item.Ip, client.Item.Port); lock (root) { if (ConnectionPools.ContainsKey(key)) { ConnectionPools[key] .Add(new ComboxClass <DateTime, ISuperGMSRpcClient> { V1 = DateTime.Now, V2 = client }); } else { List <ComboxClass <DateTime, ISuperGMSRpcClient> > cls = new List <ComboxClass <DateTime, ISuperGMSRpcClient> >(1) { new ComboxClass <DateTime, ISuperGMSRpcClient> { V1 = DateTime.Now, V2 = client }, }; ConnectionPools.Add(key, cls); } } }
/// <summary> /// 获取一个到指定服务器的连接 /// </summary> /// <param name="item">配置信息</param> /// <returns>rpc连接</returns> public static ISuperGMSRpcClient GetClient(ClientItem item) { if (item.Pool > 0) { return(Register(item)); // 0,表示开启连接池(默认),1,表示关闭连接池 } string key = GetConnectionPoolKey(item.Ip, item.Port); lock (root) { if (!runing) { Check(); runing = true; } if (ConnectionPools.ContainsKey(key)) { List <ComboxClass <DateTime, ISuperGMSRpcClient> > cls = ConnectionPools[key]; if (cls.Count > 0) { // 从队列中取一个连接,并移除掉,防止二次分配 ISuperGMSRpcClient c = cls[0].V2; cls.Remove(cls[0]); return(c); } } } // 说明没有取到,这里需要新建,新建的直接返回,不能放到连接池,只有用完的才会放回去 return(Register(item)); }
/// <summary> /// 新建一个连接 /// </summary> /// <param name="item">连接配置</param> /// <returns>连接</returns> private static ISuperGMSRpcClient Register(ClientItem item) { try { ISuperGMSRpcClient client = null; switch (item.ServerType) { case ServerType.Thrift: client = new ThriftClient(item); break; case ServerType.HttpWebApi: client = new WebApiClient(item); break; default: throw new Exception($"ClientConnectionManager.Register(), ClientItem.ServerType:'{item.ServerType}' is invalid"); } return(client); } catch (Exception ex) { logger.LogError(ex, $"ClientConnectionManager.register.Error,ServerInfo={item.ToString()}"); return(null); } }
/// <summary> /// 代理层使用 /// </summary> /// <param name="args">参数</param> /// <param name="url">前端要求将M值体现在路径上,接入层自己来做个转换处理</param> /// <returns>string,参数</returns> internal static (string c, Result <object> r) Send(Args <object> args, string url) { var serverName = ""; ClientServer cServer = null; Result <object> rr = new Result <object>(); EventId eventId = new EventId(0, args.rid); try { // 这里需要重构,统一做成一个Fliter ClientType ct = ClientTypeParser.Parser(args.ct); switch (ct) { case ClientType.InnerRpc: // 需要拦截 throw new Exception("你想干什么?"); case ClientType.App: case ClientType.Web: // 需要要做来源ip和reffer网站 case ClientType.Unkunwn: // 未知的和第三方都必须验证appkey case ClientType.ThirdPart: break; } string[] motheds = url.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (motheds == null || motheds.Length < 2) { rr.msg = "HttpProxy.Error:Request args Error,Server name Could not found rid=" + args.rid; rr.c = 503; rr.v = default(object); } else { #region 重构,获取路由配置 string server = motheds[motheds.Length - 2]; serverName = server; args.m = motheds[motheds.Length - 1]; int error = 0; gotoHere: readerWriterLock.AcquireReaderLock(80); ClientItem cItem = null; try { string s = server.ToLower(); if (cls.ContainsKey(s)) { cServer = cls[s]; var clients = cServer.Client; int idx = 0; switch (cServer.RouterType) { case RouterType.Hash: idx = RouterManager.GetPool(args.uri); break; case RouterType.Polling: idx = RouterManager.GetPolling(0, clients.Length); break; default: case RouterType.Random: idx = RouterManager.GetRandom(0, clients.Length); break; } cItem = clients[idx]; } else { StatusCode cc = new StatusCode(402, $"HttpProxy.Error:server :{server} not found rid={args.rid}"); rr.c = cc.code; rr.msg = cc.msg; rr.v = default(object); logger.LogError(eventId, new LogInfo() { ServiceName = serverName, ApiName = args.m, CreatedBy = "httpProxy", TransactionId = args.rid, UseChain = JsonConvert.SerializeObject(args.Headers), CodeMsg = rr.msg, Code = rr.c, Desc = $"HttpProxy.Error:server :{server} not found rid={args.rid}", }.ToString()); } } catch (Exception e) { string msg = $"获取路由信息异常{server}{e.Message} rid = {args.rid}"; StatusCode cc = new StatusCode(502, msg); rr.c = cc.code; rr.msg = cc.msg; rr.v = default(object); logger.LogError(eventId, e, $"获取Server:{server}路由信息异常"); } finally { if (readerWriterLock.IsReaderLockHeld) { readerWriterLock.ReleaseReaderLock(); } } #endregion 重构,获取路由配置 #region 发送请求 if (cItem == null) { string msg = $"HttpProxy.Error:无法获取路由信息:{server} rid = {args.rid}"; StatusCode cc = new StatusCode(503, msg); rr.c = cc.code; rr.msg = cc.msg; rr.v = default(object); logger.LogError(eventId, new LogInfo { ServiceName = server, ApiName = args.m, CreatedBy = "httpProxy", TransactionId = args.rid, Desc = msg, Code = rr.c, CodeMsg = rr.msg, UseChain = JsonConvert.SerializeObject(args.Headers), }.ToString()); } else { cItem.Url = args.m; var jSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; jSetting.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; jSetting.DateFormatString = "yyyy-MM-dd HH:mm:ss"; var msg = JsonConvert.SerializeObject(args, jSetting); logger.LogInformation(eventId, new LogInfo { ServiceName = server, ApiName = args.m, CreatedBy = "httpProxy", TransactionId = args.rid, Desc = string.Format("开始访问服务器:server={0},ip={1},port={2},args={3},rid={4}", cServer.ServerName, cItem.Ip, cItem.Port, msg, args.rid), Code = StatusCode.OK.code, CodeMsg = StatusCode.OK.msg, UseChain = JsonConvert.SerializeObject(args.Headers), }.ToString()); using (ISuperGMSRpcClient rpcClient = ClientConnectionManager.GetClient(cItem)) { string result = null; if (rpcClient.Send(msg, args.m, out result)) { var resultObj = JsonConvert.DeserializeObject <Result <object> >(result); logger.LogInformation(eventId, new LogInfo { ServiceName = server, ApiName = args.m, CreatedBy = "httpProxy", TransactionId = args.rid, Desc = string.Format( "服务器返回:server={0},ip={1},port={2},result={3},rid={4}", cServer.ServerName, cItem.Ip, cItem.Port, result, args.rid), Code = resultObj.c, CodeMsg = resultObj.msg, UseChain = JsonConvert.SerializeObject(args.Headers), }.ToString()); return(result, resultObj); // 直接返回结果 } } // 走到这里就说明失败了 error += 1; System.Threading.Thread.Sleep(100); // 重试3次 if (error < 3) { goto gotoHere; // 失败了就重新去找一个连接重试 } // rr = new Result<R> { v = default(R) }; // 要知道请求的rid这里只能反解出来 StatusCode ccc = new StatusCode(502, "HttpProxy.Error:无法访问远程服务器 rid=" + args.rid); rr = new Result <object>() { c = ccc.code, msg = ccc.msg, rid = args.rid, uri = args.uri, v = null, }; } #endregion 发送请求 } } catch (Exception ex) { StatusCode cc = new StatusCode(501, "HttpProxy.Error:" + ex.Message); rr.c = cc.code; rr.msg = cc.msg; rr.v = default(object); logger.LogError(eventId, ex, new LogInfo() { ServiceName = serverName, ApiName = args.m, CreatedBy = "httpProxy", TransactionId = args.rid, UseChain = JsonConvert.SerializeObject(args.Headers), CodeMsg = rr.msg, Code = rr.c, Desc = "GrantRpcClientManager.Send<R, A>.error", }.ToString()); } var js = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; js.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; js.DateFormatString = "yyyy-MM-dd HH:mm:ss"; var rst = JsonConvert.SerializeObject(rr, js); logger.LogInformation(eventId, new LogInfo() { ServiceName = serverName, ApiName = args.m, CreatedBy = "httpProxy", TransactionId = args.rid, UseChain = JsonConvert.SerializeObject(args.Headers), CodeMsg = rr.msg, Code = rr.c, Desc = string.Format("返回结果是:{0}", rst), }.ToString()); return(rst, rr); }
/// <summary> /// 客户端Rpc调用 /// </summary> /// <typeparam name="R">R</typeparam> /// <typeparam name="A">A</typeparam> /// <param name="server">server</param> /// <param name="m">m</param> /// <param name="args">args</param> /// <param name="code">code</param> /// <returns>RR</returns> public static R Send <A, R>(string server, string m, A args, RpcContext context, out StatusCode code) { Args <A> a = new Args <A>() { ct = ClientType.InnerRpc.ToString(), // 只有内部的rpc请求才能如此标记 cv = string.Empty, m = m, v = args, rid = Guid.NewGuid().ToString("N"), Headers = new Dictionary <string, HeaderValue>(), }; EventId eventId = new EventId(0, a.rid); try { #region 构造路由 // 添加自己的头信息 string sk = $"{ServerSetting.AppName}(idx:{ServerSetting.Pool})_{ServiceEnvironment.ComputerName}_{ServiceEnvironment.ComputerAddress}"; string key = $"{ServerSetting.AppName}_{HeaderValue.INNERIP}"; // 强制在一个请求链上一个微服务只能被调用一次,防止出现来回循环调用的情况出现 a.Headers.TryAdd(key, new HeaderValue(sk, HeaderValue.INNERIP, ServiceEnvironment.ComputerAddress)); // 原样透传rpcContext if (context != null) { a.ct = string.IsNullOrEmpty(context.Args.ct) ? a.ct : context.Args.ct; a.cv = string.IsNullOrEmpty(context.Args.cv) ? a.cv : context.Args.cv; a.rid = string.IsNullOrEmpty(context.Args.rid) ? a.rid : context.Args.rid; a.lg = string.IsNullOrEmpty(context.Args.lg) ? a.lg : context.Args.lg; a.tk = string.IsNullOrEmpty(context.Args.tk) ? a.tk : context.Args.tk; a.uri = string.IsNullOrEmpty(context.Args.uri) ? a.uri : context.Args.uri; if (context.Headers != null && context.Headers.Any()) { foreach (var item in context.Headers) { a.Headers.TryAdd(item.Key, item.Value); } } } int error = 0; gotoHere: ClientServer cServer = null; ClientItem cItem = null; Result <R> rr = new Result <R>(); try { readerWriterLock.AcquireReaderLock(80); string s = server.ToLower(); if (cls.ContainsKey(s)) { cServer = cls[s]; var clients = cServer.Client; int idx = 0; switch (cServer.RouterType) { case RouterType.Hash: idx = RouterManager.GetPool(a.uri); break; case RouterType.Polling: idx = RouterManager.GetPolling(0, clients.Length); break; default: case RouterType.Random: idx = RouterManager.GetRandom(0, clients.Length); break; } cItem = clients[idx]; } else { StatusCode cc = new StatusCode(402, $"server :{server} not found rid = {a.rid}"); rr.c = cc.code; rr.msg = cc.msg; rr.v = default(R); logger.LogError(eventId, new LogInfo() { ServiceName = server, ApiName = a.m, CreatedBy = "FrameWork", TransactionId = a.rid, UseChain = JsonConvert.SerializeObject(a.Headers), CodeMsg = rr.msg, Code = rr.c, Desc = $"server :{server} not found rid = {a.rid}", }.ToString()); } } catch (Exception e) { string msg = $"获取路由信息异常{server}{e.Message} rid={a.rid}"; StatusCode cc = new StatusCode(502, msg); rr.c = cc.code; rr.msg = cc.msg; rr.v = default(R); logger.LogError(eventId, new LogInfo() { ServiceName = server, ApiName = a.m, CreatedBy = "FrameWork", TransactionId = a.rid, UseChain = JsonConvert.SerializeObject(a.Headers), CodeMsg = rr.msg, Code = rr.c, Desc = $"获取路由信息异常{server}{e.Message} rid={a.rid}", }.ToString()); // GrantLogTextWriter.Write(new Exception(msg, e)); } finally { if (readerWriterLock.IsReaderLockHeld) { readerWriterLock.ReleaseReaderLock(); } } #endregion 构造路由 #region 发送请求 var jSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; jSetting.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; jSetting.DateFormatString = "yyyy-MM-dd HH:mm:ss"; var sendValue = JsonConvert.SerializeObject(a, jSetting); if (cItem == null) { code = new StatusCode(403, $"{server}的路由信息无法找到 rid={a.rid}"); rr.v = default(R); } else { logger.LogInformation(eventId, $"Client发送请求\r\n\tserver={cServer.ServerName},ip={cItem.Ip},port={cItem.Port}\r\n\targs={sendValue}"); bool isOk = false; using (ISuperGMSRpcClient rpcClient = ClientConnectionManager.GetClient(cItem)) { string result = null; if (rpcClient.Send(sendValue, m, out result)) { rr = JsonConvert.DeserializeObject <Result <R> >(result); code = new StatusCode(rr.c, rr.msg); isOk = true; } } if (!isOk) { error += 1; System.Threading.Thread.Sleep(100); // 重试3次 if (error < 3) { goto gotoHere; // 失败了就重新去找一个连接重试,如果是单台短时间内重试就没有意义了 } rr = new Result <R> { v = default(R) }; code = new StatusCode(501, "client_error无法访问远程服务器 rid=" + a.rid); } else { code = new StatusCode(rr.c, rr.msg); } } logger.LogInformation(eventId, $"Client返回结果\r\n\tServiceName:{server},ApiName:{a.m},Code:{code.code},CodeMsg:{code.msg},\r\n\tUseChain{JsonConvert.SerializeObject(a.Headers)}\r\n\tResult:{JsonConvert.SerializeObject(rr)}"); return(rr.v); #endregion 发送请求 } catch (Exception e) { code = new StatusCode(504, $"未知异常:{e.Message}"); logger.LogError(eventId, e, $"未知异常"); return(default(R)); } }