title: elasticsearch介绍及集群部署 #标题tags: elasticsearch #标签
date: 2020-05-24
categories: elastic stack # 分类

历时12天,logstash的学习之路可以告一段落了,基本可以满足日常工需求,今天开始啃elasticsearch。

elasticsearch简介

elasticsearch(下面简称为es)是一个分布式文档存储,实时的分布式搜索分析引擎,内部使用lucene做索引和搜索。当你的es是多节点部署时(es集群),存储的文档会分布再整个集群中,并且可以从任何节点立即访问。

存储文档时,将在1s内几乎实时地对其进行索引和完全搜索。es使用称为倒排索引的数据结构,该结构支持非常快速的全文本搜索,反向索引列出了出现在任何文档中的每个唯一单词,并标识了每个单词出现的所有文档。

何为倒排索引?

索引是一种数据结构,它依据你的数据建造,最终会让搜索变得非常迅速(可以将索引当作我们书籍中的目录)。

例如,如果我们想通过标签来搜索博客文章,倒排序看上去,就会是下面的样子:

elasticsearch介绍及集群部署 - 图1

在上面的示例中,如果搜索含有elections标签的博文,那么相对于查找原始数据而言,查找倒排序索引后的数据会更快捷。在搜索引擎的应用场景下,这种数据结构带来的速度提升是非常必要的。

索引可以认为是文档的优化集合,每个文档都是字段的集合,这些字段是包含数据的键值对。默认情况下,es对每个字段中的所有数据建立索引,并且每个索引字段都具有专用的优化数据结构。

es还具有无模式的能力,这意味着可以为文档建立索引,而无需明确指定如何处理文档中可能出现的每个不同字段。启用动态映射后,es自动检测并将新字段添加到索引。这种默认行为使索引和浏览数据变得很容易-只需开始建立索引文档,es就会检测布尔值,浮点数和整数值,日期和字符串并将其映射到适当的es数据类型。

es的可伸缩和弹性

集群工作原理

es旨在始终可用,并可以根据您的需求进行扩展。它是通过自然分布来实现的。我们可以将es节点添加到集群以增加容量,es会自动在所有可用节点之间分配数据和查询负载。无需大修我们的程序,es知道如何平衡多节点集群以提供扩展性和高可用性。理论上讲,es节点越多越好。

那么es是怎么实现这个可扩展性的呢?在幕后,es索引实际上只是一个或多个物理分片的逻辑分组,其中每个分片实际上是一个独立的索引。通过在多个分片之间的索引中分配文档,并在多个节点之间分配这些分片,es可以确保冗余,这样既可以防止硬件故障,又可以在将节点添加到集群中使提高查询能力。随着集群的增长或收缩,es会自动迁移碎片以重新平衡集群。

分片是什么

分片有两种类型,主书库和副本数据库。索引中的每个文档都属于一个主分片。副本分片是主分片的副本。副本可提供数据的冗余副本,以防止硬件故障并增加处理读取请求(如搜索或检索文档)的能力。

创建索引时,索引中的主碎片的数量是固定的,但是副本碎片的数量可以随时修改,而不会中断索引或查询操作。

如何合理的设置分片大小和数量

在分片大小和为索引配置的主分片数量方面,存在许多性能方面的考虑和权衡取舍,分片越多,维护这些索引的开销就越大。分片越大,当es需要重新平衡集群时,分片移动所需的时间就越长。

查询很多小的分片会使每个分片的处理速度更快,但是更多的查询意味着更多的开销,因此查询较少数量的大分片可能会更快(系统开销也会少一些)。

那么,如何来合理的设置分片呢?我们可以用以下几点来作为参考:

  • 最好将平均分片大小保持在几GB到几十GB之间,对于具有基于时间的数据,通常会看到20GB到40GB范围内的分片。
  • 尽量避免庞大的分片问题。节点可以容纳的分片数量与可用堆空间成比例,一般情况下,每GB堆空间中的分片数量应少于20。

es的跨集群复制

出于性能原因,群集内的节点必须位于同一局域网内。跨不同数据中心中的节点在群集中平衡碎片的时间太长了。但是高可用性架构要求避免将所有鸡蛋都放在一个篮子里。如果一个位置发生重大故障,则另一个位置的服务器能够无缝的接管,这就要用到跨集群复制(CCR)。

CCR提供了一种方法,可以自动将索引从主群集同步到可以用作热备份的辅助远程群集。如果主群集发生故障,则辅助群集可以接管。还可以使用CCR创建辅助群集,以接近地理位置的方式向用户提供读取请求。

