# 部署

ES 常见的部署架构:

  • 单实例
  • 集群
    • 由多个实例组成分布式集群,获得更大的容量、更高的性能,还可通过冗余节点提高可用性。
  • 远程集群
    • 远程集群与本地集群之间独立工作,但可以查询、拷贝其数据,实现横向扩容。

# 版本

  • v1.0 :于 2010 年发布。最初由 Shay Banon 开发,后来由 Elastic 公司管理。
  • v6.0 :于 2017 年发布。
  • v7.0 :于 2019 年发布。
  • v8.0 :于 2022 年发布。

# 单实例

# 部署

  • 下载二进制版:

    wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.0-linux-x86_64.tar.gz
    

    解压后运行 ES 服务器:

    bin/elasticsearch       # 在前台运行
                      -d    # 以 daemon 方式运行
    
    • 运行时需要 JDK 环境,不过二进制发行版自带了一个 JDK 。
    • 安装插件时,只需将插件解压到 plugins 目录下。
  • 或者用 Docker 部署:

    docker run -d --name elasticsearch \
               -p 9200:9200 \
               elasticsearch:7.10.0
    

# 配置

ES 服务器的配置文件是 config/elasticsearch.yml ,内容示例:

cluster.name: cluster-1             # 该 ES 所属的集群名
discovery.type: single-node         # 取消发现集群的其它节点,从而部署成单示例
node.name: node-1                   # 该 ES 的节点名,默认为当前主机名

network.host: 0.0.0.0               # 该 ES 的 Socket 绑定的 IP
network.publish_host: 10.0.0.1      # 该 ES 公布给集群中其它 ES 的 IP ,供它们访问。默认等于 network.host
# transport.port: 9300              # TCP 通信监听的端口,供集群中其它 ES 节点访问

# 关于 HTTP API
# http.port: 9200                   # HTTP 通信监听的端口,供用户访问
# http.max_initial_line_length: 4kb # 允许接收的 HTTP 请求的 URL 长度
# http.max_header_size: 8kb         # 允许接收的 HTTP 请求的 header 体积
# http.max_content_length: 100mb    # 允许接收的 HTTP 请求的 body 体积(解压之后)
# http.compression: true            # 是否压缩 HTTP 响应的 body
# http.compression_level: 3         # 压缩级别,取值范围为 1~9 ,9 的压缩率最高
# http.cors.enabled: false          # 是否允许 CORS 请求

path.data: /var/data/elasticsearch
path.logs: /var/log/elasticsearch

xpack.monitoring.enabled: false     # 是否启用对 ELK 自身的监控,默认为 true ,监控数据保存到索引 .monitoring-*
  • ES 存在多种断路器,用于在 ES 占用内存达到一定阈值时,拒绝新的读、写请求,返回 HTTP 503: circuit_breaking_exception 。
    • 如果没有断路器,ES 可能占用内存过大而被 OOM 杀死。
    • 相关配置:
      indices.breaker.total.limit: 70%      # parent 断路器,用于限制所有断路器的内存总量,默认为 JVM 堆内存的 70%
      indices.breaker.fielddata.limit: 70%  # fielddata 断路器,用于限制 fielddata 缓存,默认为 JVM 堆内存的 40%
      indices.breaker.request.limit: 60%    # request 断路器,用于限制所有请求的占用的内存,比如聚合运算
      

# 运行环境

  • ES 启动时会检查以下环境条件是否满足,如果不满足则会发出警告。如果此时还配置了 network.host 参数,则 ES 会按生产环境严格要求,将这些警告升级为异常。

    • 禁用 Swap 分区:
      • 需要执行命令 swapoff -a ,并且将 /etc/fstab 文件中的 swap 分区都注释。
    • 增加进程虚拟内存的上限:
      • 需要执行命令 sysctl vm.max_map_count=262144 ,并在 /etc/sysctl.conf 文件中永久修改该参数。
    • 增加进程数量的上限:
      • 需要执行命令 ulimit -u 4096 ,并在 /etc/security/limits.conf 文件中永久修改该参数。
    • 增加文件描述符数量的上限:
      • 需要执行命令 ulimit -n 65535 ,并在 /etc/security/limits.conf 文件中永久修改该参数。
  • 可以在 config/jvm.options 文件中配置 ES 的 JVM :

    -Xms4g
    -Xmx4g
    -XX:MaxDirectMemorySize=2g    # 建议设置为 -Xmx 的一半
    
    • JVM -Xmx 过低时,会频繁引发 GC ,增加 CPU 负载,增加 ES 读写耗时。
    • JVM -Xmx 最多为 32G ,否则会大幅降低 Java 对象指针的效率,增加 CPU 负载。
    • 主机应该留出一些空闲内存,相当于 JVM -Xmx 的 0.5~1 倍,用作 Page Cache ,提高 Lucene 读写磁盘的性能。

# 备份数据

ES 备份数据的几种方式:

  • 通过 Snapshot API 创建快照文件。
    • 适合离线备份,备份速度快。
  • 通过 reindex API 将远程集群的数据拷贝到本地集群。

