public static void Register(string programNamespace) { ServicePointManager.SetTcpKeepAlive(true, 5 * 60 * 1000, 5 * 60 * 1000); // 设置系统socket如果5分钟没有交互,需要发送心跳包,进行保活 //初始化线程池最小大小 为 1000 ThreadPool.GetMinThreads(out var wt, out var ct); if (wt < 1000 || ct < 1000) { ThreadPool.SetMinThreads(Math.Max(wt, 1000), Math.Max(ct, 1000)); } var rpcServer = ServerSetting.GetRpcServer(); string assPath = string.IsNullOrEmpty(programNamespace) ? rpcServer.AssemblyPath : programNamespace.EndsWith(".dll") ? programNamespace : programNamespace + ".dll"; if (rpcServer != null) { SuperGMSServerConfig s = new SuperGMSServerConfig() { Port = rpcServer.Port, ServerType = rpcServer.ServerType, AssemblyPath = assPath, Pool = rpcServer.Pool, Ip = rpcServer.Ip, TimeOut = rpcServer.TimeOut, Enable = rpcServer.Enable, PortList = rpcServer.PortList, }; Register(s); } logger.LogInformation($"ThreadPool.GetMinThreads: worker-{Math.Max(wt, 1000)}; io-{Math.Max(ct, 1000)}"); }
public static void Register(SuperGMSServerConfig config) { switch (config.ServerType) { default: case ServerType.Thrift: server = new ThriftRpcServer(); break; case ServerType.Grpc: break; case ServerType.WCF: break; case ServerType.TaskWorker: server = new TaskWorker.TaskWorker(); break; case ServerType.HttpWebApi: server = new WebApiServer(); break; } if (server == null) { } else { // 开启线程去监听,要不当前主线程会被hang住 Thread th = new Thread(new ThreadStart(() => { server.RpcServerRegister(config); })); th.IsBackground = true; th.Name = string.Format("rpc_thread_{0}", config.AssemblyPath); th.Start(); Console.CancelKeyPress += Console_CancelKeyPress; } }
/// <summary> /// 注册服务 /// </summary> /// <param name="server">服务配置</param> public void RpcServerRegister(SuperGMSServerConfig server) { try { distributer = new RpcDistributer(server); // 这里会初始化serverSetting和zk连接以及其他配置 // 注册zk登记自己(包括serverName,ip,port,pool) server.ServerName = distributer.ShortName; // 兼容集中配置 if (server.PortList != null && server.PortList.ContainsKey(server.ServerName)) { server.Port = server.PortList[server.ServerName]; ServerSetting.UpdateRpcPort(server.Port); } bool IsExit = false; // 要先初始化系统相关组件之后才能注册Rpc端口,要不请·求上来了,还没有初始化其他的,会有问题 // 去zk注册自己 if (ServerSetting.ConfigCenter.ConfigType == ConfigType.Zookeeper) { Task.Run(() => { Random r = new Random(); // rpc注册socket是阻塞的,只能提前通过线程注册, 等待1s 再注册路由,这个过程中,如果rpc端口不成功,将会撤销资源退出,这个注册也就失败了,防止先注册路由,然后再rpc注册异常,导致路由瞬间抖动,造成瞬间无效广播; Thread.Sleep(r.Next(1500, 2500)); // 随机等待在1s--2s之间吧,防止集群一瞬间同时重启,容易形成广播风暴,形成雪崩; if (IsExit) { return; } ServerSetting.RegisterRouter(server.ServerName, server.Ip, server.Port, ServerSetting.GetRpcServer().Enable, server.TimeOut); logger.LogInformation($"\r\n服务名:{server.ServerName},开始监听Ip是:{server.Ip},端口是:{server.Port}\r\n*******************▄︻┻┳══━一zookeeper路由注册成功,系统启动成功!▄︻┻┳══━一*******************"); }); } else { Task.Run(() => { Thread.Sleep(1500); if (IsExit) { return; } logger.LogInformation($"\r\n服务名:{server.ServerName},开始监听Ip是:{server.Ip},端口是:{server.Port}\r\n*******************▄︻┻┳══━一启用本地配置,系统启动成功!▄︻┻┳══━一*******************"); }); } ServerRegister(server); // 底层通讯和业务进行绑定 // 只有socket才会阻塞 if (server.ServerType == ServerType.Thrift || server.ServerType == ServerType.Grpc) { IsExit = true; // 通知所有注册方,停止注册,系统要撤销所有资源了,防止其他异常,优雅一点点,不能太暴力 logger.LogWarning($"\r\n rpc端口监听异常退出:{server.ServerName}{server.Port}{server.AssemblyPath}" + " \r\n time=" + DateTime.Now.ToString("yy-MM-dd HH:mm:ss:ffff")); if (ServerSetting.ConfigCenter.ConfigType == ConfigType.Zookeeper) { ZookeeperManager.ClearRouter(server.ServerName, server.Ip); } // rpc监听是hold住当前线程的,因为底层吞掉异常了,跑到这里来就说明异常了,要彻底释放 // 让他等一下,把日志写完 System.Threading.Thread.Sleep(1000); // 如果启动失败,一定要彻底清理退出,因为在线程中,只能这样,要不只是线程退出,主程序还运行 Environment.Exit(0); } } catch (Exception ex) { logger.LogCritical(ex, "\r\n Error 服务异常退出 " + DateTime.Now.ToString("yy-MM-dd HH:mm:ss:ffff")); // 让他等一下,把日志写完 System.Threading.Thread.Sleep(1000); // 如果启动失败,一定要彻底清理退出,因为在线程中,只能这样,要不只是线程退出,主程序还运行 Environment.Exit(0); } }
/// <summary> /// 注册服务 /// </summary> /// <param name="server">服务配置</param> protected abstract void ServerRegister(SuperGMSServerConfig server);