跨集群复制是主动-被动的。主群集上的索引是活动的领导者索引,并处理所有写请求。复制到辅助群集的索引是只读跟随者。

更通俗的理解es

为了理解es中数据是如何组织的,可以从以下两个角度来观察:

  • 逻辑设计:用于索引和搜索到最小单位是文档,可以将其认为是关系性数据库里的一行。文档以类型来分组,索引是更大的容器,如果这样说比较抽象,那么我们可以套在sql数据库上,你可以这样来理解:es中的文档 == 数据库中的行;es中的type == 数据库中的表;es中的索引 === 数据库中的库。
  • 物理设计:es将每个索引划分为分片,每个分片可以在集群中的不同服务器间迁移。

示意图如下:

elasticsearch介绍及集群部署 - 图2

es集群中的查询流程

查询操作可以在es中的主分片或副本分片上进行。

elasticsearch介绍及集群部署 - 图3

上图就是一个完整的查询过程,大概流程如下:

  • client向集群发送查询请求,集群再随机选择一个节点作为协调节点(NODE1),负责处理这次查询。
  • Node 1使用文档的routing id来计算要查询的文档再哪个分片上(再上面的图中,落在了分片0上),分片0的副本存在所有的节点上,这种情况下,协调节点可以把请求转发到任意节点,在上图中将请求转发到了node 2 上。
  • node 2 执行查找,并将查找结果返回给协调节点node 1,node 1 再将文档返回给client。

部署es集群

环境准备

系统 主机名 服务 IP
Cent OS 7.7 es1 es 192.168.20.3
Cent OS 7.7 es2 es 192.168.20.4
Cent OS 7.7 es3 es+kibana 192.168.20.5

注:所有主机节点均为4G内存,4个CPU。

注:以下操作在es1主机执行。

下载并解压

  1. [root@es3 local]# wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.6.2-linux-x86_64.tar.gz
  2. [root@es1 local]# tar zxf elasticsearch-7.6.2-linux-x86_64.tar.gz
  3. [root@es1 local]# mv elasticsearch-7.6.2 /usr/local/es
  4. [root@es1 local]# rm -rf elasticsearch-7.6.2-linux-x86_64.tar.gz

在上线生产环境之前,必须考虑以下设置:

  • 禁用交换风区
  • 增加文件描述符
  • 确保有足够的虚拟内存
  • 确保足够的线程
  • JVM DNS缓存设置

优化es

配置es的临时目录

默认情况下,Elasticsearch使用启动脚本在系统tmp目录下立即创建的私有临时目录。但我们最好为他配置专有的临时目录。

  1. [root@es1 bin]# vim /usr/local/es/bin/elasticsearch-env
  2. ES_TMPDIR=/data/es/tmp # 在第二行指定即可

配置jvm致命错误日志
  1. [root@es1 bin]# vim /usr/local/es/config/jvm.options
  2. -XX:ErrorFile=/data/es/logs/hs_err_pid%p.log

配置虚拟内存(官方推荐)

es默认使用mmapfs目录来存储索引。mmap计数的默认操作系统限制可能太低,这可能导致内存异常。

  1. [root@es1 config]# tail -1 /etc/sysctl.conf # 写入以下配置
  2. vm.max_map_count=262144
  3. vm.swappiness = 0
  4. [root@es1 config]# sysctl -p # 刷新配置
  5. vm.max_map_count = 262144
  6. vm.swappiness = 0

修改其默认使用内存大小
  1. [root@es1 es]# pwd
  2. /usr/local/es
  3. [root@es1 es]# vim config/jvm.options
  4. # elasticsearch默认内存使用为1G,可以更改如下配置,修改其默认使用内存
  5. -Xms700m
  6. -Xmx700m

注:生产环境中建议将Xms和Xmx两个值设置为一致(最多不要超过物理内存的50%),我们线上的环境是设置为8g。

禁用交换分区

大多数操作系统尝试使用尽可能多的内存作为文件系统缓存,并急切地交换出未使用的应用程序内存。这可能导致部分JVM堆或其可执行页面被交换到磁盘,交换对性能和节点稳定性非常不利,应该不惜一切代价避免交换。它可能导致垃圾收集持续几分钟而不是几毫秒,并且可能导致节点响应缓慢,甚至与集群断开连接。在弹性分布式系统中,让操作系统杀死节点更有效。

  1. $ swapoff -a #临时禁用
  2. $ grep swap /etc/fstab # 注释掉交换分区挂载项
  3. #/dev/mapper/centos-swap swap swap defaults 0 0
  4. $ free -h | grep -i swap # 确认交换分区已关闭
  5. Swap: 0B 0B 0B

