# 部署

ES 常见的部署架构:

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

# 版本

  • ElasticSearch、Kibana 的开源版本又称为社区版(OSS),只提供了基础功能。其它功能通过一组闭源插件 x-pack 提供。

    • x-pack 提供的 Monitoring、Grok Debugger 等功能是免费使用的,属于 basic license ,但 Security、Alerting 等功能是收费的。
    • 详见 Elastic 公司的 订阅列表 (opens new window)
  • v1.0

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

    • :于 2017 年发布。
    • 创建索引时,只能定义一个 type ,默认命名为 _doc 。
  • v7.0

    • :于 2019 年发布。
    • 创建索引时,建议不包含 type 。
    • number_of_shards 默认值从 5 改为 1 。
    • 终端日志改为 JSON 格式。
    • 默认配置了 "search.max_open_scroll_context": 500 。建议将 scroll 请求改为 PIT + search_after 请求。
    • 从 v6.8、v7.1 版本开始,将 x-pack 中的 RBAC 身份认证、TLS 加密通信改为免费功能。
      • 启用方法:在 elasticsearch.yml 中加入 xpack.security.enabled: true ,然后执行 bin/elasticsearch-setup-passwords auto 生成各个内置用户的密码。
    • v7.8 新增了可组合的索引模板(composable index template)。
    • v7.10 新增了 PIT(point in time)。
  • v8.0

    • :于 2022 年发布。
    • 创建索引时,禁用 type 。
    • 内置字段 _id 默认禁用 fielddata ,避免占用大量 JVM 内存,因此不支持 aggregations、sorting、scripting 操作。给集群配置 "indices.id_field_data.enabled": true 才会启用。
    • 初次部署 ES 时,默认会自动修改 config/elasticsearch.yml 文件,启用 x-pack 中的 RBAC 身份认证、TLS 加密通信。
      • 它会自动生成自签名的 TLS 证书文件,保存到 config/certs/ 目录下,有三个文件:
        http_ca.crt     # CA 证书文件,用于签署 http.p12 证书
        http.p12        # ES 提供 HTTP 端口供客户端访问时,采用该证书进行 TLS 加密通信
        transport.p12   # ES 集群的各节点通过 TCP 端口相互通信时,采用该证书进行 TLS 加密通信
        
      • 用户需要执行以下命令,为内置用户生成随机密码。
        bin/elasticsearch-reset-password --url https://localhost:9200 -u elastic
        bin/elasticsearch-reset-password --url https://localhost:9200 -u kibana_system
        
      • 用户需要拷贝 config/certs/http_ca.crt 这个 CA 证书文件,给访问 ES 的客户端使用,例如:
        curl https://localhost:9200 --cacert http_ca.crt -u elastic
        
        如果客户端不使用 CA 证书文件,则不能验证 ES 服务器的身份,只能忽略 TLS 认证,例如:
        curl https://localhost:9200 -k -u elastic
        

# 单实例

# 部署

  • 下载二进制版:

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

    解压后运行:

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

    version: '3'
    
    services:
      elasticsearch:
        container_name: elasticsearch
        image: elasticsearch:7.10.0
        restart: unless-stopped
        ports:
          - 9200:9200
          # - 9300:9300
        volumes:
          - ./config:/usr/share/elasticsearch/config
          - ./data:/usr/share/elasticsearch/data
    
    • 容器内以非 root 用户运行服务,需要调整挂载目录的权限:
      mkdir -p data
      chown -R 1000 .
      

