Esempio n. 1
0
        public virtual Server Choose(LoadBalancerRoute route)
        {
            if (route == null || route.ServerGroups.IsNullOrEmpty())
            {
                return(null);
            }

            InternalBuildLoadBalanceItems(route);
            ServerGroup serverGroup = null;

            for (int i = 0; i < serverGroups.Count; i++)
            {
                serverGroup = roundRobinAlgorithm.Choose(serverGroups);
                if (serverGroup.AvailableServers.Length > 0)
                {
                    break;
                }
            }
            if (serverGroup == null)
            {
                return(null);
            }

            var serverContext = serverContexts.GetOrAdd(serverGroup.GroupId, key => new RoundRobinContext(serverGroup));

            return(serverContext.Choose());
        }
Esempio n. 2
0
        private bool CheckHealth(LoadBalancerRoute route)
        {
            bool      statusChanged = false;
            Stopwatch watch         = Stopwatch.StartNew();
            var       additionInfo  = _loadBalancerContext.AdditionalInfo.Copy().With("RouteId", route.RouteId);

            var servers = route.Servers;

            if (servers.Length == 0)
            {
                return(false);
            }

            if (route.AvailableServers.Length == 0)
            {
                string message = "There is no available server in the list. Need check health.";
                _logger.Warn(message, additionInfo);
            }

            int checkedCount = 0, availableCount = 0;

            foreach (Server server in servers)
            {
                try
                {
                    bool isAlive = server.IsAlive;
                    if (isAlive != CheckHealth(route, server))
                    {
                        statusChanged = true;
                    }
                    if (server.IsAlive)
                    {
                        ++availableCount;
                    }
                    ++checkedCount;
                }
                catch (Exception ex)
                {
                    _logger.Warn("Error occurred while check server", ex, additionInfo);
                }
            }

            watch.Stop();
            var checkHealthLatencyMetric = GetCheckHealthLatencyMetric(route);

            checkHealthLatencyMetric.AddValue(watch.ElapsedMilliseconds);

            bool hasUnavailableServers = checkedCount != servers.Length || availableCount != servers.Length;

            if (hasUnavailableServers || _lastHasUnavailableServers)
            {
                string messageFormat = "{0} servers checked ({1}/{2}) in route:{3}";
                string message       = string.Format(messageFormat, checkedCount, availableCount, servers.Length, route.RouteId);
                _logger.Info(message, additionInfo);
            }
            _lastHasUnavailableServers = hasUnavailableServers;

            return(statusChanged);
        }
Esempio n. 3
0
        private IEventMetric GetCheckHealthEventMetric(LoadBalancerRoute route, string serverId)
        {
            var metricId = _loadBalancerContext.GetMetricId(route.RouteId + "." + serverId + "." + CheckHealthEventMetricSuffix);
            var distributionMetricName           = _loadBalancerContext.GetDistributionMetricName(CheckHealthEventMetricSuffix);
            Dictionary <string, string> metadata = new Dictionary <string, string>();

            metadata["metric_name_distribution"] = distributionMetricName;
            metadata["loadbalancerid"]           = _loadBalancerContext.LoadBalancerId;
            metadata["routeid"]  = route.RouteId;
            metadata["serverid"] = serverId;
            return(_checkHealthEventMetrics.GetOrAdd(route.RouteId, key => _loadBalancerContext.EventMetricManager.GetMetric(metricId, new MetricConfig(metadata))));
        }
        private void InitAvailableServerCountMetric(LoadBalancerRoute route)
        {
            var metricId   = _loadBalancerContext.GetMetricId(route.RouteId + "." + ServerAvailableCountMetricSuffix);
            var metricName = _loadBalancerContext.GetMetricName(ServerAvailableCountMetricSuffix);
            Dictionary <string, string> metadata = new Dictionary <string, string>();

            metadata["metric_name_audit"] = metricName;
            metadata["loadbalancerid"]    = _loadBalancerContext.LoadBalancerId;
            metadata["routeid"]           = route.RouteId;
            var metricConfig = new StatusMetricConfig <double>(() => route.AvailableServers.Length, metadata);

            _availableServerCountMetrics.GetOrAdd(route.RouteId, key => _statusMetricManager.GetMetric(metricId, metricConfig));
        }
Esempio n. 5
0
        public ILoadBalancerRequestContext GetRequestContext(LoadBalancerRequestConfig requestConfig)
        {
            LoadBalancerRoute route = LoadBalancerContext.ServerSourceFilter.GetLoadBalancerRoute(requestConfig);

            if (route == null)
            {
                _logger.Warn("No matching route for \n" + requestConfig, LoadBalancerContext.AdditionalInfo);
                return(null);
            }
            Server server = LoadBalancerContext.GetLoadBalancerRule(route.RouteId).Choose(route);

            return(server == null ? null : new DefaultLoadBalancerRequestContext(server, LoadBalancerContext));
        }
