using CYQ.Data.Tool; using System; using System.Collections.Generic; using System.Threading; namespace CYQ.Data.Cache { /// /// The SocketPool encapsulates the list of PooledSockets against one specific host, and contains methods for /// acquiring or returning PooledSockets. /// internal partial class HostNode : IDisposable { //用于验证权限的委托事件。 internal delegate bool OnAfterSocketCreateDelegate(MSocket socket); internal event OnAfterSocketCreateDelegate OnAfterSocketCreateEvent; #region 可对外的属性 //Public variables and properties public readonly string Host; /// /// 扩展属性:如果链接后需要验证密码(如Redis可设置密码) /// public string Password; //Debug variables and properties public int NewSockets = 0; public int CloseSockets = 0; public int TimeoutFromSocketPool = 0; public int FailedNewSockets = 0; public int ReusedSockets = 0; public int DeadSocketsInPool = 0; public int DeadSocketsOnReturn = 0; public int Acquired = 0; /// /// 最后的错误信息。 /// public string Error; /// /// 当前 Socket 池的可用数量。 /// public int Poolsize { get { return socketQueue.Count; } } /// /// 主机节点是不是挂了。 /// public bool IsEndPointDead = false; public DateTime DeadEndPointRetryTime; #endregion /// /// 备份的Socket池,如果某主机挂了,在配置了备份的情况下,会由备份Socket池提供服务。 /// // public HostNode HostNodeBak; /// /// Socket的挂科时间。 /// private DateTime socketDeadTime = DateTime.MinValue; public int MaxQueue { get { return hostServer.ServerType == CacheType.Redis ? AppConfig.Redis.MaxSocket : AppConfig.MemCache.MaxSocket; } } /// /// 超出最大链接后的等待时间。 /// public int MaxWait { get { return hostServer.ServerType == CacheType.Redis ? AppConfig.Redis.MaxWait : AppConfig.MemCache.MaxWait; } } public int minQueue = 1; /// /// If the host stops responding, we mark it as dead for this amount of seconds, /// and we double this for each consecutive failed retry. If the host comes alive /// again, we reset this to 1 again. /// private int deadEndPointSecondsUntilRetry = 1; private const int maxDeadEndPointSecondsUntilRetry = 60; private HostServer hostServer; /// /// 主机服务。 /// public HostServer HostServer { get { return hostServer; } } private Queue socketQueue = new Queue(32); internal HostNode(HostServer hostServer, string host) { this.hostServer = hostServer; string[] items = host.Split('-'); Host = items[0].Trim(); if (items.Length > 1) { Password = items[1].Trim(); } } /// /// 从队列获取数据,并可能进行等待。 /// /// /// private MSocket GetFromQueue(int wait) { //Do we have free sockets in the pool? //if so - return the first working one. //if not - create a new one. int count = 0; while (true) { count++; if (socketQueue.Count > 0) { MSocket mSocket = null; lock (socketQueue) { if (socketQueue.Count > 0) { mSocket = socketQueue.Dequeue(); } } if (mSocket != null) { if (mSocket.IsAlive) { Interlocked.Increment(ref ReusedSockets); return mSocket; } else { Interlocked.Increment(ref DeadSocketsInPool); Interlocked.Increment(ref CloseSockets); return null; } } } if (count > wait) { return null; } Thread.Sleep(1); } } /// /// Gets a socket from the pool. /// If there are no free sockets, a new one will be created. If something goes /// wrong while creating the new socket, this pool's endpoint will be marked as dead /// and all subsequent calls to this method will return null until the retry interval /// has passed. /// 这个方法扩展(备份链接池) /// internal MSocket Acquire() { if (IsEndPointDead) { return null; } //If we know the endpoint is dead, check if it is time for a retry, otherwise return null. //检测当前是否挂科,如果是(15分钟内),由备份服务器提供服务 //if (socketDeadTime.AddMinutes(15) >= DateTime.Now && HostNodeBak != null) //{ // return HostNodeBak.Acquire(); //} //else //{ Interlocked.Increment(ref Acquired); //} //已经生产超过最大队列值 MSocket socket = GetFromQueue(0); if (socket != null) { return socket; } //提前检测,少进锁 if (NewSockets - CloseSockets >= MaxQueue) { //Try to create a new socket. On failure, mark endpoint as dead and return null. socket = GetFromQueue(MaxWait); if (socket != null) { return socket; } Interlocked.Increment(ref TimeoutFromSocketPool); return null; } //加锁,避免并发瞬时产生太多链接,浪费资源 lock (this) { if (NewSockets - CloseSockets < MaxQueue) { //If we know the endpoint is dead, check if it is time for a retry, otherwise return null. if (IsEndPointDead) { return null; } socket = new MSocket(this, Host); if (socket.IsAlive) { Interlocked.Increment(ref NewSockets);//先处理计数器 } else { Interlocked.Increment(ref FailedNewSockets);//先处理计数器 AddToDeadPool(); } } } if (socket == null) { if (NewSockets - CloseSockets >= MaxQueue) { //Try to create a new socket. On failure, mark endpoint as dead and return null. socket = GetFromQueue(MaxWait); if (socket != null) { return socket; } Interlocked.Increment(ref TimeoutFromSocketPool); } return null; } if (socket.IsAlive) { //不抛异常,则正常链接。 if (OnAfterSocketCreateEvent != null) { OnAfterSocketCreateEvent(socket); } return socket; } else { Log.Write("Error connecting to: " + Host, LogType.Cache); return null; } } /// /// Returns a socket to the pool. /// If the socket is dead, it will be destroyed. /// If there are more than MaxPoolSize sockets in the pool, it will be destroyed. /// If there are less than MinPoolSize sockets in the pool, it will always be put back. /// If there are something inbetween those values, the age of the socket is checked. /// If it is older than the SocketRecycleAge, it is destroyed, otherwise it will be /// put back in the pool. /// internal void Return(MSocket socket) { //If the socket is dead, destroy it. if (!socket.IsAlive || hasDisponse) { Interlocked.Increment(ref DeadSocketsOnReturn); Interlocked.Increment(ref CloseSockets); socket.Close(); } else { //Clean up socket socket.Reset(); //Check pool size. if (socketQueue.Count >= MaxQueue) { //If the pool is full, destroy the socket. Interlocked.Increment(ref CloseSockets); socket.Close(); } else if (socketQueue.Count > minQueue && socket.CreateTime.AddMinutes(10) < DateTime.Now) { //socket 服务超过半小时的,也可以休息了,只保留最底个数。 //If we have more than the minimum amount of sockets, but less than the max, and the socket is older than the recycle age, we destroy it. Interlocked.Increment(ref CloseSockets); socket.Close(); } else { //Put the socket back in the pool. lock (socketQueue) { socketQueue.Enqueue(socket); } } } } /// /// 线程池里重试链接。 /// /// internal bool TryConnection() { if (DateTime.Now > DeadEndPointRetryTime) { MSocket socket = new MSocket(this, Host); if (socket.IsAlive) { IsEndPointDead = false; deadEndPointSecondsUntilRetry = 1; //Reset retry timer on success. if (OnAfterSocketCreateEvent != null) { OnAfterSocketCreateEvent(socket);//身份验证 } Return(socket);//不浪费,丢到池里重用。 return true; } else { //Retry in 1 minutes DeadEndPointRetryTime = DateTime.Now.AddSeconds(deadEndPointSecondsUntilRetry); if (deadEndPointSecondsUntilRetry < maxDeadEndPointSecondsUntilRetry) { deadEndPointSecondsUntilRetry += 1; //Double retry interval until next time } } } return false; } static bool isTaskDoing = false; /// /// 添加故障节点 /// /// public void AddToDeadPool() { if (!IsEndPointDead) { IsEndPointDead = true; socketDeadTime = DateTime.Now; if (!deadNode.ContainsKey(Host)) { deadNode.Add(Host, this); } if (!isTaskDoing) { lock (deadNode) { isTaskDoing = true; ThreadBreak.AddGlobalThread(new ParameterizedThreadStart(DoHostNodeTask)); } } } } #region IDisposable 成员 bool hasDisponse = false; public void Dispose() { hasDisponse = true; while (socketQueue.Count > 0) { socketQueue.Dequeue().Close(); } } #endregion } internal partial class HostNode { /// /// 已故障节点 /// static MDictionary deadNode = new MDictionary(); /// /// 线程检测已故障节点。 /// /// static void DoHostNodeTask(object threadID) { while (true) { Thread.Sleep(1000); if (deadNode.Count > 0) { List keys = deadNode.GetKeys(); foreach (string key in keys) { if (deadNode[key].TryConnection()) { deadNode.Remove(key); } } } } } } }