修改其打开文件数的大小

如果服务器文件数上线和线程上线较低,就会产生如下异常:

  1. 1. max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]每个进程最大同时打开文件数太小
  2. 2. max number of threads [3818] for user [es] is too low, increase to at least [4096]最大线程个数太低

可以进行以下修改,以便修改可打开文件数的大小

  1. $ mv /etc/security/limits.conf{,.bak}
  2. $ cat >> /etc/security/limits.conf << EOF
  3. * - nofile 65535
  4. * - memlock unlimited
  5. * - stack 655360
  6. * - nproc unlimited
  7. EOF

修改es配置文件

关于日志的优化配置可以参考官方文档,一般默认即可,无需改动(官方文档修改的日志配置文件为/usr/local/es/config/log4j2.properties)。

  1. [root@es1 ~]# egrep -v '^$|^#' /usr/local/es/config/elasticsearch.yml
  2. cluster.name: my-es
  3. node.name: es1
  4. node.master: true
  5. node.data: false
  6. path.data: /data/es
  7. path.logs: /data/es/logs
  8. bootstrap.memory_lock: true
  9. network.host: 192.168.20.2 # 这里请指定具体IP,而不是0.0.0.0
  10. # 如果不指定具体IP,最后有大概率无法形成集群
  11. http.port: 9200 # 绑定传入http请求的端口
  12. transport.port: 9331 # 绑定用于群集间通信的端口
  13. discovery.seed_hosts:
  14. - es1:9331
  15. - es2:9331
  16. - es3:9331
  17. cluster.initial_master_nodes: # 定义初始集群时的节点,仅在第一次启动es时需要配置此项
  18. - es1 # 此名字必须和node.name一致。
  19. # 开启跨域访问
  20. http.cors.enabled: true
  21. http.cors.allow-origin: "*"

配置文件中的其他选项解释

配置数据存放路径

path.data设置可以被设置为多条路径,在这种情况下,所有的路径将被用于存储数据(虽然属于单个碎片文件将全部存储相同的数据路径上):

  1. path:
  2. data:
  3. - /data/es/elasticsearch_1
  4. - /data/es/elasticsearch_2
  5. - /data/es/elasticsearch_3

附加:docker stack/docker-compose启动es集群

以下yml文件来源于官方文档

  1. version: '2.2'
  2. services:
  3. es01:
  4. image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
  5. container_name: es01
  6. environment:
  7. - node.name=es01
  8. - cluster.name=es-docker-cluster
  9. - discovery.seed_hosts=es02,es03
  10. - cluster.initial_master_nodes=es01,es02,es03
  11. - bootstrap.memory_lock=true
  12. - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
  13. ulimits:
  14. memlock:
  15. soft: -1
  16. hard: -1
  17. volumes:
  18. - data01:/usr/share/elasticsearch/data
  19. ports:
  20. - 9200:9200
  21. networks:
  22. - elastic
  23. es02:
  24. image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
  25. container_name: es02
  26. environment:
  27. - node.name=es02
  28. - cluster.name=es-docker-cluster
  29. - discovery.seed_hosts=es01,es03
  30. - cluster.initial_master_nodes=es01,es02,es03
  31. - bootstrap.memory_lock=true
  32. - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
  33. ulimits:
  34. memlock:
  35. soft: -1
  36. hard: -1
  37. volumes:
  38. - data02:/usr/share/elasticsearch/data
  39. networks:
  40. - elastic
  41. es03:
  42. image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
  43. container_name: es03
  44. environment:
  45. - node.name=es03
  46. - cluster.name=es-docker-cluster
  47. - discovery.seed_hosts=es01,es02
  48. - cluster.initial_master_nodes=es01,es02,es03
  49. - bootstrap.memory_lock=true
  50. - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
  51. ulimits:
  52. memlock:
  53. soft: -1
  54. hard: -1
  55. volumes:
  56. - data03:/usr/share/elasticsearch/data
  57. networks:
  58. - elastic
  59. volumes:
  60. data01:
  61. driver: local
  62. data02:
  63. driver: local
  64. data03:
  65. driver: local
  66. networks:
  67. elastic:
  68. driver: bridge

es的启动与停止