# 集群

# 部署

  • 部署 ES 集群时,需要部署多个 ES 实例,然后在它们的配置文件中都加入如下配置:

    # discovery.type: single-node   # 不设置该参数,则默认会寻找集群的其它节点
    
    discovery.seed_hosts:   # 声明该集群的所有节点,默认值为 127.0.0.1、[::1]
      - 10.0.0.1:9300
      - 10.0.0.2:9300
      - 10.0.0.3:9300
    
    • ES 服务器启动之后,会自动检查这些节点,如果存在其它 ES 服务器,并且拥有相同的集群名,则组成同一个集群。
  • 部署一个新集群时,还需要声明初始的主资格节点:

    cluster.initial_master_nodes:
      - node-1              # 这里使用节点名,不使用 IP
      - node-2
      - node-3
    

# 节点

  • 一个 ES 集群(cluster)中的每个 ES 实例称为一个节点(node)。

  • 集群中有且仅有一个主节点,负责管理集群,比如增删索引、分配分片给节点。

  • 一个 ES 节点可以担任多种角色:

    • master
      • :主资格节点(master-eligible),有资格被选为主节点。
      • 只有主资格节点可以参与主节点的选举投票。
    • data
      • :数据节点,负责存储数据,支持增删查改、聚合等操作。
      • master 和 data 节点都需要使用 path.data 目录。
    • ingest
      • :摄取节点,负责将管道应用于文档,以便在建立索引之前加工文档。
    • ml
      • :机器学习节点。集群至少拥有一个此类节点才能提供机器学习功能。
    • remote_cluster_client
      • :远程集群节点,可以连接到远程集群,作为其客户端。
    • transform
      • :转换节点。提供转换功能。
    • coordinating
      • :协调节点。它是每个节点的隐式角色,不能取消。
      • 每个节点都知道各个文档存储在哪个节点上,也默认可以处理用户的 HTTP 请求。
        因此用户可以向任意节点发出查询请求,该节点会将请求转发给存储相应文档的数据节点(可能有多个),然后将查询结果返回给用户。
  • 节点的默认角色配置如下:

    node.master: true
    node.voting_only: false   # 是否只参与主节点选举,而不担任主节点
    node.data: true
    node.ingest: true
    node.ml: true
    cluster.remote.connect: true
    
  • 在以下情况下,主资格节点会发起主节点的选举:

    • 发现它自己不是主节点。
    • 询问其它节点,发现大家都没有连接到主节点。
    • 发现有至少 discovery.zen.minimum_master_nodes 个主资格节点没有连接到主节点。 该参数的默认值为:主资格节点总数/2 + 1
  • ES 集群的高可用方案:

    • 部署至少 3 个主资格节点,其中至少 2 个节点为 node.voting_only: false ,从而可以通过选举更换主节点。
    • 不能同时停止 50% 数量的主资格节点,否则集群会不能投票决策。但可以分多次停止。
    • 让每个节点专注于一种角色,以减少不相关的工作负担。比如配置专用的主节点:
      node.master: true
      node.voting_only: false
      node.data: false
      node.ingest: false
      node.ml: false
      cluster.remote.connect: false
      

# 管理

  • 相关 API :

    GET  /                    # 查询集群的基本信息
    GET  /_cluster/stats      # 查询集群的统计信息
    GET  /_cluster/health     # 查询集群的健康状态
    GET  /_cluster/settings   # 查询集群的配置
    
    GET  /_nodes              # 查询所有节点的配置
    GET  /_nodes/stats        # 查询所有节点的状态
    
  • 例:查询所有节点

    [[email protected] ~]# curl 127.0.0.1:9200/_cat/nodes?v
    ip         heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
    10.0.0.1             11          85   1    0.06    0.09     0.18 dilm      *      node-1
    
  • 例:查询集群的基本信息

    [[email protected] ~]# curl 127.0.0.1:9200
    {
      "name" : "node-1",
      "cluster_name" : "cluster-1",
      "cluster_uuid" : "cDXF4mIeRqK4Dlj_YmSSoA",
      "version" : {
        "number" : "7.10.0",
        "build_flavor" : "default",
        "build_type" : "tar",
        "build_hash" : "7f634e9f44834fbc12724506cc1da681b0c3b1e3",
        "build_date" : "2020-02-06T00:09:00.449973Z",
        "build_snapshot" : false,
        "lucene_version" : "8.4.0",
        "minimum_wire_compatibility_version" : "6.8.0",
        "minimum_index_compatibility_version" : "6.0.0-beta1"
      },
      "tagline" : "You Know, for Search"
    }
    
  • 例:查询集群的健康状态

    [[email protected] ~]# curl 127.0.0.1:9200/_cluster/health?pretty
    {
      "cluster_name" : "cluster-1",
      "status" : "yellow",            # 集群的状态
      "timed_out" : false,
      "number_of_nodes" : 1,          # 节点的数量
      "number_of_data_nodes" : 1,     # 数据节点的数量
      "active_shards" : 4,            # 可用分片的数量,包括主分片、副分片,不包括未分配的分片
      "active_primary_shards" : 4,    # 可用主分片的数量
      "relocating_shards" : 0,
      "initializing_shards" : 0,
      "unassigned_shards" : 4,        # 未分配的分片的数量
      "delayed_unassigned_shards" : 0,
      "number_of_pending_tasks" : 0,
      "number_of_in_flight_fetch" : 0,
      "task_max_waiting_in_queue_millis" : 0,
      "active_shards_percent_as_number" : 50.0
    }
    
    • status 的可能取值:
      • green :所有主分片、副分片都可用。
      • yellow :所有主分片都可用,但存在不可用的副分片。
      • red :存在不可用的主分片。
  • 例:查询所有索引的状态

    [[email protected] ~]# curl 127.0.0.1:9200/_cat/indices?v
    health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
    yellow open   class   aeUT1h6QS8-vSAzoEclR3Q   1   1          0            0       283b           283b
    yellow open   student EaDptPz9TtqGk-CNL-yTMg   1   1          1            0      4.4kb          4.4kb
    
    • health 表示分片的状态,status 表示索引是否被关闭。
    • 这里索引的 health 为 yellow ,是因为只部署了单实例 ES ,而副分片不能被分配到主分片所在节点上,导致一直处于未分配状态。

