protected static Channel TryGetChannelFromLoadBalancer(Channel lbChannel,
                                                               ChannelCredentials credentials,
                                                               string serviceName,
                                                               int maxMesssageLength)
        {
            ServiceDiscoveryGrpc.ServiceDiscoveryGrpcClient lbClient =
                new ServiceDiscoveryGrpc.ServiceDiscoveryGrpcClient(lbChannel);

            DiscoverServicesResponse lbResponse = lbClient.DiscoverTopServices(
                new DiscoverServicesRequest
            {
                ServiceName = serviceName,
                MaxCount    = 1
            });

            if (lbResponse.ServiceLocations.Count > 0)
            {
                ServiceLocationMsg serviceLocation = lbResponse.ServiceLocations[0];

                Channel result = GrpcUtils.CreateChannel(serviceLocation.HostName,
                                                         serviceLocation.Port, credentials,
                                                         maxMesssageLength);

                _msg.DebugFormat("The load balancer is suggesting {0}", result.ResolvedTarget);

                return(result);
            }

            // Assumption: A load balancer is never also serving real requests -> lets not use it at all!
            _msg.Debug("The load balancer has no service locations available.");

            return(null);
        }
Beispiel #2
0
        public override async Task <DiscoverServicesResponse> DiscoverTopServices(
            DiscoverServicesRequest request, ServerCallContext context)
        {
            DiscoverServicesResponse response = null;

            try
            {
                ProcessUtils.EnsureThreadIdInName();

                Stopwatch watch = Stopwatch.StartNew();

                response = new DiscoverServicesResponse();

                IList <ServiceLocationMsg> result = await GetTopServiceLocationMessages(request);

                response.ServiceLocations.AddRange(result);

                _logger.LogDebug(
                    "Returning {count} service location(s) [{time}ms]: {serviceLocations}",
                    result.Count,
                    watch.ElapsedMilliseconds,
                    string.Concat(result.Select(s => $"{s.HostName}:{s.Port}, ")));
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error discovering service {serviceName}", request.ServiceName);

                SetUnhealthy();
            }

            return(response);
        }
        public void CanDiscoverSingleService()
        {
            DeregisterServices(_host127001, _startPort127001);

            ServiceDiscoveryGrpc.ServiceDiscoveryGrpcClient client = GetClient();

            DiscoverServicesResponse response = client.DiscoverServices(
                new DiscoverServicesRequest
            {
                ServiceName = _serviceName,
                MaxCount    = 1
            });

            Assert.AreEqual(1, response.ServiceLocations.Count);

            ServiceLocationMsg serviceLocation = response.ServiceLocations[0];

            Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
            Assert.AreEqual(_localHost, serviceLocation.HostName);
        }
        public void CanDiscoverManyServices()
        {
            DeregisterServices(_host127001, _startPort127001);

            ServiceDiscoveryGrpc.ServiceDiscoveryGrpcClient client = GetClient();

            DiscoverServicesResponse response = client.DiscoverServices(
                new DiscoverServicesRequest
            {
                ServiceName = _serviceName,
                MaxCount    = 3
            });

            Assert.AreEqual(3, response.ServiceLocations.Count);

            foreach (var serviceLocation in response.ServiceLocations)
            {
                Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
                Assert.AreEqual(_localHost, serviceLocation.HostName);
                Assert.True(serviceLocation.Port >= _startPort &&
                            serviceLocation.Port < _startPort + _serviceCount);
            }
        }
        public void CanBalanceMultiMachineLoad()
        {
            // Add a 'second host' with a different name (127.0.0.1 vs localhost)
            StartAndRegisterServices(_host127001, _startPort127001);

            // Wait until the least recently used service cache can be cleared
            // (it could contain ports from previous tests)
            Thread.Sleep(5000);

            ServiceDiscoveryGrpc.ServiceDiscoveryGrpcClient client = GetClient();

            // All load at 0
            var singleServiceRequest = new DiscoverServicesRequest
            {
                ServiceName = _serviceName,
                MaxCount    = 1
            };

            DiscoverServicesResponse response = client.DiscoverTopServices(singleServiceRequest);

            Assert.AreEqual(1, response.ServiceLocations.Count);

            // If all else is equal, they are ordered by port
            ServiceLocation serviceLocation = ToServiceLocation(response.ServiceLocations[0]);

            Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
            string firstLocationHost = serviceLocation.HostName;

            // Add one load to the first machine:
            _serviceLoadByLocation[serviceLocation].CurrentProcessCount += 1;

            // The second time, thanks to machine-level cpu balancing the first port from the other
            // machine should be returned:
            response = client.DiscoverTopServices(singleServiceRequest);
            Assert.AreEqual(1, response.ServiceLocations.Count);

            serviceLocation = ToServiceLocation(response.ServiceLocations[0]);
            Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
            Assert.AreNotEqual(firstLocationHost, serviceLocation.HostName);

            foreach (KeyValuePair <ServiceLocation, ServiceLoad> loadByPort in
                     _serviceLoadByLocation)
            {
                if (loadByPort.Key.HostName == _localHost)
                {
                    continue;
                }

                // Overload the 127.0.0.1 host completely:
                int ascendingRank  = loadByPort.Key.Port - _startPort127001;
                int descendingRank = _serviceCount - ascendingRank;

                loadByPort.Value.CurrentProcessCount = descendingRank;
            }

            Stopwatch watch = Stopwatch.StartNew();

            response = client.DiscoverTopServices(
                new DiscoverServicesRequest
            {
                ServiceName = _serviceName,
                MaxCount    = 6
            });

            watch.Stop();
            Console.WriteLine("First time full balancing: {0}ms", watch.ElapsedMilliseconds);

            Assert.AreEqual(6, response.ServiceLocations.Count);

            HashSet <int> usedPorts = new HashSet <int>();

            for (var i = 0; i < response.ServiceLocations.Count; i++)
            {
                serviceLocation = ToServiceLocation(response.ServiceLocations[i]);

                Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
                Assert.AreEqual(_localHost, serviceLocation.HostName);

                Assert.True(serviceLocation.Port >= _startPort &&
                            serviceLocation.Port < _startPort + _serviceCount);

                usedPorts.Add(serviceLocation.Port);
            }

            // Assert performance after warm-up:

            watch = Stopwatch.StartNew();

            response = client.DiscoverTopServices(
                new DiscoverServicesRequest
            {
                ServiceName = _serviceName,
                MaxCount    = 4
            });

            Assert.AreEqual(4, response.ServiceLocations.Count);

            watch.Stop();

            Console.WriteLine("Second time full balancing (warm channels): {0}ms",
                              watch.ElapsedMilliseconds);

            Assert.Less(watch.ElapsedMilliseconds, 50);

            for (var i = 0; i < response.ServiceLocations.Count; i++)
            {
                serviceLocation = ToServiceLocation(response.ServiceLocations[i]);

                Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
                Assert.AreEqual(_localHost, serviceLocation.HostName);

                Assert.True(serviceLocation.Port >= _startPort &&
                            serviceLocation.Port < _startPort + _serviceCount);

                Assert.IsFalse(usedPorts.Contains(serviceLocation.Port));
            }

            DeregisterServices(_host127001, _startPort127001);
        }
        public void CanBalanceLoad()
        {
            ServiceDiscoveryGrpc.ServiceDiscoveryGrpcClient client = GetClient();

            // All load at 0
            var singleServiceRequest = new DiscoverServicesRequest
            {
                ServiceName = _serviceName,
                MaxCount    = 1
            };

            DiscoverServicesResponse response = client.DiscoverTopServices(singleServiceRequest);

            Assert.AreEqual(1, response.ServiceLocations.Count);

            // If all else is equal, they are ordered by port
            var serviceLocation = response.ServiceLocations[0];

            Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
            Assert.AreEqual(_localHost, serviceLocation.HostName);
            Assert.AreEqual(_startPort, serviceLocation.Port);

            // The second time, thanks to some kind of round-robin among the least recently used
            // a different port should be returned:
            response = client.DiscoverTopServices(singleServiceRequest);
            Assert.AreEqual(1, response.ServiceLocations.Count);

            serviceLocation = response.ServiceLocations[0];
            Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
            Assert.AreEqual(_localHost, serviceLocation.HostName);
            Assert.AreNotEqual(_startPort, serviceLocation.Port);

            foreach (KeyValuePair <ServiceLocation, ServiceLoad> loadByPort in
                     _serviceLoadByLocation)
            {
                // Order by port but descending

                int ascendingRank  = loadByPort.Key.Port - _startPort;
                int descendingRank = _serviceCount - ascendingRank;

                loadByPort.Value.CurrentProcessCount = descendingRank;
            }

            Stopwatch watch = Stopwatch.StartNew();

            response = client.DiscoverTopServices(
                new DiscoverServicesRequest
            {
                ServiceName = _serviceName,
                MaxCount    = 3
            });

            watch.Stop();
            Console.WriteLine("First time full balancing: {0}ms", watch.ElapsedMilliseconds);

            Assert.AreEqual(3, response.ServiceLocations.Count);

            for (var i = 0; i < response.ServiceLocations.Count; i++)
            {
                serviceLocation = response.ServiceLocations[i];

                Assert.AreEqual(_serviceName, serviceLocation.ServiceName);
                Assert.AreEqual(_localHost, serviceLocation.HostName);

                int expected = _startPort + _serviceCount - i - 1;
                Assert.AreEqual(expected, serviceLocation.Port);

                Assert.True(serviceLocation.Port >= _startPort &&
                            serviceLocation.Port < _startPort + _serviceCount);
            }

            // Assert performance after warm-up:

            watch = Stopwatch.StartNew();

            response = client.DiscoverTopServices(
                new DiscoverServicesRequest
            {
                ServiceName = _serviceName,
                MaxCount    = 3
            });

            Assert.AreEqual(3, response.ServiceLocations.Count);

            watch.Stop();

            Console.WriteLine("Second time full balancing (warm channels): {0}ms",
                              watch.ElapsedMilliseconds);

            Assert.Less(watch.ElapsedMilliseconds, 50);
        }