第一种启停方式
  1. $ /usr/local/es/bin/elasticsearch & # 启动es
  2. $ jps | grep Elasticsearch # 停止es
  3. # 或者
  4. $ ps -ef | grep elasticsearch | xargs kill -SIGTERM

第二种启停方式
  1. $ ./bin/elasticsearch -p /tmp/elasticsearch.pid -d
  2. $ ps -ef | grep elasticsearch | grep -v grep # 查看到该程序的pid,也可以cat /tmp/elasticsearch.pid来查看pid号
  3. $ kill -SIGTERM 15516

停止时的致命错误

在Elasticsearch虚拟机的生命周期内,可能会出现某些致命错误,使虚拟机处于可疑状态。此类致命错误包括内存不足错误,虚拟机内部错误以及严重的I/O错误。

当Elasticsearch检测到虚拟机遇到此类致命错误时,Elasticsearch将尝试记录该错误,然后停止该虚拟机。当Elasticsearch启动此类关闭时,它不会如上所述进行有序关闭。Elasticsearch流程还将返回一个特殊的状态代码,以指示错误的性质。状态码如下:

错误信息 退出状态码
JVM内部错误 128
内存不足错误 127
堆栈溢出错误 126
未知的虚拟机错 125
严重的I/O错误 124
未知的致命错误 1

全集群重新启动和滚动重启操作

参考: 官方文档

启动es1节点

  1. $ useradd es # 创建es用户
  2. # 更改相应的目录属主
  3. $ chown -R es.es /usr/local/es/
  4. $ mkdir -p /data/es/{logs,tmp}
  5. $ chown -R es.es /data/es/
  6. # 使用es用户启动es程序,-p是指定pid文件名,-d是后台启动
  7. $ su -s /bin/bash -c "/usr/local/es/bin/elasticsearch -p /data/es/es.pid -d" es
  8. $ ss -lnpt | egrep "9200|9331" # 确定端口在监听
  9. LISTEN 0 128 :::9200 :::* users:(("java",pid=58589,fd=248))
  10. LISTEN 0 128 :::9331 :::* users:(("java",pid=58589,fd=222))
  11. # 当群集启动成功后,一定要删除配置的初始群集引导
  12. $ vim /usr/local/es/config/elasticsearch.yml # 修改配置文件,删除初始群集引导
  13. cluster.initial_master_nodes:
  14. - es1

将修改后的相应目录发送到其他节点

  1. # 在复制前,先在es2和es3上执行下面的指令创建es用户
  2. [root@es2 ~]# useradd es
  3. # 在es1上将es目录发送到其他节点
  4. [root@es1 ~]# for i in es{2..3};do rsync -avz /usr/local/es root@${i}:/usr/local/;done
  5. [root@es1 ~]# for i in es{2..3};do rsync -avz /etc/security/limits.conf root@${i}:/etc/security/;done
  6. [root@es1 ~]# for i in es{2..3};do rsync -avz /etc/sysctl.conf root@${i}:/etc/;done

配置es2主机

  1. # 确定某些限制已生效,若没有生效,请重新登录
  2. [root@es2 ~]$ ulimit -Hu
  3. 4096
  4. [root@es2 ~]$ ulimit -Hn
  5. 65536
  6. [root@es2 ~]# sysctl -p # 刷新配置
  7. vm.max_map_count = 262144
  8. vm.swappiness = 0
  9. [root@es2 ~]# mkdir -p /data/es/{logs,tmp}
  10. [root@es2 ~]# chown -R es.es /data/es
  11. [root@es2 ~]# chown -R es.es /usr/local/es
  12. # 修改es配置文件
  13. [root@es2 ~]# egrep -v '^$|^#' /usr/local/es/config/elasticsearch.yml
  14. cluster.name: my-es
  15. node.name: es2 # 这里改下名字
  16. node.master: true
  17. node.data: true # 这里改为true
  18. path.data: /data/es
  19. path.logs: /data/es/logs
  20. bootstrap.memory_lock: true
  21. network.host: 0.0.0.0
  22. http.port: 9200 # 绑定传入http请求的端口
  23. transport.port: 9331 # 绑定用于群集间通信的端口
  24. discovery.seed_hosts:
  25. - es1:9331
  26. - es2:9331
  27. - es3:9331 # 注意,删除了初始master引导配置
  28. http.cors.enabled: true
  29. http.cors.allow-origin: "*"
  30. [root@es2 ~]$ su -s /bin/bash -c "/usr/local/es/bin/elasticsearch -p /data/es/es.pid -d" es # 使用es用户后台启动es程序
  31. [root@es2 ~]$ ss -lnpt | egrep "9200|9331"
  32. LISTEN 0 128 :::9200 :::* users:(("java",pid=65224,fd=266))
  33. LISTEN 0 128 :::9331 :::* users:(("java",pid=65224,fd=222))