# 配置

  • ES 启动时会检查 Linux 主机是否满足以下条件,如果不满足则会发出警告。如果此时还配置了 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
    
    • JVM -Xmx 过低时,会频繁引发 GC ,增加 CPU 负载,增加 ES 读写耗时。
    • JVM -Xmx 不应该超过 32G ,否则会大幅降低 JVM Compressed oop 指针的效率,增加 CPU 负载。如果需要更多内存,则应该增加 ES 集群的节点数,横向扩容。
    • 主机应该留出一些空闲内存,相当于 JVM -Xmx 的 0.5~1 倍,用作 Page Cache ,提高 Lucene 读写磁盘的性能。
  • ES 的主配置文件是 config/elasticsearch.yml 。修改它之后,需要重启 ES 才会生效。

    • 部署 ES 集群时,修改一个 elasticsearch.yml 只会作用于一个 ES 节点,因此需要同步修改所有 ES 节点的配置文件。
  • elasticsearch.yml 的内容示例:

    cluster.name: cluster-1             # 该 ES 所属的集群名
    discovery.type: single-node         # 发现模式。这里取消发现集群的其它节点,从而部署成单实例
    node.name: node-1                   # 该 ES 的节点名,默认采用当前主机名
    # path.data: /var/data/elasticsearch
    # path.logs: /var/log/elasticsearch
    
    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 请求
    
    xpack.monitoring.enabled: false     # 是否启用对 ELK 自身的监控,默认为 true ,监控数据保存到索引 .monitoring-*
    
    # xpack.security.enabled: true                # 是否启用 security 功能,包括 RBAC 身份认证、TLS 加密通信等
    # xpack.security.http.ssl.enabled: true       # ES 提供 HTTP 端口供客户端访问时,是否启用 TLS 加密通信
    # xpack.security.transport.ssl.enabled: true  # ES 集群的各节点通过 TCP 端口相互通信时,采用启用 TLS 加密通信
    
  • ES 允许在运行时通过 API 修改一些配置参数,称为动态参数(Dynamic)。而其它配置参数称为静态参数(Static)。

    • 动态参数分为两种作用域:
      • persistent :持久配置,即使集群重启也会生效。
      • transient :暂时配置,在集群重启之后失效。
    • 集群按以下优先级顺序采用配置参数:
      • transient
      • persistent
      • 配置文件
      • 默认配置
    • 例:将一个参数的 transient 值设置为 null ,或者等集群重启,则会采用该参数的 persistent 值。
    • 修改动态参数的示例:
      PUT /_cluster/settings
      {
        "persistent": {
          "indices.id_field_data.enabled": false,       # 内置字段 _id 是否启用 fielddata ,ES v8 开始默认禁用
          "indices.recovery.max_bytes_per_sec": "50mb", # 每个节点执行 peer recovery 或 snapshot recovery 操作时,最大的 IO 速度
          "cluster.max_shards_per_node": 1000   # 每个数据节点最多打开的 shard 数量(包括主分片、副分片、unassigned_shards,不包括 closed 索引的分片),默认为 1000
        },
        "transient" : {
          "indices.recovery.max_bytes_per_sec" : "20mb"
        }
      }
      
  • 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 备份数据的几种方式:

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

# 集群

# 部署

  • 部署 ES 集群时,需要部署多个 ES 实例,在它们的 elasticsearch.yml 中都加入以下配置:

    # 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 节点启动时,会自动根据 discovery.seed_hosts 连接到其它 ES 节点,如果它们拥有相同的 cluster.name ,则组成同一个 ES 集群。
  • 初次启动 ES 集群时,尚未选举出主节点。第一个启动的 ES 节点应该属于主资格节点,并临时添加以下配置:

    cluster.initial_master_nodes:
      - node-1              # 指定当前节点的名称或 IP
    
    • 这表示初始的主资格节点有哪些,需要从中选举出一个节点,担任主节点。
    • ES 集群初次启动成功之后,即可删除 cluster.initial_master_nodes 配置。此后如果重启 ES 节点、新增 ES 节点,会自动根据 discovery.seed_hosts 连接到其它 ES 节点,获知当前的主节点地址。

# 节点

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

    • 全部节点中,有且仅有一个主节点(master),负责管理集群,比如增删索引、分配分片给某个节点。
  • 一个 ES 节点可以担任多种角色:

    • master
      • :主资格节点(master-eligible),有资格被选举为主节点。
      • ES 集群中可存在一个或多个主资格节点,会自动选举出一个节点,担任主节点。
      • 只有主资格节点有权参与主节点的选举投票,data、coordinating 等角色的节点无权参与 。
      • 可以给某个主资格节点配置 node.voting_only: true ,表示只参与选举投票,不会当选。
    • 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        # 查询所有节点的状态
    
  • 例:查询所有节点

    [root@CentOS ~]# 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
    
  • 例:查询集群的基本信息

    [root@CentOS ~]# 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"
    }
    
  • 例:查询集群的健康状态

    [root@CentOS ~]# 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 :存在不可用的主分片。
  • 例:查询所有索引的状态

    [root@CentOS ~]# 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   test_log EaDptPz9TtqGk-CNL-yTMg   1   1          1            0      4.4kb          4.4kb
    
    • health 表示分片的状态,status 表示索引是否被关闭。
    • 这里索引的 health 为 yellow ,是因为只部署了单实例 ES ,而副分片不能被分配到主分片所在节点上,导致一直处于未分配状态。

# 远程集群

  • 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  /test_log/_search                # 不指定集群名,则默认查询本地集群
    GET  /cluster_1:test_log/_search      # 可以指定一个集群进行查询
    GET  /test_log,cluster_1:test_log,cluster_2:test_log/_search    # 可以指定多个集群进行查询
    
  • 可创建指向远程集群的 index pattern ,例如:

    cluster_1:test_log