集群负载均衡日志
大石头 authored at 2019-10-15 07:58:01
3.30 KiB
X
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using NewLife.Collections;
using NewLife.Log;
using NewLife.Net;

namespace NewLife.Remoting
{
    /// <summary>客户端单连接故障转移集群</summary>
    public class ClientSingleCluster : ICluster<String, ISocketClient>
    {
        /// <summary>最后使用资源</summary>
        public KeyValuePair<String, ISocketClient> Current { get; private set; }

        /// <summary>服务器地址列表</summary>
        public Func<IEnumerable<String>> GetItems { get; set; }

        /// <summary>创建回调</summary>
        public Func<String, ISocketClient> OnCreate { get; set; }

        /// <summary>打开</summary>
        public virtual Boolean Open() => true;

        /// <summary>关闭</summary>
        /// <param name="reason">关闭原因。便于日志分析</param>
        /// <returns>是否成功</returns>
        public virtual Boolean Close(String reason) => _Client == null ? false : _Client.Close(reason);

        private ISocketClient _Client;
        /// <summary>从集群中获取资源</summary>
        /// <returns></returns>
        public virtual ISocketClient Get()
        {
            var tc = _Client;
            if (tc != null && tc.Active && !tc.Disposed) return tc;
            lock (this)
            {
                tc = _Client;
                if (tc != null && tc.Active && !tc.Disposed) return tc;

                // 释放旧对象
                tc.TryDispose();

                return _Client = CreateClient();
            }
        }

        /// <summary>归还</summary>
        /// <param name="value"></param>
        public virtual Boolean Put(ISocketClient value) => true;

        /// <summary>Round-Robin 负载均衡</summary>
        private Int32 _index = -1;

        /// <summary>为连接池创建连接</summary>
        /// <returns></returns>
        protected virtual ISocketClient CreateClient()
        {
            // 遍历所有服务,找到可用服务端
            var svrs = GetItems().ToArray();
            if (svrs == null || svrs.Length == 0) throw new InvalidOperationException("没有设置服务端地址Servers");

            var idx = Interlocked.Increment(ref _index);
            Exception last = null;
            for (var i = 0; i < svrs.Length; i++)
            {
                // Round-Robin 负载均衡
                var k = (idx + i) % svrs.Length;
                var svr = svrs[k];
                try
                {
                    WriteLog("集群转移:{0}", svr);

                    var client = OnCreate(svr);
                    client.Open();

                    // 设置当前资源
                    Current = new KeyValuePair<String, ISocketClient>(svr, client);

                    return client;
                }
                catch (Exception ex)
                {
                    last = ex;
                }
            }

            throw last;
        }

        #region 日志
        /// <summary>日志</summary>
        public ILog Log { get; set; } = Logger.Null;

        /// <summary>写日志</summary>
        /// <param name="format"></param>
        /// <param name="args"></param>
        public void WriteLog(String format, params Object[] args) => Log?.Info(format, args);
        #endregion
    }
}