连接
NEST使用合理的默认值来连接和与Elasticsearch集群进行交互,但提供了许多配置选项和组件来改变此行为
- 配置选项
- 连接池
- 修改默认连接
- 使用证书
配置选项
使用Elasticsearch.Net和NEST连接到Elasticsearch很容易,但是您可能希望更改默认的连接行为。 ConnectionSettings
(和ConnectionConfiguration
for Elasticsearch.Net)上有许多配置选项可用于控制客户端与弹性搜索的交互方式。
ConnectionConfiguration上的选项
以下是ConnectionConfiguration
上可用的连接配置选项列表; 由于ConnectionSettings
来自ConnectionConfiguration
,所以这些选项可用于Elasticsearch.Net和NEST:
BasicAuthentication
发送所有请求到Elasticsearch的基本身份验证凭据
ClientCertificate
使用以下证书验证所有HTTP请求。 您还可以使用ClientCertificates
根据个别请求进行设置
ClientCertificates
使用以下证书来验证所有HTTP请求。 您还可以使用ClientCertificates
根据个别请求进行设置
ConnectionLimit
限制可以向端点打开的并发连接数。 默认为80。
对于桌面CLR,当创建ServicePoint对象时,此设置适用于ServicePointManager对象上的DefaultConnectionLimit属性,影响默认的IConnection
实现。
对于Core CLR,此设置适用于默认IConnection
实现中HttpClient使用的HttpClientHandler实例上的MaxConnectionsPerServer属性
DeadTimeout
设置节点已被标记为死机时的默认死区超时因子。 一些连接池可能会使用平面超时,而其他连接池则会采用这一因素并以指数方式增加
DisableAutomaticProxyDetection
禁用代理的自动检测
DisableDirectStreaming
确保响应字节始终在ElasticsearchResponse<T>
上可用
根据注册的串行器,这可能会使响应缓冲在内存中,可能会影响性能。
DisablePing
当一个节点是第一次使用时,或者当它被标记为死后第一次使用时,超时时间超时的ping将发送到节点,以确保当它仍然死亡时,报告速度与 可能。 如果您在可能较慢的原始请求中失败,则可以全局禁用这些ping
EnableDebugMode
打开有助于调试的设置,如DisableDirectStreaming()和PrettyJson(),以便可以检查原始请求和响应JSON
EnableHttpCompression
启用gzip压缩的请求和响应
您需要在Elasticsearch上配置http压缩才能使用
EnableHttpPipelining
允许请求Pipeline
还必须在Elasticsearch中启用HTTP Pipeline,以使其正常工作
EnableTcpKeepAlive
在TCP连接上设置保持活动选项。
对于桌面CLR,设置ServicePointManager.SetTcpKeepAlive
GlobalHeaders
每个请求将发送的header集合。 在您总是需要传递header的情况下很有用,例如一个定制的auth header
GlobalQueryStringParameters
每个请求将发送的一组查询字符串参数。在您总是需要传递参数的情况下有用。一个API密钥。
MaxDeadTimeout
设置节点可以被标记为死亡的最大时间。 IConnectionPool的不同实现可能会选择不同的默认值。
MaximumRetries
给定请求的最大重试次数,
MaxRetryTimeout
限制总运行时间,包括重试次数,与RequestTimeout分开
未指定时,默认为RequestTimeout,默认为60秒
NodePredicate
注册谓词以选择要执行API调用的节点。请注意,嗅探请求省略此谓词,并始终在所有节点上执行。当使用支持重新占用节点的IConnectionPool
实现时,这将默认从普通API调用中省略主节点。当使用静态或单节点连接池时,假定应该逐字地采用实例化客户端的节点列表。
OnRequestCompleted
注册从Elasticsearch收到响应时调用的Action 。这对于实现自定义日志记录是有用的。可以通过多次呼叫来注册多个回调
OnRequestDataCreated
注册创建RequestData时调用的Action 。可以通过多次呼叫来注册多个回调
PingTimeout
设置ping请求的默认ping超时(以毫秒为单位),用于确定节点是否存活。平时应尽快失败。
PrettyJson
强制所有请求都有?pretty = true查询参数附加,导致Elasticsearch返回格式化的JSON。还强制客户端发送格式化的JSON。默认为false
Proxy
如果您的连接必须通过代理,请使用此方法来指定代理网址
RequestTimeout
将每个请求的默认超时(以毫秒为单位)设置为Elasticsearch。默认为60秒。
您可以在此处将其设置为高值,并在Elasticsearch方面指定超时。
ServerCertificateValidationCallback
注册一个ServerCertificateValidationCallback,这是每个端点调用,直到它返回true。此回调后,返回true,该端点在该主机的ServiceEndpoint的生存期内被验证。
SniffLifeSpan
设置集群状态被认为是过时的持续时间,并且应该再次执行嗅探。一个IConnectionPool
必须表明它支持reeeding,否则嗅探将永远不会发生。默认为1小时。设置为null以完全禁用。嗅探只会发生在对于SupportsReseeding返回true的ConnectionPools上
SniffOnConnectionFault
如果连接池支持重新进入,则在呼叫失败时启用群集重新启动。默认为true
SniffOnStartup
如果该池支持重新占用,则可以嗅探连接池的首次使用情况。默认为true
ThrowExceptions
而不是跟随一个c / go像错误检查response.IsValid总是在客户端上抛出一个异常,当调用导致客户端或Elasticsearch服务器上的异常。
这种例外的原因可能是搜索解析器错误,索引丢失异常等…
ConnectionSettings上的选项
以下是ConnectionSettings
上可用连接配置选项的列表:
DefaultFieldNameInferrer
指定如何从POCO属性名称推断字段名称。
默认情况下,NEST骆驼案例属性名称。 EmailAddress POCO属性⇒“emailAddress”Elasticsearch 文档字段名称
DefaultIndex
未指定索引时使用的默认索引。
DefaultTypeNameInferrer
指定如何从POCO类型推断类型名称。 默认情况下,通过在类型名称上调用ToLowerInvariant
来推断类型名称。
MapDefaultTypeIndices
指定给定的POCO类型的默认索引名称。 优先于全局DefaultIndex
MapDefaultTypeNames
指定给定的POCO类型的默认类型名称。 优先于全局DefaultTypeNameInferrer
MapIdPropertyFor
在Elasticsearch中指定索引时,应指定给定POCO上的哪个属性来推断文档的id。 文档的类型。
MapPropertiesFor
指定如何为给定的POCO类型映射属性。 文档的类型。
PluralizeTypeNames
从POCO类型名称推断时,可以多种类型名称。
这将调用DefaultTypeNameInferrer
与实现将多项化类型名称。 这以前是Nest 0.90之前的默认值
以下示例说明使用低级客户端设置多个配置选项
var connectionConfiguration = new ConnectionConfiguration()
.DisableAutomaticProxyDetection()
.EnableHttpCompression()
.DisableDirectStreaming()
.PrettyJson()
.RequestTimeout(TimeSpan.FromMinutes(2));
var lowLevelClient = new ElasticLowLevelClient(connectionConfiguration);
并与高级客户端
var connectionSettings = new ConnectionSettings()
.InferMappingFor<Project>(i => i
.IndexName("my-projects")
.TypeName("project")
)
.EnableDebugMode()
.PrettyJson()
.RequestTimeout(TimeSpan.FromMinutes(2));
var client = new ElasticClient(connectionSettings);
可以直接在节点URI上指定基本身份验证凭据
var uri = new Uri("http://username:password@localhost:9200");
var settings = new ConnectionConfiguration(uri);
但是当使用与多个节点的连接池时,这可能很尴尬,特别是当使用的连接池是能够重新加载iteslf的连接池时。 因此,我们建议在ConnectionSettings
上指定凭据。
连接池
连接池是内部机制,负责注册集群中的哪些节点,以及NEST可以使用哪些节点发出客户端呼叫。
尽管名称,NEST中的连接池不像您可能熟悉的连接池,可以使用ADO.Net与数据库进行交互; 例如,NEST中的连接池不负责管理到Elasticsearch的TCP连接的底层池,这由桌面CLR中的ServicePointManager处理,可以通过更改HttpConnection上的ServicePoint行为来控制。
那么,NEST中的连接池是什么负责? 它负责管理可以进行连接的弹性搜索集群中的节点,并且有一个与ConnectionSettings实例关联的IConnectionPool实例。 由于在应用程序的使用寿命期间推荐使用单个客户端和连接设置实例,所以单个连接池实例的生命周期也将被绑定到应用程序的生命周期。
连接池有四种类型
- SingleNodeConnectionPool
- StaticConnectionPool
- SniffingConnectionPool
- StickyConnectionPool
SingleNodeConnectionPool
所有连接池中最简单的连接池,如果没有连接池显式传递给ConnectionSettings
构造函数,则为默认值。 它需要一个Uri
,并使用它来连接到所有呼叫的Elasticsearch。 单节点连接池不会选择嗅探或ping行为,并且永远不会将节点标记为死亡或活动。 它拥有的一个Uri
总是准备好去。
单节点连接池是要使用的池,如果您的群集只包含一个节点,或者您正在通过单个负载平衡器实例与群集进行交互。
var uri = new Uri("http://localhost:9201");
var pool = new SingleNodeConnectionPool(uri);
pool.Nodes.Should().HaveCount(1);
var node = pool.Nodes.First();
node.Uri.Port.Should().Be(9201);
这种类型的池是硬连线的,以选择退出重新加载(因此,嗅探)以及ping
pool.SupportsReseeding.Should().BeFalse();
和ping
pool.SupportsPinging.Should().BeFalse();
当您使用采用单个Uri的ElasticClient
低构造函数时,我们默认使用SingleNodeConnectionPool
var client = new ElasticClient(uri);
client.ConnectionSettings.ConnectionPool.Should().BeOfType<SingleNodeConnectionPool>();
但是,我们敦促您始终明确地传递您的连接设置
client = new ElasticClient(new ConnectionSettings(uri));
client.ConnectionSettings.ConnectionPool.Should().BeOfType<SingleNodeConnectionPool>();
或者更好地显式地传递连接池
client = new ElasticClient(new ConnectionSettings(pool));
client.ConnectionSettings.ConnectionPool.Should().BeOfType<SingleNodeConnectionPool>();
StaticConnectionPool
如果您有一个已知的小型集群,静态连接池是非常好的,并且不想启用嗅探来查找集群拓扑
var uris = Enumerable.Range(9200, 5).Select(p => new Uri("http://localhost:" + p));
一个连接池可以使用Uri's
的数量来播种
var pool = new StaticConnectionPool(uris);
或者使用可以枚举的Node
var nodes = uris.Select(u => new Node(u));
pool = new StaticConnectionPool(nodes);
这种类型的池的硬连线退出补种(因此嗅探)的
pool.SupportsReseeding.Should().BeFalse();
但支持ping功能
pool.SupportsPinging.Should().BeTrue();
要使用此静态连接池创建客户端,请将连接池传递给您传递给ElasticClient
的ConnectionSettings
var client = new ElasticClient(new ConnectionSettings(pool));
client.ConnectionSettings.ConnectionPool.Should().BeOfType<StaticConnectionPool>();
SniffingConnectionPool
StaticConnectionPool
的子类,允许自身在运行时重新占用。 它具有ReaderWriterLockSlim
非常小的开销,以确保线程安全。
var uris = Enumerable.Range(9200, 5).Select(p => new Uri("http://localhost:" + p));
连接池可以使用Uri的无数种子播种
var pool = new SniffingConnectionPool(uris);
或者使用可以枚举的Node
。 这里的主要优点是您可以在种子时包括已知的节点角色,NEST可以使用此信息首先支持在主符合条件的节点上进行嗅探,并仅采取主节点转出节点以发出客户端呼叫。
var nodes = uris.Select(u=>new Node(u));
pool = new SniffingConnectionPool(nodes);
这种类型的池硬连线,以便选择补种(因此嗅探)
pool.SupportsReseeding.Should().BeTrue();
和ping
pool.SupportsPinging.Should().BeTrue();
要使用嗅探连接池创建客户端,将连接池传递给您传递给ElasticClient
的ConnectionSettings
var client = new ElasticClient(new ConnectionSettings(pool));
client.ConnectionSettings.ConnectionPool.Should().BeOfType<SniffingConnectionPool>();
StickyConnectionPool
一种连接池,返回第一个活动节点以发出请求,使得节点在请求之间是粘性的。 它使用System.Threading.Interlocked
以线程安全的方式将索引器保存到最后一个活动节点。
var uris = Enumerable.Range(9200, 5).Select(p => new Uri("http://localhost:" + p));
连接池可以使用Uri的无数种子播种
var pool = new StickyConnectionPool(uris);
或使用可枚举的Node
。 这里的主要优点是您可以在种子时包括已知的节点角色,NEST可以使用此信息首先支持在主符合条件的节点上进行嗅探,并仅采取主节点转出节点以发出客户端呼叫。
var nodes = uris.Select(u=>new Node(u));
pool = new StickyConnectionPool(nodes);
这种类型的池的硬连线退出补种(因此嗅探)的
pool.SupportsReseeding.Should().BeFalse();
但是支持ping
pool.SupportsPinging.Should().BeTrue();
要使用粘性连接池创建客户端,将连接池传递给您传递给ElasticClient
的ConnectionSettings
var client = new ElasticClient(new ConnectionSettings(pool));
client.ConnectionSettings.ConnectionPool.Should().BeOfType<StickyConnectionPool>();
修改默认连接
客户端抽象发送请求并创建IConnection
后面的响应,默认实现使用
System.Net.WebRequest for Desktop CLR
Core.Net的System.Net.Http.HttpClient
不同实现的原因是WebRequest
和ServicePoint
在netstandard 1.3上不能直接使用。
使用WebRequest
的桌面CLR实现是最成熟的实现,自NEST开始以来一直在生产中尝试和信任。 因此,我们还没有准备好放弃所有CLR版本中的HttpClient
实现。
除了生产使用之外,还有一些重要的切换,易于针对不能在HttpClient
上设置的ServicePoint
进行设置。
最后,另一个限制是HttpClient
没有同步代码路径,所以支持这些方法是做黑客异步补丁,这绝对需要时间来烘烤。
那么你为什么要通过自己的IConnection
? 我们来看几个例子
使用InMemoryConnection
InMemoryConnection
是内置的IConnection
,可以轻松地对单元测试进行编写。 它可以配置为使用默认响应字节,HTTP状态代码和进行通话时发生异常进行响应。
InMemoryConnection
实际上并不发送任何请求或从Elasticsearch
收到任何响应; 请求仍然被序列化,并且如果在请求或全局上将.DisableDirectStreaming
设置为true
,则可以在响应上获取请求字节
var connection = new InMemoryConnection();
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(connectionPool, connection);
var client = new ElasticClient(settings);
这里我们通过使用IConnectionPool
和IConnection
的重载创建一个新的ConnectionSettings
。 我们传递一个InMemoryConnection
,它使用默认的无参数构造函数,将返回200,并且从不实际执行任何IO。
我们来看一个比较复杂的例子
var response = new
{
took = 1,
timed_out = false,
_shards = new
{
total = 2,
successful = 2,
failed = 0
},
hits = new
{
total = 25,
max_score = 1.0,
hits = Enumerable.Range(1, 25).Select(i => (object)new
{
_index = "project",
_type = "project",
_id = $"Project {i}",
_score = 1.0,
_source = new { name = $"Project {i}" }
}).ToArray()
}
};
var responseBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(response));
var connection = new InMemoryConnection(responseBytes, 200);
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(connectionPool, connection).DefaultIndex("project");
var client = new ElasticClient(settings);
var searchResponse = client.Search<Project>(s => s.MatchAll());
InMemoryConnection
配置为始终返回responseBytes
以及200个HTTP状态代码
我们现在可以断言searchResponse
是有效的,并且包含从我们的固定InMemoryConnection
响应中反序列化的文档
searchResponse.IsValid.Should().BeTrue();
searchResponse.Documents.Count.Should().Be(25);
改变HttpConnection
可能需要更改默认HttpConnection
的工作原理,例如,向请求添加X509证书,更改允许到端点的最大连接数等。
通过从HttpConnection
派生,可以改变连接的行为。 以下提供了一些例子
ServicePoint行为
如果您在桌面CLR上运行,您可以通过从HttpConnection
导出的IConnection
实现覆盖AlterServicePoint
来轻松覆盖当前ServicePoint
的特定属性
public class MyCustomHttpConnection : HttpConnection
{
protected override void AlterServicePoint(ServicePoint requestServicePoint, RequestData requestData)
{
base.AlterServicePoint(requestServicePoint, requestData);
requestServicePoint.ConnectionLimit = 10000;
requestServicePoint.UseNagleAlgorithm = true;
}
}
var connection = new MyCustomHttpConnection();
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(connectionPool, connection);
var client = new ElasticClient(settings);
连接限制从默认值80增加到更高,并且启用了Nagling,这在客户端默认禁用。
客户端通过.NET的内部连接池重新使用TCP连接,所以将连接限制更改为真正高的应该只有仔细考虑和测试才能完成。 这里仅举例说明。
X.509证书
可以通过覆盖源自HttpConnection
的IConnection
实现中的CreateHttpWebRequest
方法来从客户端向每个请求添加X509证书
public class X509CertificateHttpConnection : HttpConnection
{
protected override HttpWebRequest CreateHttpWebRequest(RequestData requestData)
{
var request = base.CreateHttpWebRequest(requestData);
request.ClientCertificates.Add(new X509Certificate("file_path_to_cert"));
return request;
}
}
如前所述,自定义连接的新实例将传递给ConnectionSettings
以便使用
var connection = new X509CertificateHttpConnection();
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(connectionPool, connection);
var client = new ElasticClient(settings);
使用证书
如果您已经在Elasticsearch上使用X-Pack或通过Elasticsearch之前的代理启用SSL,并且生成证书的证书颁发机构(CA)由运行客户端代码的计算机信任,则应该没有任何内容要通过HTTPS与客户端通过HTTPS与群集通信。
如果您使用自己的不受信任的CA,则.NET将不允许您默认对该端点进行HTTPS调用。使用.NET,您可以通过全局静态ServicePointManager.ServerCertificateValidationCallback
上的自定义验证回调来预先解决此问题。你会发现这样做的大多数例子将只是从验证回调函数返回true,并快速地回到日落。这是不可取的,因为它允许任何HTTPS流量在当前的AppDomain
中进行,无需任何验证。这是一个具体的例子:
想象一下,您部署一个通过NEST通过HTTPS与Elasticsearch交谈的Web应用程序,并且还使用一些第三方SOAP / WSDL端点;通过设置
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, errors) => true;
不会对与Elasticsearch和外部Web服务的HTTPS连接执行验证
验证配置
也可以使用.NET为每个服务端点设置回调,Elasticsearch.NET和NEST都通过连接设置ConnectionConfiguration
与Elasticsearch.Net和ConnectionSettings
与NEST进行通信)。 您可以在该处理程序中进行自己的验证,或者在静态类CertificateValidations
上使用我们随附的随处理程序中的一个。
两个最基本的是AllowAll
和DenyAll
,它们分别接受或拒绝我们节点的所有SSL流量。 这里有几个例子。
拒绝所有证书验证
这里我们使用拒绝所有证书验证的验证回调来设置ConnectionSettings
public class DenyAllCertificatesCluster : SslAndKpiXPackCluster
{
protected override ConnectionSettings ConnectionSettings(ConnectionSettings s) => s
.ServerCertificateValidationCallback((o, certificate, chain, errors) => false)
.ServerCertificateValidationCallback(CertificateValidations.DenyAll);
}
允许所有证书验证
这里我们使用一个验证回调来设置ConnectionSettings
,该回调允许所有的证书验证
public class AllowAllCertificatesCluster : SslAndKpiXPackCluster
{
protected override ConnectionSettings ConnectionSettings(ConnectionSettings s) => s
.ServerCertificateValidationCallback((o, certificate, chain, errors) => true)
.ServerCertificateValidationCallback(CertificateValidations.AllowAll);
}
允许证书颁发机构的证书
如果您的客户端应用程序可以在本地访问公共CA证书,则Elasticsearch.NET和NEST会附带一些方便的帮助者,可以断言服务器提供的证书是来自本地CA的证书。
如果您使用X-Pack的certgen
工具来生成SSL证书,则生成的节点证书不会包含证书链中的CA,以减少SSL握手大小。 在这种情况下,您可以使用CertificateValidations.AuthorityIsRoot
并将其CA公钥的本地副本传递给它,以断言使用它生成服务器的证书
public class CertgenCaCluster : SslAndKpiXPackCluster
{
protected override ConnectionSettings ConnectionSettings(ConnectionSettings s) => s
.ServerCertificateValidationCallback(
CertificateValidations.AuthorityIsRoot(new X509Certificate(this.Node.FileSystem.CaCertificate))
);
}
如果您的本地副本与服务器的CA不匹配,则客户端将无法连接
public class BadCertgenCaCluster : SslAndKpiXPackCluster
{
protected override ConnectionSettings ConnectionSettings(ConnectionSettings s) => s
.ServerCertificateValidationCallback(
CertificateValidations.AuthorityPartOfChain(new X509Certificate(this.Node.FileSystem.UnusedCaCertificate))
);
}
如果您购买供应商生成的SSL证书,则通常的做法是将CA和任何中间CA包含在证书链中。 当使用这样的证书时,请使用CertificateValidations.AuthorityPartOfChain
来验证本地CA证书是用于生成服务器密钥的链的一部分。
客户证书
X-Pack还允许您配置PKI领域,以通过客户端证书进行用户身份验证。 X-Pack附带的certgen
工具还可以生成客户端证书,并将证书的可分辨名称(DN)分配给具有特定角色的用户。
certgen默认情况下只生成一个公共证书.cer
)和一个私有密钥.key。要使用客户端证书进行身份验证,您需要同时提供一个证书。最简单的方法是从.cer
和.key
生成一个pfx或p12文件,并使用新的X509Certificate(pathToPfx)将它们附加到请求。
如果您没有办法运行openssl或Pvk2Pfx作为部署的一部分,客户端将随附一个方便的帮手,通过将路径传递给certgen输出的.cer和.key文件,即时生成一个。可惜的是,这种功能在.NET Core中不可用,因为无法在运行时用于生成pfx文件的加密服务提供程序中设置PublicKey属性。
您可以将客户端证书设置为在ConnectionSettings
上的所有连接上使用
public class PkiCluster : CertgenCaCluster
{
public override ConnectionSettings Authenticate(ConnectionSettings s) => s
.ClientCertificate(
ClientCertificate.LoadWithPrivateKey(
//在ConnectionSettings上设置客户端证书
//.cer文件的路径
//.key文件的路径
//私钥的密码
this.Node.FileSystem.ClientCertificate,
this.Node.FileSystem.ClientPrivateKey,
"")
);
//hide
protected override string[] AdditionalServerSettings => base.AdditionalServerSettings.Concat(new[]
{
"xpack.security.authc.realms.file1.enabled=false",
"xpack.security.http.ssl.client_authentication=required"
}).ToArray();
}
或者根据RequestConfiguration
的请求,它将优先于在ConnectionConfiguration
上定义的请求
对象初始化程序语法示例
new RootNodeInfoRequest
{
RequestConfiguration = new RequestConfiguration
{
ClientCertificates = new X509Certificate2Collection { new X509Certificate2(this.Certificate) }
}
}
流畅的DSL示例
s => s
.RequestConfiguration(r => r
.ClientCertificate(this.Certificate)
)