# 配置

  • 用户可以在配置文件 elasticsearch.yml 中添加 ES 的配置参数,但这只会作用于当前 ES 节点。

  • 部分配置参数支持在 ES 运行时通过 API 修改,称为动态参数(Dynamic)。而其它配置参数称为静态参数(Static)。

    • 动态参数又分为两种作用域:
      • persistent :持久配置,即使集群重启也会生效。
      • transient :暂时配置,在集群重启之后失效。
    • 集群按以下优先级顺序采用配置参数:
      • transient
      • persistent
      • 配置文件
      • 默认配置
    • 例:将一个参数的 transient 值设置为 null ,或者等集群重启,则会采用该参数的 persistent 值。
  • 修改动态参数的示例:

    PUT /_cluster/settings
    {
      "persistent": {
        "indices.recovery.max_bytes_per_sec" : "50mb"
      }
      "transient" : {
        "indices.recovery.max_bytes_per_sec" : "20mb"
      }
    }
    

# 远程集群

  • ES 支持给本地集群添加多个远程集群(remote cluster)。
    • 这些集群之间会独立工作,独立存储自己的数据。
    • 这是单向连接,本地集群故障时不会影响远程集群,但远程集群故障时可能影响本地集群。
  • 用户可以跨集群搜索,同时查询本地集群和远程集群,从而实现 ES 的横向扩容。
    • 原理:
      1. 用户将跨集群的查询请求发送到本地集群。
      2. 本地集群验证用户的身份,如果有效,则将请求及用户的身份转发到远程集群。
      3. 远程集群验证用户的身份,如果有权访问指定的数据,则执行查询,然后将查询结果返回给本地集群。
      4. 本地集群将远程集群的查询结果返回给用户。
    • 本地集群使用的 SSL 公钥必须受到远程集群的信任。
    • 用户账号必须在本地集群、远程集群都存在。

# 配置

  • 可以在 elasticsearch.yml 文件中配置远程集群,但这只会对当前节点生效。如下:

    cluster:
      remote:
        cluster_1:                                  # 添加一个远程集群,该名称不必与目标集群的实际名称一致
          seeds:
            - 10.0.0.1:9300                         # 远程集群中的节点列表
        cluster_2:                                  # 添加另一个远程集群
          seeds:
            - 10.0.0.2:9300
          # transport.initial_connect_timeout: 30s  # 启动当前节点时,第一次连接到远程集群的超时时间
          # transport.ping_schedule: 30s            # 每隔多久检查与远程集群的连接是否正常正常,默认为 -1 ,即不检查
          # transport.compress: true                # 将请求压缩之后再发送到远程集群
          # skip_unavailable: false                 # 跨集群搜索时是否跳过不可用集群
    
  • 也可以通过 API 添加远程集群,上传其配置信息:

    PUT /_cluster/settings
    {
      "persistent": {
        "cluster": {
          "remote": {
            "cluster_1": {
              "seeds": [            # 设置 "seeds": null 则会删除该远程集群
                  "127.0.0.1:9300"
              ]
            },
            "cluster_2": {
              "seeds": [
                  "10.0.0.2:9300"
              ]
            }
          }
        }
      }
    }
    
  • 相关 API :

    GET  /_cluster/settings    # 查询集群的配置,包括远程集群
    GET  /_remote/info         # 查询远程集群的状态
    

# 查询

  • 使用 <cluster_name>:<index_name> 的格式,即可查询远程集群的索引:

    GET  /student/_search                # 不指定集群名,则默认查询本地集群
    GET  /cluster_1:student/_search      # 可以指定一个集群进行查询
    GET  /student,cluster_1:student,cluster_2:student/_search    # 可以指定多个集群进行查询
    
  • 可创建指向远程集群的 index pattern :

    cluster_1:student