连接池概述
连接池是NEST
和Elasticsearch.Net
的一种内部机制,它主要负责注册和管理集群中的节点,以及协调NEST
客户端如何向远程集群发送API调用。
尽管也是连接池,但
NEST
中的连接池并不像ADO.Net与数据库交互时熟悉的连接池。例如,NEST
中的连接池不负责管理到Elasticsearch的TCP连接的底层池,这是由桌面CLR中的ServicePointManager
处理的。
那么,NEST
中的连接池主要负责什么呢?它负责管理可以建立连接的Elasticsearch集群中的节点,并且有一个与ConnectionSettings
实例相关联的IConnectionPool
实例。因此,建议在整个应用程序的生命周期中使用单个客户端和连接设置实例,单个连接池实例的生命周期也将与应用程序的生命周期进行绑定。
NEST
提供了5种可用的连接池:
- SingleNodeConnectionPool
- CloudConnectionPool
- StaticConnectionPool
- SniffingConnectionPool
- StickyConnectionPool
SingleNodeConnectionPool
SingleNodeConnectionPool 是5种连接池中最简单的一种,如果没有将连接池显式传递给ConnectionSettings
构造函数,则使用默认连接池。它接收一个Uri
参数并使用该Uri
连接到Elasticsearch来进行所有调用。单节点连接池不会选择嗅探或ping
行为,也不会标记节点的存活状态。
如果集群只包含单个节点,或者通过单个负载均衡器实例与集群交互,则可以使用单节点连接池。
var uri = new Uri("http://localhost:9201");
var pool = new SingleNodeConnectionPool(uri);
var client = new ElasticClient(new ConnectionSettings(pool));
当你使用ElasticClient
的Uri
作为惟一参数的构造器时,其他实例内部默认使用的即为一个SingleNodeConnectionPool
连接池:
client = new ElasticClient(uri);
但是,建议还是显式地传递连接池的连接配置。
CloudConnectionPool
这是SingleNodeConnectionPool
的专门的子类,主要是用来连接Elastic官方提供了Elasticsearch云服务(当然,你也可以搭建自己的Elasticsearch私有云服务),它接收Cloud Id
和凭证
两个参数。在使用时,客户端还将为连接设置选择弹性云优化的默认值。
你可以从弹性云集群管理控制台获取集群的云Id。
一个云Id的形式应该是这样的:cluster_name:base_64_data
,其中的base_64_data
是云实例服务中的UUID,比如:
host_name$elasticsearch_uuid$kibana_uuid$apm_uuid
除此之外,只有host_name
和elasticsearch_uuid
始终可用。
可以使用凭据
和Cloud Id
创建云连接池,如下:
var credentials = new BasicAuthenticationCredentials("username", "password");
var pool = new CloudConnectionPool(cloudId, credentials);
var client = new ElasticClient(new ConnectionSettings(pool));
你也可以使用接收Cloud Id
和凭证
参数的ElasticClient
构造函数来创建云客户端实例,如:
client = new ElasticClient(cloudId, credentials);
StaticConnectionPool
如果你有一个小型Elasticsearch集群,并且不希望启用嗅探来查找集群拓扑,那么静态连接池非常有用。
给定一个Uri集合:
var uris = Enumerable.Range(9200, 5)
.Select(port => new Uri($"http://localhost:{port}"));
然后使用这个集合来创建连接池:
var pool = new StaticConnectionPool(uris);
var client = new ElasticClient(new ConnectionSettings(pool));
或者使用可枚举的Node
:
var nodes = uris.Select(u => new Node(u));
pool = new StaticConnectionPool(nodes);
client = new ElasticClient(new ConnectionSettings(pool));
这种类型的池是硬连接的,可以选择不重播(嗅探),但在启用时支持ping
。
SniffingConnectionPool
嗅探连接池(SniffingConnectionPool
)派生自StaticConnectionPool
,它允许自己在运行时重播,并附带了一个开销非常小的ReaderWriterLockSlim
来确保线程安全。
给定一个Uri集合:
var uris = Enumerable.Range(9200, 5)
.Select(port => new Uri($"http://localhost:{port}"));
使用这些Uri集合来创建嗅探连接池:
var pool = new SniffingConnectionPool(uris);
var client = new ElasticClient(new ConnectionSettings(pool));
或者使用可枚举的Node
节点:
var nodes = uris.Select(u=>new Node(u));
pool = new SniffingConnectionPool(nodes);
client = new ElasticClient(new ConnectionSettings(pool));
使用节点的一个主要好处是,在传播时可以包含已知的节点角色,然后NEST
可以使用这些角色来处理特定的API请求。
这种类型的池是硬连接的,可以选择重播(嗅探)和ping
。
StickyConnectionPool
StickyConnectionPool
连接池返回第一个发出请求的活动节点,这样该节点在请求之间具有粘性。它使用System.Threading.Interlocked
以线程安全的方式将索引器保持到最后一个活动节点。
给定一个Uri集合:
var uris = Enumerable.Range(9200, 5)
.Select(port => new Uri($"http://localhost:{port}"));
使用这些Uri集合来创建连接池:
var pool = new StickyConnectionPool(uris);
var client = new ElasticClient(new ConnectionSettings(pool));
或者使用可枚举的Node
节点:
var nodes = uris.Select(u=>new Node(u));
pool = new StickyConnectionPool(nodes);
client = new ElasticClient(new ConnectionSettings(pool));
这种类型的池是硬连接的,可以选择不嗅探,但是支持ping
。
Sticky Sniffing Connection Pool
StickySniffingConnectionPool
连接池返回第一个发出请求的活动节点,这样该节点在请求之间具有粘性。这个实现支持嗅探和排序,这样应用程序的每个实例都可以使用一个节点。例如,同一机架中的基于节点属性的节点。
给定一个Uri集合:
var uris = Enumerable.Range(9200, 5)
.Select(port => new Uri($"http://localhost:{port}"));
嗅探排序的粘性池接受第二个参数,一个Func<Node, float>
委托,它接受一个节点并返回一个权重,所有节点将按权重降序排序。下面的示例是对节点进行评分,有节点属性rack_id并且值为
rack_one
中的客户端节点得分最高。
var pool = new StickySniffingConnectionPool(uris, node =>
{
var weight = 0f;
if (node.ClientNode)
weight += 10;
if (node.Settings.TryGetValue("node.attr.rack_id", out var rackId) && rackId.ToString() == "rack_one")
weight += 10;
return weight;
});
var client = new ElasticClient(new ConnectionSettings(pool));
发表评论
登录用户才能发表评论, 请 登 录 或者 注册