Beispiel #1
0
        private async Task TestIfNodeAlive(ServerNode node)
        {
            var    command = new GetTopologyCommand();
            string url;
            var    request = CreateRequest(node, command, out url);

            var sp = Stopwatch.StartNew();

            try
            {
                var response = await _httpClient.SendAsync(request).ConfigureAwait(false);

                if (response.IsSuccessStatusCode)
                {
                    node.IsFailed = false;
                }
            }
            catch (Exception e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Tested if node alive but it's down: {url}", e);
                }
            }
            finally
            {
                sp.Stop();
                node.UpdateRequestTime(sp.ElapsedMilliseconds);
            }
        }
Beispiel #2
0
        private async Task UpdateTopology()
        {
            JsonOperationContext context;

            using (ContextPool.AllocateOperationContext(out context))
            {
                var node = _topology.LeaderNode;

                var serverHash = ServerHash.GetServerHash(node.Url, node.Database);

                if (_firstTimeTryLoadFromTopologyCache)
                {
                    _firstTimeTryLoadFromTopologyCache = false;

                    var cachedTopology = TopologyLocalCache.TryLoadTopologyFromLocalCache(serverHash, context);
                    if (cachedTopology != null && cachedTopology.Etag > 0)
                    {
                        _topology = cachedTopology;
                        // we have cached topology, but we need to verify it is up to date, we'll check in
                        // 1 second, and let the rest of the system start
                        _updateTopologyTimer.Change(TimeSpan.FromSeconds(1), Timeout.InfiniteTimeSpan);
                        return;
                    }
                }

                var command = new GetTopologyCommand();
                try
                {
                    await ExecuteAsync(new ChoosenNode { Node = node }, context, command);

                    if (_topology.Etag != command.Result.Etag)
                    {
                        _topology = command.Result;
                        TopologyLocalCache.TrySavingTopologyToLocalCache(serverHash, _topology, context);
                    }
                }
                catch (Exception ex)
                {
                    if (Logger.IsInfoEnabled)
                    {
                        Logger.Info("Failed to update topology", ex);
                    }
                }
                finally
                {
                    _updateTopologyTimer.Change(TimeSpan.FromMinutes(5), Timeout.InfiniteTimeSpan);
                }
            }
        }
        public async Task Fastst_node_should_choose_the_node_without_delay()
        {
            NoTimeouts();
            var databaseName = "Fastst_node_should_choose_the_node_without_delay" + Guid.NewGuid();

            var(leader, serversToProxies) = await CreateRaftClusterWithProxiesAndGetLeader(3);

            var followers = Servers.Where(x => x.ServerStore.IsLeader() == false).ToArray();

            var conventionsForLoadBalancing = new DocumentConventions
            {
                ReadBalanceBehavior = ReadBalanceBehavior.FastestNode
            };

            //set proxies with delays to all servers except follower2
            using (var leaderStore = new DocumentStore
            {
                Urls = new[] { ReplacePort(leader.WebUrl, serversToProxies[leader].Port) },
                Database = databaseName,
                Conventions = conventionsForLoadBalancing
            })
            {
                leaderStore.Initialize();

                var(index, _) = await CreateDatabaseInCluster(databaseName, 3, leader.WebUrl);
                await WaitForRaftIndexToBeAppliedInCluster(index, TimeSpan.FromSeconds(30));

                var leaderRequestExecutor = leaderStore.GetRequestExecutor();

                //make sure we have updated topology --> more deterministic test
                await leaderRequestExecutor.UpdateTopologyAsync(new ServerNode
                {
                    ClusterTag = leader.ServerStore.NodeTag,
                    Database   = databaseName,
                    Url        = leader.WebUrl
                }, 5000);

                ApplyProxiesOnRequestExecutor(serversToProxies, leaderRequestExecutor);

                //wait until all nodes in database cluster are members (and not promotables)
                //GetTopologyCommand -> does not retrieve promotables
                using (var context = JsonOperationContext.ShortTermSingleUse())
                {
                    var topology = new Topology();
                    while (topology.Nodes?.Count != 3)
                    {
                        var topologyGetCommand = new GetTopologyCommand();
                        await leaderRequestExecutor.ExecuteAsync(topologyGetCommand, context).ConfigureAwait(false);

                        topology = topologyGetCommand.Result;
                        Thread.Sleep(50);
                    }
                }

                //set delays to all servers except follower2
                foreach (var server in Servers)
                {
                    if (server == followers[1])
                    {
                        continue;
                    }

                    serversToProxies[server].ConnectionDelay = 300;
                }

                using (var session = leaderStore.OpenSession())
                {
                    session.Store(new User {
                        Name = "John Dow"
                    }, "users/1");
                    session.SaveChanges();
                }

                while (leaderRequestExecutor.InSpeedTestPhase)
                {
                    using (var session = leaderStore.OpenSession())
                    {
                        session.Load <User>("users/1");
                    }
                }

                var fastest        = leaderRequestExecutor.GetFastestNode().Result.Node;
                var follower2Proxy = ReplacePort(followers[1].WebUrl, serversToProxies[followers[1]].Port);

                Assert.Equal(follower2Proxy, fastest.Url);
            }
        }
        public async Task Round_robin_load_balancing_with_failing_node_should_work()
        {
            var databaseName = "Round_robin_load_balancing_should_work" + Guid.NewGuid();
            var leader       = await CreateRaftClusterAndGetLeader(3);

            var followers = Servers.Where(x => x.ServerStore.IsLeader() == false).ToArray();

            var conventionsForLoadBalancing = new DocumentConventions
            {
                ReadBalanceBehavior = ReadBalanceBehavior.RoundRobin
            };

            using (var leaderStore = new DocumentStore
            {
                Urls = new[] { leader.WebUrl },
                Database = databaseName,
                Conventions = conventionsForLoadBalancing
            })
                using (var follower1 = new DocumentStore
                {
                    Urls = new[] { followers[0].WebUrl },
                    Database = databaseName,
                    Conventions = conventionsForLoadBalancing
                })
                    using (var follower2 = new DocumentStore
                    {
                        Urls = new[] { followers[1].WebUrl },
                        Database = databaseName,
                        Conventions = conventionsForLoadBalancing
                    })
                        using (var context = JsonOperationContext.ShortTermSingleUse())
                        {
                            leaderStore.Initialize();
                            follower1.Initialize();
                            follower2.Initialize();

                            var(index, _) = await CreateDatabaseInCluster(databaseName, 3, leader.WebUrl);
                            await WaitForRaftIndexToBeAppliedInCluster(index, TimeSpan.FromSeconds(30));

                            var leaderRequestExecutor = leaderStore.GetRequestExecutor();

                            //wait until all nodes in database cluster are members (and not promotables)
                            //GetTopologyCommand -> does not retrieve promotables
                            var topology = new Topology();
                            while (topology.Nodes?.Count != 3)
                            {
                                var topologyGetCommand = new GetTopologyCommand();
                                await leaderRequestExecutor.ExecuteAsync(topologyGetCommand, context);

                                topology = topologyGetCommand.Result;
                                Thread.Sleep(50);
                            }

                            foreach (var server in Servers)
                            {
                                await server.ServerStore.Cluster.WaitForIndexNotification(index);
                            }

                            using (var session = leaderStore.OpenSession())
                            {
                                session.Store(new User {
                                    Name = "John Dow"
                                });
                                session.Store(new User {
                                    Name = "Jack Dow"
                                });
                                session.Store(new User {
                                    Name = "Jane Dow"
                                });
                                session.Store(new User {
                                    Name = "FooBar"
                                }, "marker");
                                session.SaveChanges();

                                await WaitForDocumentInClusterAsync <User>(session as DocumentSession,
                                                                           "marker", x => true,
                                                                           leader.ServerStore.Configuration.Cluster.OperationTimeout.AsTimeSpan);
                            }

                            var requestExecutor = RequestExecutor.Create(follower1.Urls, databaseName, null, follower1.Conventions);
                            do //make sure there are three nodes in the topology
                            {
                                await Task.Delay(100);
                            } while (requestExecutor.TopologyNodes == null);

                            DisposeServerAndWaitForFinishOfDisposal(leader);

                            var failedRequests = new HashSet <(string, Exception)>();

                            requestExecutor.FailedRequest += (url, e) => failedRequests.Add((url, e));



                            using (var tmpContext = JsonOperationContext.ShortTermSingleUse())
                            {
                                for (var sessionId = 0; sessionId < 5; sessionId++)
                                {
                                    requestExecutor.Cache.Clear(); //make sure we do not use request cache
                                    await requestExecutor.ExecuteAsync(new GetStatisticsCommand(), tmpContext, CancellationToken.None, new SessionInfo(sessionId, false));
                                }
                            }
                        }
        }
        public async Task Round_robin_load_balancing_should_work()
        {
            var databaseName = "Round_robin_load_balancing_should_work" + Guid.NewGuid();
            var leader       = await CreateRaftClusterAndGetLeader(3);

            var followers = Servers.Where(x => x.ServerStore.IsLeader() == false).ToArray();

            var conventionsForLoadBalancing = new DocumentConventions
            {
                ReadBalanceBehavior = ReadBalanceBehavior.RoundRobin
            };

            using (var leaderStore = new DocumentStore
            {
                Urls = new [] { leader.WebUrl },
                Database = databaseName,
                Conventions = conventionsForLoadBalancing
            })
                using (var follower1 = new DocumentStore
                {
                    Urls = new[] { followers[0].WebUrl },
                    Database = databaseName,
                    Conventions = conventionsForLoadBalancing
                })
                    using (var follower2 = new DocumentStore
                    {
                        Urls = new[] { followers[1].WebUrl },
                        Database = databaseName,
                        Conventions = conventionsForLoadBalancing
                    })
                        using (var context = JsonOperationContext.ShortTermSingleUse())
                        {
                            leaderStore.Initialize();
                            follower1.Initialize();
                            follower2.Initialize();

                            var(index, _) = await CreateDatabaseInCluster(databaseName, 3, leader.WebUrl);
                            await WaitForRaftIndexToBeAppliedInCluster(index, TimeSpan.FromSeconds(30));

                            var leaderRequestExecutor = leaderStore.GetRequestExecutor();

                            //make sure we have updated topology --> more deterministic test
                            await leaderRequestExecutor.UpdateTopologyAsync(new ServerNode
                            {
                                ClusterTag = leader.ServerStore.NodeTag,
                                Database   = databaseName,
                                Url        = leader.WebUrl
                            }, 5000);

                            //wait until all nodes in database cluster are members (and not promotables)
                            //GetTopologyCommand -> does not retrieve promotables
                            var topology = new Topology();
                            while (topology.Nodes?.Count != 3)
                            {
                                var topologyGetCommand = new GetTopologyCommand();
                                await leaderRequestExecutor.ExecuteAsync(topologyGetCommand, context);

                                topology = topologyGetCommand.Result;
                                Thread.Sleep(50);
                            }

                            foreach (var server in Servers)
                            {
                                await server.ServerStore.Cluster.WaitForIndexNotification(index);
                            }

                            using (var session = leaderStore.OpenSession())
                            {
                                session.Store(new User {
                                    Name = "John Dow"
                                });
                                session.Store(new User {
                                    Name = "Jack Dow"
                                });
                                session.Store(new User {
                                    Name = "Jane Dow"
                                });
                                session.Store(new User {
                                    Name = "FooBar"
                                }, "marker");
                                session.SaveChanges();

                                await WaitForDocumentInClusterAsync <User>(session as DocumentSession, "marker", x => true, leader.ServerStore.Configuration.Cluster.OperationTimeout.AsTimeSpan);
                            }

                            var usedUrls = new List <string>();

                            for (var i = 0; i < 3; i++)
                            {
                                using (var session = leaderStore.OpenSession())
                                {
                                    // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                                    session.Query <User>().Where(u => u.Name.StartsWith("Ja")).ToList();
                                    usedUrls.Add((await session.Advanced.GetCurrentSessionNode()).Url.ToLower());
                                }
                            }

                            foreach (var url in usedUrls)
                            {
                                Assert.Single(usedUrls, url);
                            }
                        }
        }