Esempio n. 6
0
 protected void InternalBuildLoadBalanceItems(LoadBalancerRoute route)
 {
     if (!Object.ReferenceEquals(loadBalancerRoute, route))
     {
         lock (this)
         {
             if (!Object.ReferenceEquals(loadBalancerRoute, route))
             {
                 serverGroups      = BuildLoadBalanceItems(route);
                 serverContexts    = new ConcurrentDictionary <string, RoundRobinContext>();
                 loadBalancerRoute = route;
             }
         }
     }
 }
        private void PingServers(LoadBalancerRoute route)
        {
            PingUtil pingUtil = new PingUtil(_loadBalancerContext, _logger);

            if (pingUtil.HasPing)
            {
                foreach (ServerGroup serverGroup in route.ServerGroups)
                {
                    foreach (Server server in serverGroup.Servers)
                    {
                        server.IsAlive = pingUtil.IsAlive(server);
                    }
                }
            }
        }
        protected override List <ServerGroup> BuildLoadBalanceItems(LoadBalancerRoute route)
        {
            int weightGCD = GetWeightGCD(route.ServerGroups);

            var newLoadBalanceItems = new List <ServerGroup>();

            foreach (var serverGroup in route.ServerGroups)
            {
                int weight = serverGroup.Weight / weightGCD;
                for (int i = 0; i < weight; i++)
                {
                    newLoadBalanceItems.Add(serverGroup);
                }
            }
            newLoadBalanceItems.Shuffle();
            return(newLoadBalanceItems);
        }
        public void WeightedRoundRobinWithSpecificWeightTest()
        {
            int    serverCount    = 10;
            int    repeatTimes    = 100;
            int    repeatInterval = 0;
            int    threadCount    = 20;
            int    serverSumCount = 0;
            string loadBalancerId = MethodInfo.GetCurrentMethod().Name;

            IConfiguration configuration        = ObjectFactory.CreateAppSettingConfiguration();
            var            configurationSource  = ObjectFactory.CreateDefaultConfigurationSource(0, "App.config", configuration);
            var            configurationManager = ObjectFactory.CreateDefaultConfigurationManager(configurationSource);

            Dictionary <int, AtomicInteger> indexCountMapping = new Dictionary <int, AtomicInteger>();
            List <ServerGroup> serverGroups = new List <ServerGroup>();
            List <Server>      servers      = new List <Server>();

            for (int i = 0; i < serverCount; i++)
            {
                var metadata = new Dictionary <string, string>();
                metadata["Index"] = i.ToString();
                var server = new Server("Server_" + i, metadata);
                servers.Add(server);
                serverGroups.Add(new ServerGroup(server.ServerId, i, new List <Server>()
                {
                    server
                }));
                indexCountMapping[i] = 0;
                serverSumCount      += i;
            }
            LoadBalancerRoute route0 = new LoadBalancerRoute("default", serverGroups);

            ServerGroup route1Group0 = new ServerGroup("group0", 2, new List <Server>()
            {
                servers[0]
            });
            ServerGroup route1Group1 = new ServerGroup("group1", 1, new List <Server>()
            {
                servers[1]
            });
            LoadBalancerRoute route1 = new LoadBalancerRoute("route1", new List <ServerGroup>()
            {
                route1Group0, route1Group1
            });

            ServerGroup route2Group0 = new ServerGroup("group0", 2, new List <Server>()
            {
                servers[0]
            });
            ServerGroup route2Group1 = new ServerGroup("group1", 3, new List <Server>()
            {
                servers[1]
            });
            LoadBalancerRoute route2 = new LoadBalancerRoute("route2", new List <ServerGroup>()
            {
                route2Group0, route2Group1
            });

            LoadBalancerRequestConfig route1Config = new LoadBalancerRequestConfig(new List <LoadBalancerRouteConfig>()
            {
                new LoadBalancerRouteConfig("route1", 1, false)
            });
            LoadBalancerRequestConfig route2Config = new LoadBalancerRequestConfig(new List <LoadBalancerRouteConfig>()
            {
                new LoadBalancerRouteConfig("route2", 1, false)
            });

            int server0Count       = route1Group0.Weight + route2Group0.Weight;
            int server1Count       = route1Group1.Weight + route2Group1.Weight;
            int route1RequestCount = route1Group0.Weight + route1Group1.Weight;
            int route2RequestCount = route2Group0.Weight + route2Group1.Weight;

            var ping         = new TruePing();
            var serverSource = new DefaultDynamicServerSource(new List <LoadBalancerRoute>()
            {
                route0, route1, route2
            });
            var factory             = LoadBalancerManager.GetManager("soa", new LoadBalancerManagerConfig(configurationManager));
            var loadBalancerConfig  = new LoadBalancerConfig(ping, serverSource);
            var loadBalancer        = factory.GetLoadBalancer(loadBalancerId, loadBalancerConfig);
            var defaultLoadBalancer = ((DefaultLoadBalancer)loadBalancer).LoadBalancerContext;

            Action action = () =>
            {
                for (int i = 0; i < repeatTimes; i++)
                {
                    for (int j = 0; j < serverSumCount; j++)
                    {
                        var requestContext = loadBalancer.GetRequestContext(requestConfig);
                        int index          = int.Parse(requestContext.Server.Metadata["Index"]);
                        indexCountMapping[index].IncrementAndGet();
                        if (repeatInterval > 0)
                        {
                            Thread.Sleep(repeatInterval);
                        }
                    }

                    for (int j = 0; j < route1RequestCount; j++)
                    {
                        var requestContext = loadBalancer.GetRequestContext(route1Config);
                        int index          = int.Parse(requestContext.Server.Metadata["Index"]);
                        indexCountMapping[index].IncrementAndGet();
                        if (repeatInterval > 0)
                        {
                            Thread.Sleep(repeatInterval);
                        }
                    }

                    for (int j = 0; j < route2RequestCount; j++)
                    {
                        var requestContext = loadBalancer.GetRequestContext(route2Config);
                        int index          = int.Parse(requestContext.Server.Metadata["Index"]);
                        indexCountMapping[index].IncrementAndGet();
                        if (repeatInterval > 0)
                        {
                            Thread.Sleep(repeatInterval);
                        }
                    }
                }
            };

            List <Task> tasks = new List <Task>();

            for (int i = 0; i < threadCount; i++)
            {
                tasks.Add(Task.Factory.StartNew(action));
            }
            Task.WaitAll(tasks.ToArray());

            foreach (var item in indexCountMapping)
            {
                if (item.Key == 0)
                {
                    Assert.AreEqual((item.Key + server0Count) * repeatTimes * threadCount, item.Value.Value, item.Key.ToString());
                }
                else if (item.Key == 1)
                {
                    Assert.AreEqual((item.Key + server1Count) * repeatTimes * threadCount, item.Value.Value, item.Key.ToString());
                }
                else
                {
                    Assert.AreEqual(item.Key * repeatTimes * threadCount, item.Value.Value, item.Key.ToString());
                }
            }
        }
