轮循行为

874 发布于: 2021-03-25 读完约需 3 分钟

嗅探连接池Sniffing connection pools和静态连接池Static connection pools在活动节点上轮询,以便将请求均匀分布到所有已知节点上。

创建视图方法(CreateView)

CreateView()IConnectionPool接口提供的一个公共方法,该方法创建一个客户端已知集群中所有活动节点的视图。不同的连接池实现可以决定返回的不同的视图,比如:

  • SingleNodeConnectionPool连接池只能返回一个节点;
  • StickyConnectionPool连接池可以返回与请求对应的最后一个活动节点的起始位置相同的活动节点的视图;
  • SniffingConnectionPool连接池返回起始位置在每次调用时都在变化的视图。

CreateView方法是以无锁线程安全的方式实现的,这意味着每个被调用者都会返回自己的游标,以在内部节点列表上前进。这样做是为了保证每个失败的请求都尝试所有节点,而不会影响全局游标。

以下示例设置了一个包含10个节点的静态连接池,在启动时强制随机化为false,这样我们就可以测试返回的节点是否符合我们预期的顺序。

var uris = Enumerable.Range(9200, NumberOfNodes).Select(p => new Uri("http://localhost:" + p));
var staticPool = new StaticConnectionPool(uris, randomize: false);
var sniffingPool = new SniffingConnectionPool(uris, randomize: false);

this.AssertCreateView(staticPool);
this.AssertCreateView(sniffingPool);

那么,我们期望的顺序是怎么样的呢?让我们来设想一下:

  • 线程A首先调用CreateView(),但不使用本地游标,并从内部全局游标获取当前值,即0
  • 接着,线程B在没有本地游标的情况下调用CreateView(),因此从1开始
  • 在此之后,每个线程应该使用它们的本地游标依次遍历节点。例如,线程A可能得到0、1、2、3、5,而线程B将得到1、2、3、4、0。
var startingPositions = Enumerable.Range(0, NumberOfNodes)
    .Select(i => pool.CreateView().First())
    .Select(n => n.Uri.Port)
    .ToList();

var expectedOrder = Enumerable.Range(9200, NumberOfNodes);
startingPositions.Should().ContainInOrder(expectedOrder);

上面的代码证明,每次调用CreateView()都会分配下一个可用节点。

重新调整测试策略:

  • 通过NumberOfNodex * 2个线程来调用CreateView()方法
  • 在每个线程上,使用本地游标调用CreateView()方法NumberOfNodes * 10次。

验证每个线程是否看到所有节点以及它们是否被包裹。例如,在节点9209之后,又出现了节点9200:

var threadedStartPositions = new ConcurrentBag<int>();
var threads = Enumerable.Range(0, 20)
    .Select(i => CreateThreadCallingCreateView(pool, threadedStartPositions))
    .ToList();

foreach (var t in threads) t.Start();
foreach (var t in threads) t.Join();

每个线程都报告了它启动的第一个节点,因为我们启动了NumberOfNodes * 2个线程,确保每个节点可以看到两次:

var grouped = threadedStartPositions.GroupBy(p => p).ToList();
grouped.Count.Should().Be(NumberOfNodes);
grouped.Select(p => p.Count()).Should().OnlyContain(p => p == 2);

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

发表评论

登录用户才能发表评论, 请 登 录 或者 注册