教程:基于双向跨集群复制的灾难恢复
编辑教程:基于双向跨集群复制的灾难恢复编辑
了解如何基于双向跨集群复制在两个集群之间设置灾难恢复。以下教程适用于支持通过查询更新和通过查询删除的数据流。您只能在领导者索引上执行这些操作。
本教程以 Logstash 作为摄取源。它利用了 Logstash 的一项功能,即Logstash 到 Elasticsearch 的输出可以在指定的多个主机之间进行负载均衡。Beats 和 Elastic Agent 目前不支持多个输出。在本教程中,也可以设置代理(负载均衡器)来重定向流量,而无需使用 Logstash。
- 在
clusterA
和clusterB
上设置远程集群。 - 使用排除模式设置双向跨集群复制。
- 使用多个主机设置 Logstash,以便在灾难期间自动进行负载均衡和切换。
初始设置编辑
-
在两个集群上设置远程集群。
response = client.cluster.put_settings( body: { persistent: { cluster: { remote: { "clusterB": { mode: 'proxy', skip_unavailable: true, server_name: 'clusterb.es.region-b.gcp.elastic-cloud.com', proxy_socket_connections: 18, proxy_address: 'clusterb.es.region-b.gcp.elastic-cloud.com:9400' } } } } } ) puts response response = client.cluster.put_settings( body: { persistent: { cluster: { remote: { "clusterA": { mode: 'proxy', skip_unavailable: true, server_name: 'clustera.es.region-a.gcp.elastic-cloud.com', proxy_socket_connections: 18, proxy_address: 'clustera.es.region-a.gcp.elastic-cloud.com:9400' } } } } } ) puts response
### On cluster A ### PUT _cluster/settings { "persistent": { "cluster": { "remote": { "clusterB": { "mode": "proxy", "skip_unavailable": true, "server_name": "clusterb.es.region-b.gcp.elastic-cloud.com", "proxy_socket_connections": 18, "proxy_address": "clusterb.es.region-b.gcp.elastic-cloud.com:9400" } } } } } ### On cluster B ### PUT _cluster/settings { "persistent": { "cluster": { "remote": { "clusterA": { "mode": "proxy", "skip_unavailable": true, "server_name": "clustera.es.region-a.gcp.elastic-cloud.com", "proxy_socket_connections": 18, "proxy_address": "clustera.es.region-a.gcp.elastic-cloud.com:9400" } } } } }
-
设置双向跨集群复制。
### On cluster A ### PUT /_ccr/auto_follow/logs-generic-default { "remote_cluster": "clusterB", "leader_index_patterns": [ ".ds-logs-generic-default-20*" ], "leader_index_exclusion_patterns":"*-replicated_from_clustera", "follow_index_pattern": "{{leader_index}}-replicated_from_clusterb" } ### On cluster B ### PUT /_ccr/auto_follow/logs-generic-default { "remote_cluster": "clusterA", "leader_index_patterns": [ ".ds-logs-generic-default-20*" ], "leader_index_exclusion_patterns":"*-replicated_from_clusterb", "follow_index_pattern": "{{leader_index}}-replicated_from_clustera" }
即使模式可能匹配,集群上的现有数据也不会被
_ccr/auto_follow
复制。此功能只会复制新创建的后备索引(作为数据流的一部分)。使用
leader_index_exclusion_patterns
避免递归。follow_index_pattern
只允许使用小写字符。由于 UI 中缺少排除模式,因此无法通过 Kibana UI 执行此步骤。请使用此步骤中的 API。
-
设置 Logstash 配置文件。
此示例使用输入生成器来演示集群中的文档计数。请根据您自己的用例重新配置此部分。
### On Logstash server ### ### This is a logstash config file ### input { generator{ message => 'Hello World' count => 100 } } output { elasticsearch { hosts => ["https://clustera.es.region-a.gcp.elastic-cloud.com:9243","https://clusterb.es.region-b.gcp.elastic-cloud.com:9243"] user => "logstash-user" password => "same_password_for_both_clusters" } }
关键点是,当
集群 A
关闭时,所有流量都会自动重定向到集群 B
。一旦集群 A
恢复,流量就会自动重定向回集群 A
。这是通过选项hosts
实现的,其中在数组[clusterA, clusterB]
中指定了多个 ES 集群端点。在两个集群上为同一个用户设置相同的密码,以使用此负载均衡功能。
-
使用之前的配置文件启动 Logstash。
### On Logstash server ### bin/logstash -f multiple_hosts.conf
-
观察数据流中的文档计数。
该设置会在每个集群上创建一个名为
logs-generic-default
的数据流。当两个集群都启动时,Logstash 会将 50% 的文档写入集群 A
,将另外 50% 的文档写入集群 B
。双向跨集群复制会在每个集群上再创建一个数据流,并带有
-replication_from_cluster{a|b}
后缀。在此步骤结束时-
集群 A 上的数据流包含
logs-generic-default-replicated_from_clusterb
中有 50 个文档logs-generic-default
中有 50 个文档
-
集群 B 上的数据流包含
logs-generic-default-replicated_from_clustera
中有 50 个文档logs-generic-default
中有 50 个文档
-
-
应设置查询以搜索两个数据流。在任一集群上对
logs*
的查询总共返回 100 个匹配项。response = client.search( index: 'logs*', size: 0 ) puts response
GET logs*/_search?size=0
clusterA
关闭时的故障转移编辑
- 您可以通过关闭任一集群来模拟这种情况。在本教程中,让我们关闭
集群 A
。 -
使用相同的配置文件启动 Logstash。(在 Logstash 持续摄取的实际用例中,不需要此步骤。)
### On Logstash server ### bin/logstash -f multiple_hosts.conf
-
观察所有 Logstash 流量都将自动重定向到
集群 B
。在此期间,您还应该将所有搜索流量重定向到
clusterB
集群。 -
集群 B
上的两个数据流现在包含不同数量的文档。-
集群 A(关闭)上的数据流
logs-generic-default-replicated_from_clusterb
中有 50 个文档logs-generic-default
中有 50 个文档
-
集群 B(启动)上的数据流
logs-generic-default-replicated_from_clustera
中有 50 个文档logs-generic-default
中有 150 个文档
-
clusterA
恢复时的故障恢复编辑
- 您可以通过重新启动
集群 A
来模拟这种情况。 -
在
集群 A
关闭期间摄取到集群 B
的数据将自动复制。-
集群 A 上的数据流
logs-generic-default-replicated_from_clusterb
中有 150 个文档logs-generic-default
中有 50 个文档
-
集群 B 上的数据流
logs-generic-default-replicated_from_clustera
中有 50 个文档logs-generic-default
中有 150 个文档
-
- 如果此时 Logstash 正在运行,您还会观察到流量被发送到两个集群。
执行通过查询更新或删除编辑
可以更新或删除文档,但您只能在领导者索引上执行这些操作。
-
首先确定哪个后备索引包含您要更新的文档。
response = client.search( index: 'logs-generic-default*', filter_path: 'hits.hits._index', body: { query: { match: { 'event.sequence' => '97' } } } ) puts response
### On either of the cluster ### GET logs-generic-default*/_search?filter_path=hits.hits._index { "query": { "match": { "event.sequence": "97" } } }
- 如果匹配项返回
"_index": ".ds-logs-generic-default-replicated_from_clustera-<yyyy.MM.dd>-*"
,则您需要在集群 A
上继续执行下一步。 - 如果匹配项返回
"_index": ".ds-logs-generic-default-replicated_from_clusterb-<yyyy.MM.dd>-*"
,则您需要在集群 B
上继续执行下一步。 - 如果匹配项返回
"_index": ".ds-logs-generic-default-<yyyy.MM.dd>-*"
,则您需要在执行搜索查询的同一个集群上继续执行下一步。
- 如果匹配项返回
-
执行通过查询更新(或删除)
response = client.update_by_query( index: 'logs-generic-default', body: { query: { match: { 'event.sequence' => '97' } }, script: { source: 'ctx._source.event.original = params.new_event', lang: 'painless', params: { new_event: 'FOOBAR' } } } ) puts response
### On the cluster identified from the previous step ### POST logs-generic-default/_update_by_query { "query": { "match": { "event.sequence": "97" } }, "script": { "source": "ctx._source.event.original = params.new_event", "lang": "painless", "params": { "new_event": "FOOBAR" } } }
如果软删除在复制到跟随者之前被合并,则以下过程将失败,因为领导者上的历史记录不完整,有关详细信息,请参阅index.soft_deletes.retention_lease.period。