教程:基于双向跨集群复制的灾难恢复

编辑

教程:基于双向跨集群复制的灾难恢复编辑

了解如何基于双向跨集群复制在两个集群之间设置灾难恢复。以下教程适用于支持通过查询更新通过查询删除的数据流。您只能在领导者索引上执行这些操作。

本教程以 Logstash 作为摄取源。它利用了 Logstash 的一项功能,即Logstash 到 Elasticsearch 的输出可以在指定的多个主机之间进行负载均衡。Beats 和 Elastic Agent 目前不支持多个输出。在本教程中,也可以设置代理(负载均衡器)来重定向流量,而无需使用 Logstash。

  • clusterAclusterB上设置远程集群。
  • 使用排除模式设置双向跨集群复制。
  • 使用多个主机设置 Logstash,以便在灾难期间自动进行负载均衡和切换。
Bi-directional cross cluster replication failover and failback

初始设置编辑

  1. 在两个集群上设置远程集群。

    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"
            }
          }
        }
      }
    }
  2. 设置双向跨集群复制。

    ### 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。

  3. 设置 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 集群端点。

    在两个集群上为同一个用户设置相同的密码,以使用此负载均衡功能。

  4. 使用之前的配置文件启动 Logstash。

    ### On Logstash server ###
    bin/logstash -f multiple_hosts.conf
  5. 观察数据流中的文档计数。

    该设置会在每个集群上创建一个名为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 个文档
  6. 应设置查询以搜索两个数据流。在任一集群上对logs*的查询总共返回 100 个匹配项。

    response = client.search(
      index: 'logs*',
      size: 0
    )
    puts response
    GET logs*/_search?size=0

clusterA关闭时的故障转移编辑

  1. 您可以通过关闭任一集群来模拟这种情况。在本教程中,让我们关闭集群 A
  2. 使用相同的配置文件启动 Logstash。(在 Logstash 持续摄取的实际用例中,不需要此步骤。)

    ### On Logstash server ###
    bin/logstash -f multiple_hosts.conf
  3. 观察所有 Logstash 流量都将自动重定向到集群 B

    在此期间,您还应该将所有搜索流量重定向到clusterB集群。

  4. 集群 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恢复时的故障恢复编辑

  1. 您可以通过重新启动集群 A来模拟这种情况。
  2. 集群 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 个文档
  3. 如果此时 Logstash 正在运行,您还会观察到流量被发送到两个集群。

执行通过查询更新或删除编辑

可以更新或删除文档,但您只能在领导者索引上执行这些操作。

  1. 首先确定哪个后备索引包含您要更新的文档。

    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>-*",则您需要在执行搜索查询的同一个集群上继续执行下一步。
  2. 执行通过查询更新(或删除)

    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