注:es3主机上,除了需要稍微改动下配置文件外,其他操作与es2完全一致,这里就不写了。参考下面更改后配置文件自行改动并启动下es。

  1. # es3主机的配置文件如下
  2. [root@es3 ~]# egrep -v '^$|^#' /usr/local/es/config/elasticsearch.yml
  3. cluster.name: my-es
  4. node.name: es3 # 改下node name
  5. node.master: true
  6. node.data: true
  7. path.data: /data/es
  8. path.logs: /data/es/logs
  9. bootstrap.memory_lock: true
  10. network.host: 0.0.0.0
  11. http.port: 9200 # 绑定传入http请求的端口
  12. transport.port: 9331 # 绑定用于群集间通信的端口
  13. discovery.seed_hosts:
  14. - es1:9331
  15. - es2:9331
  16. - es3:9331
  17. http.cors.enabled: true
  18. http.cors.allow-origin: "*"

当三台主机启动后,可以访问每个节点的9200端口,通过比较各个节点的uuid,来判断是否加入到同一个集群中,如下(如果uuid为“na”则表示群集有问题,虽然都是一样的,但绝对不正常,正常的话都是很长一串字母):

elasticsearch介绍及集群部署 - 图4

集群状态正常的话,是下面这样的:

elasticsearch介绍及集群部署 - 图5

三个节点的uuid一致,则表示在同一个集群中。

安装ElasticSearch Head

此应用用于管理es集群,任意一个节点安装即可,非必须安装,也可以使用chrome提供的插件:ElasticSearch Head。

  1. [root@es3 ~]# git clone git://github.com/mobz/elasticsearch-head.git
  2. [root@es3 ~]# cd elasticsearch-head/
  3. [root@es1 elasticsearch-head]# yum -y install npm openssl
  4. [root@es3 elasticsearch-head]# npm install
  5. [root@es3 elasticsearch-head]# npm run start &

由于上述安装方式比较费时间,我这里就使用谷歌的ElasticSearch Head插件了,访问界面如下:

elasticsearch介绍及集群部署 - 图6

安装kibana

由于kibana可以用来根据es集群的数据进行查询、绘制图表等。所以这里也将kibana部署上,后续操作,可能会在kibana上进行。

  1. # 下载并解压kibana
  2. [root@es1 ~]# wget https://artifacts.elastic.co/downloads/kibana/kibana-7.6.2-linux-x86_64.tar.gz
  3. [root@es1 ~]# tar zxf kibana-7.6.2-linux-x86_64_.tar.gz
  4. [root@es1 ~]# mv kibana-7.6.2-linux-x86_64 /usr/local/kibana
  5. [root@es1 ~]# cd /usr/local/kibana/config/
  6. [root@es1 config]# egrep -v '$^|^#' kibana.yml # 修改后的配置文件如下
  7. server.port: 5601 # 监听端口
  8. server.host: "0.0.0.0" # 监听地址
  9. # 指定es集群,必须在同一个集群内
  10. elasticsearch.hosts: ["http://es1:9200","http://es2:9200","http://es3:9200"]
  11. kibana.index: ".kibana" # 增加kibana索引,用于存储kibana保存的仪表盘、图饼等信息。
  12. elasticsearch.requestTimeout: 90000 # 连接es的超时时间
  13. i18n.locale: "zh-CN" # 配置kibana为中文

启动kibana

  1. [root@es1 ~]# useradd kibana
  2. [root@es1 ~]# chown -R kibana.kibana /usr/local/kibana/
  3. # 需要给这个文件666的权限,我尝试过给777权限,第一次可以启动,但再启动就会权限拒绝
  4. [root@es1 ~]# chmod 666 /usr/local/kibana/.i18nrc.json
  5. [root@es1 ~]# su -s /bin/bash -c "/usr/local/kibana/bin/kibana &" kibana

输出以下信息,则表示启动成功:

elasticsearch介绍及集群部署 - 图7

访问kibana主机5601端口

elasticsearch介绍及集群部署 - 图8

若选择了示例数据,则这里可以选择将这些仪表盘添加到kibana中,如下:

elasticsearch介绍及集群部署 - 图9

下面的索引中包含了kibana的默认索引

elasticsearch介绍及集群部署 - 图10