Esempio n. 10
0
 protected virtual List <ServerGroup> BuildLoadBalanceItems(LoadBalancerRoute route)
 {
     return(new List <ServerGroup>(route.ServerGroups));
 }
Esempio n. 11
0
        private bool CheckHealth(LoadBalancerRoute route, Server server)
        {
            if (!server.IsAlive)
            {
                if (!_pingUtil.HasPing)
                {
                    return(server.IsAlive);
                }

                bool pingSuccess = _loadBalancerContext.Ping.IsAlive(server);
                if (pingSuccess)
                {
                    server.IsAlive = true;
                    string message = string.Format("Server({0}) is available due to ping success", server);
                    _logger.Info(message, _loadBalancerContext.AdditionalInfo.Copy().With(AvailabilityKey, bool.TrueString));
                    var checkHealthEventMetric = GetCheckHealthEventMetric(route, server.ServerId);
                    checkHealthEventMetric.AddEvent("PullIn");
                }
                return(pingSuccess);
            }
            else
            {
                if (route.AvailableServers.Length <= _loadBalancerContext.MinAvailableServerCount)
                {
                    return(true);
                }

                int  successCount, failureCount, totalCount, failurePercent;
                bool failureRateExceeded, pingSuccess;
                var  serverStats = _loadBalancerContext.GetServerStats(server);
                successCount = serverStats.GetAvailableCount();
                failureCount = serverStats.GetUnavailableCount();
                totalCount   = successCount + failureCount;
                if (totalCount == 0)
                {
                    return(server.IsAlive);
                }

                failurePercent      = (int)(failureCount * 100.0 / totalCount);
                failureRateExceeded = failurePercent >= FailureThresholdPercentage;
                if (!failureRateExceeded)
                {
                    return(true);
                }

                if (!_pingUtil.HasPing)
                {
                    server.IsAlive = false;
                    string message = string.Format("Server({0}) is unavailable due to high failure rate({1}%)", server, failurePercent);
                    _logger.Warn(message, _loadBalancerContext.AdditionalInfo.Copy().With(AvailabilityKey, bool.FalseString));
                    var checkHealthEventMetric = GetCheckHealthEventMetric(route, server.ServerId);
                    checkHealthEventMetric.AddEvent("PullOut");
                    return(false);
                }

                pingSuccess = _pingUtil.IsAlive(server);
                if (!pingSuccess)
                {
                    server.IsAlive = false;
                    string message = string.Format("Server({0}) is unavailable due to high failure rate({1}%) and ping failure", server, failurePercent);
                    _logger.Warn(message, _loadBalancerContext.AdditionalInfo.Copy().With(AvailabilityKey, bool.FalseString));
                    var checkHealthEventMetric = GetCheckHealthEventMetric(route, server.ServerId);
                    checkHealthEventMetric.AddEvent("PullOut");
                }
                return(pingSuccess);
            }
        }
Esempio n. 12
0
 internal SeekRouteEventArgs(LoadBalancerRoute route)
 {
     Route = route;
 }