Rubin's Blog

  • 首页
  • 关于作者
  • 隐私政策
享受恬静与美好~~~
分享生活的点点滴滴~~~
  1. 首页
  2. Elasticsearch
  3. 正文

Elasticsearch之企业级高可用分布式集群

2021年 12月 6日 960点热度 0人点赞 0条评论

核心概念

  • 集群(Cluster):一个Elasticsearch集群由多个节点(Node)组成,每个集群都有一个共同的集群名称作为标识
  • 节点(Node):一个Elasticsearch实例即一个Node,一台机器可以有多个实例,正常使用下每个实例都应该会部署在不同的机器上。Elasticsearch的配置文件中可以通过node.master、node.data来设置节点类型。node.master:true代表的是有资格竞选主节点、false代表的是没有资格竞选主节点。node.data:表示节点是否存储数据(true\false)
  • 分片:每个索引有1个或多个分片,每个分片存储不同的数据。分片可分为主分片(primary shard)和复制分片(replica shard),复制分片是主分片的拷贝。默认每个主分片有一个复制分片,每个索引的复制分片的数量可以动态地调整,复制分片从不与它的主分片在同一个节点上
  • 副本:这里指主分片的副本分片(主分片的拷贝)(副本有两个作用:提高恢复能力:当主分片挂掉时,某个复制分片可以变成主分片;提高性能:get 和 search 请求既可以由主分片又可以由复制分片处理)

Node节点组合如下:

  • 主节点+数据节点(master+data)(默认):节点既有成为主节点的资格,又存储数据
node.master: true
node.data: true
  • 数据节点(data):节点没有成为主节点的资格,不参与选举,只会存储数据
node.master: false
node.data: true
  • 客户端节点(client):不会成为主节点,也不会存储数据,主要是针对海量请求的时候可以进行负载均衡
node.master: false
node.data: false

Elasticsearch分布式架构

Elasticseasrch的架构遵循其基本概念:一个采用Restful API标准的高扩展性和高可用性的实时数据分析的全文搜索引擎。

特性如下:

  • 高扩展性:体现在Elasticsearch添加节点非常简单,新节点无需做复杂的配置,只要配置好集群信息将会被集群自动发现
  • 高可用性:因为Elasticsearch是分布式的,每个节点都会有备份,所以宕机一两个节点也不会出现问题,集群会通过备份进行自动复盘
  • 实时性:使用倒排索引来建立存储结构,搜索时常在百毫秒内就可完成

分层如下:

第一层 —— Gateway:

Elasticsearch支持的索引快照的存储格式,es默认是先把索引存放到内存中,当内存满了之后再持久化到本地磁盘。gateway对索引快照进行存储,当Elasticsearch关闭再启动的时候,它就会从这个gateway里面读取索引数据;支持的格式有:本地的Local FileSystem、分布式的Shared FileSystem、Hadoop的文件系统HDFS、Amazon(亚马逊)的S3。

第二层 —— Lucene框架:

Elasticsearch基于Lucene(基于Java开发)框架。

第三层 —— Elasticsearch数据的加工处理方式:

Index Module(创建Index模块)、Search Module(搜索模块)、Mapping(映射)、River。River代表es的一个数据源(运行在Elasticsearch集群内部的一个插件,主要用来从外部获取获取异构数据,然后在Elasticsearch里创建索引;常见的插件有RabbitMQ River、Twitter River)。

第四层 —— Elasticsearch发现机制、脚本:

Discovery是Elasticsearch自动发现节点的机制的模块,Zen Discovery和 EC2 Discovery。EC2:亚马逊弹性计算云 EC2 Discovery主要在亚马云平台中使用。Zen Discovery作用就相当于SolrCloud中的ZooKeeper。Zen Discovery 从功能上可以分为两部分,第一部分是集群刚启动时的选主,或者是新加入集群的节点发现当前集群的Master。第二部分是选主完成后,Master和Folower的相互探活。

Scripting是脚本执行功能,有这个功能能很方便对查询出来的数据进行加工处理。

3rd Plugins表示Elasticsearch支持安装很多第三方的插件,例如elasticsearch-ik分词插件、elasticsearch-sql插件。

第五层 —— Elasticsearch的交互方式:

有Thrift、Memcached、Http三种协议,默认的是用Http协议传输。

第六层 —— Elasticsearch的API支持模式:

RESTFul Style API风格的API接口标准是当下十分流行的。Elasticsearch作为分布式集群,客户端到服务端,节点与节点间通信有TCP和Http通信协议,底层实现为Netty框架。

解析Elasticsearch的分布式架构

分布式架构的透明隐藏特性

Elasticsearch是一个分布式系统,隐藏了复杂的处理机制。

分片机制:将文本数据切割成n个小份存储在不同的节点上,减少大文件存储在单个节点上对设备带来的压力。

分片的副本:在集群中某个节点宕掉后,通过副本可以快速对缺失数据进行复盘。

  • 集群发现机制(cluster discovery):在当前启动了一个Elasticsearch进程,再启动第二个Elasticsearch进程时,这个进程将作为一个Node自动就发现了集群,并自动加入,前提是这些Node都必须配置一套集群信息
  • Shard负载均衡:例如现在由10个Shard(分片),集群中由三个节点,Elasticsearch会进行均衡的分配,以保持每个节点均衡的负载请求

扩容机制

  • 垂直扩容:用新机器替换已有的机器,服务器台数不变容量增加
  • 水平扩容:直接增加新机器,服务器台数和容量都增加

rebalance

增加或减少节点时会自动负载。

主节点

主节点的主要职则是和集群操作的相关内容,如创建或删除索引,跟踪哪些节点是集群的一部分,并决定哪些分片分配给相关的节点。稳定的主节点对集群的健康是非常重要的。

节点对等

每个节点都能接受请求,每个节点接受到请求后都能把该请求路由到有相关数据的其它节点上,接受原始请求的节点负责采集数据并返回给客户端。

集群环境搭建

我们搭建一个三个节点的集群环境,由于资源有限,我这边只在一台服务器上来演示主从环境。

调整虚拟机内存到3G以上。

操作系统服务器ip端口号是否能成为主节点
Centos7192.168.211.1369200是
Centos7192.168.211.1369201是
Centos7192.168.211.1369202是

节点搭建

elasticsearch.yml配置文件说明:

配置项作用
cluster.name集群名称,相同名称为一个集群
node.name节点名称,集群模式下每个节点名称唯一
node.master当前节点是否可以被选举为master节点,是:true、否:false
node.data当前节点是否用于存储数据,是:true、否:false
path.data索引数据存放的位置
path.logs日志文件存放的位置
bootstrap.memory_lock需求锁住物理内存,是:true、否:false
network.host监听地址,用于访问该es
http.portes对外提供的http端口,默认 9200
transport.port节点选举的通信端口 默认是9300
discovery.seed_hostses7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点
cluster.initial_master_nodeses7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举Master
http.cors.enabled是否支持跨域,是:true,在使用head插件时需要此配置
http.cors.allow-origin "*"表示支持所有域名

我们要只需要在之前的基础上,打开配置文件elasticsearch.yml,添加如下配置:

cluster.name: my-es  #集群名称
node.name: node-1 # 节点名称 
node.master: true #当前节点是否可以被选举为master节点,是:true、否:false
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300 
# 初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node-1","node-2","node-3"]
# 写入候选主节点的设备地址 ---
discovery.seed_hosts: ["127.0.0.1:9300", "127.0.0.1:9301","127.0.0.1:9302"]
http.cors.enabled: true
http.cors.allow-origin: "*"

修改完配置文件之后,一定要把之前的data目录下node数据删除再重新启动服务。

第二节点配置

拷贝原来的ES节点elasticsearch并命名为elasticsearch1,并授权:

cp elasticsearch/ elasticsearch1 -rf
chown -R estest elasticsearch1

进入elasticsearch1目录config文件夹,修改elasticsearch.yml配置文件并保存:

# 修改node.name 和 http.port transport.port
node.name: node-2
http.port: 9201
transport.port: 9301
#启动从环境1 一定要用estest用户来执行
cd bin/
./elasticsearch  

第三节点配置

拷贝第一个节点 并命名为elasticsearch2,并授权:

cp elasticsearch/ elasticsearch2 -rf
chown -R estest elasticsearch2

进入elasticsearch2目录config文件夹,修改elasticsearch.yml配置文件并保存:

# 修改node.name 和 http.port transport.port
node.name: node-3
http.port: 9202
transport.port: 9302
#启动从环境1 一定要用estest用户来执行
cd bin/
./elasticsearch 

简单验证:http://127.0.0.1:9200/_cat/health?v。

Elasticsearch Head插件介绍及安装和验证主从环境

Elasticsearch Head插件介绍及安装

elasticsearch-head是一个界面化的集群操作和管理工具,可以对集群进行傻瓜式操作。你可以通过插件把它集成到ES。

es-head主要有三个方面的操作:

  1. 显示集群的拓扑,能够快速访问并显示集群的状态类,并且能够执行索引和节点级别操作
  2. 搜索接口能够查询集群中原始json或表格格式的检索数据
  3. 有一个输入窗口,允许任意调用RESTful API

官方的文档: https://github.com/mobz/elasticsearch-head。

elasticsearch-head安装

EalsticSearch只是后端提供各种api,那么怎么直观的使用它呢?elasticsearch-head将是一款专门针对于EalsticSearch的客户端工具。elasticsearch-head下载地址:https://github.com/mobz/elasticsearch-head elasticsearch-head,它是一个基于NodeJS的前端工程。

NodeJS安装:

# 下载
wget https://nodejs.org/dist/v10.15.3/node-v10.15.3-linux-x64.tar.xz  

# 解压
tar xf node-v10.15.3-linux-x64.tar.xz  
# 进入解压目录  
cd node-v10.15.3-linux-x64/  
# 执行node命令 查看版本       
./bin/node -v                

解压文件的bin目录底下包含了node、npm等命令,我们可以使用ln命令来设置软连接:

ln -s /root/node-v10.15.3-linux-x64/bin/npm  /usr/local/bin/
ln -s /root/node-v10.15.3-linux-x64/bin/node  /usr/local/bin/

phantomjs安装配置:

cd /usr/local
wget https://github.com/Medium/phantomjs/releases/download/v2.1.1/phantomjs-
2.1.1-linux-x86_64.tar.bz2
# 注意安装
yum install -y bzip2
tar -jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2
vim /etc/profile
export PATH=$PATH:/usr/local/phantomjs-2.1.1-linux-x86_64/bin
# 注意环境变量$Path移动在最前面
source /etc/profile

elasticsearch-head安装:

npm install -g cnpm --registry=https://registry.npm.taobao.org
yum -y install git
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
cnpm install

elasticsearch-head发现主机并连接,elasticsearch.yml配置文件修改(如果之前设置过 可以忽略这一步):

http.cors.enabled: true
http.cors.allow-origin: "*"

启动:

npm run start

启动完成后,我们用elasticsearch-head查看,主从环境配置是否正常:

http://127.0.0.1:9100

集群规划

我们需要多大规模的集群

需要从以下两个方面考虑

  1. 当前的数据量有多大?数据增长情况如何?
  2. 你的机器配置如何?cpu、多大内存、多大硬盘容量?

推算的依据

Elasticsearch JVM heap最大可以设置32G。

30G heap大概能处理的数据量10T。如果内存很大如128G,可在一台机器上运行多个ES节点实例。

备注:集群规划满足当前数据规模+适量增长规模即可,后续可按需扩展。

两类应用场景

  • 用于构建业务搜索功能模块,且多是垂直领域的搜索。数据量级几千万到数十亿级别。一般2-4台机器的规模
  • 用于大规模数据的实时OLAP(联机处理分析),经典的如ELK Stack,数据规模可能达到千亿或更多。几十到上百节点的规模

集群中的节点角色如何分配

节点角色

  • node.master: true节点可以作为主节点
  • node.data: true默认是数据节点
  • Coordinate Node是协调节点,一个节点只作为接收请求、转发请求到其他节点、汇总各个节点返回数据等功能的节点,就叫协调节点,如果仅担任协调节点,将上两个配置设为false

说明:一个节点可以充当一个或多个角色,默认三个角色都有。

节点角色如何分配:

  • 小规模集群,不需严格区分
  • 中大规模集群(十个以上节点),应考虑单独的角色充当。特别并发查询量大,查询的合并量大,可以增加独立的协调节点。角色分开的好处是分工分开,不互影响。如不会因协调角色负载过高而影响数据节点的能力

如何避免脑裂问题

脑裂问题:一个集群中只有一个A主节点,A主节点因为需要处理的东西太多或者网络过于繁忙,从而导致其他从节点ping不通A主节点,这样其他从节点就会认为A主节点不可用了,就会重新选出一个新的主节点B。过了一会A主节点恢复正常了,这样就出现了两个主节点,导致一部分数据来源于A主节点,另外一部分数据来源于B主节点,出现数据不一致问题,这就是脑裂。

6.x和之前版本尽量避免脑裂,需要添加最小数量的主节点配置:

discovery.zen.minimum_master_nodes: (有master资格节点数/2) + 1

这个参数控制的是,选举主节点时需要看到最少多少个具有Master资格的活节点,才能进行选举。官方的推荐值是(N/2)+1,其中N是具有master资格的节点的数量。

在新版7.X的ES中,对ES的集群发现系统做了调整,不再有discovery.zen.minimum_master_nodes这个控制集群脑裂的配置,转而由集群自主控制,并且新版在启动一个新的集群的时候需要有cluster.initial_master_nodes初始化集群列表。

在ES7中,discovery.zen.* 开头的参数,有些已经失效:

常用做法(中大规模集群):

  1. Master和DataNode角色分开,配置奇数个Master,如3
  2. 单播发现机制,配置Master资格节点(5.0之前):discovery.zen.ping.multicast.enabled: false —— 关闭多播发现机制,默认是关闭的
  3. 延长ping Master的等待时长:discovery.zen.ping_timeout: 30(默认值是3秒)——其他节点ping主节点多久时间没有响应就认为主节点不可用了(ES7中换成了discovery.request_peers_timeout)

索引应该设置多少个分片

说明:分片数指定后不可变,除非重建索引。

分片设置的可参考原则:

ElasticSearch推荐的最大JVM堆空间是30~32G,所以把你的分片最大容量限制为30GB,然后再对分片数量做合理估算。例如,你认为你的数据能达到200GB,推荐你最多分配7到8个分片。

在开始阶段,一个好的方案是根据你的节点数量按照1.5~3倍的原则来创建分片。例如,如果你有3个节点,则推荐你创建的分片数最多不超过9(3x3)个。当性能下降时,增加节点,ES会平衡分片的放置。

对于基于日期的索引需求,并且对索引数据的搜索场景非常少。 也许这些索引量将达到成百上千,但每个索引的数据量只有1GB甚至更小。对于这种类似场景,建议只需要为索引分配1个分片。如日志管理就是一个日期的索引需求,日期索引会很多,但每个索引存放的日志数据量就很少。

分片应该设置几个副本

副本设置基本原则:为保证高可用,副本数设置为2即可。要求集群至少要有3个节点,来分开存放主分片、副本。
如发现并发量大时,查询性能会下降,可增加副本数,来提升并发查询能力。

注意:新增副本时主节点会自动协调,然后拷贝数据到新增的副本节点,副本数是可以随时调整的!

PUT /my_temp_index/_settings
{
  "number_of_replicas": 1
}

分布式集群调优策略

Index(写)调优

副本数置0

如果是集群首次灌入数据,可以将副本数设置为0,写入完毕再调整回去,这样副本分片只需要拷贝,节省了索引过程。

PUT /my_temp_index/_settings
{
  "number_of_replicas": 0
}

自动生成doc ID

通过Elasticsearch写入流程可以看出,如果写入doc时如果外部指定了id,则Elasticsearch会先尝试读取原来doc的版本号,以判断是否需要更新。这会涉及一次读取磁盘的操作,通过自动生成doc ID可以避免这个环节。

合理设置mappings

  • 将不需要建立索引的字段index属性设置为not_analyzed或no。对字段不分词,或者不索引,可以减少很多运算操作,降低CPU占用。 尤其是binary类型,默认情况下占用CPU非常高,而这种类型进行分词通常没有什么意义
  • 减少字段内容长度,如果原始数据的大段内容无须全部建立索引,则可以尽量减少不必要的内容
  • 使用不同的分析器(analyzer),不同的分析器在索引过程中运算复杂度也有较大的差异

调整_source字段

_source字段用于存储doc原始数据,对于部分不需要存储的字段,可以通过includes excludes过滤,或者将_source禁用,一般用于索引和数据分离,这样可以降低 I/O 的压力,不过实际场景中大多不会禁用_source。

对analyzed的字段禁用norms

 Norms用于在搜索时计算doc的评分,如果不需要评分,则可以将其禁用:

"title": {
  "type": "string",
  "norms": {
   "enabled": false
    }
}

调整索引的刷新间隔

该参数缺省是1s,强制ES每秒创建一个新segment,从而保证新写入的数据近实时的可见、可被搜索到。比如该参数被调整为30s,降低了刷新的次数,把刷新操作消耗的系统资源释放出来给index操作使用。

PUT /my_index/_settings
{
 "index" : {
     "refresh_interval": "30s"
    }
}

这种方案以牺牲可见性的方式,提高了index操作的性能。

批处理

批处理把多个index操作请求合并到一个batch中去处理,和MySQL的jdbc的bacth有类似之处。如图:

比如每批1000个documents是一个性能比较好的size。每批中多少document条数合适,受很多因素影响而不同,如单个document的大小等。ES官网建议通过在单个node、单个shard做性能基准测试来确定这个参数的最优值。

Document的路由处理

当对一批中的documents进行index操作时,该批index操作所需的线程的个数由要写入的目的shard的个数决定。看下图:

上图中,有2批documents写入ES,每批都需要写入4个shard,所以总共需要8个线程。如果能减少shard的个数,那么耗费的线程个数也会减少。例如下图,两批中每批的shard个数都只有2个,总共线程消耗个数4个,减少一半。

默认的routing就是id,也可以在发送请求的时候,手动指定一个routing value,比如说put/index/doc/id?routing=user_id。

值得注意的是线程数虽然降低了,但是单批的处理耗时可能增加了。和提高刷新间隔方法类似,这有可能会延长数据不见的时间。

Search(读)调优

在存储的Document条数超过10亿条后,我们如何进行搜索调优。

数据分组

多人拿ES用来存储日志,日志的索引管理方式一般基于日期的,基于天、周、月、年建索引。如下图,基于天建索引:

当搜索单天的数据,只需要查询一个索引的shards就可以。当需要查询多天的数据时,需要查询多个索引的shards。这种方案其实和数据库的分表、分库、分区查询方案相比,思路类似,小数据范围查询而不是大海捞针。

开始的方案是建一个index,当数据量增大的时候,就扩容增加index的shard的个数。当shards增大时,要搜索的shards个数也随之显著上升。基于数据分组的思路,可以基于client进行数据分组,每一个client只需依赖自己的index的数据shards进行搜索,而不是所有的数据shards,大大提高了搜索的性能,如下图:

使用Filter替代Query

在搜索时候使用Query,需要为Document的相关度打分。使用Filter,没有打分环节处理,做的事情更少,而且Filter理论上更快一些。

如果搜索不需要打分,可以直接使用Filter查询。如果部分搜索需要打分,建议使用bool查询。这种方式可以把打分的查询和不打分的查询组合在一起使用,如:

GET /_search
{
 "query": {
  "bool": {
   "must": {
    "term": {
     "user": "kimchy"
   }
  },
   "filter": {
    "term": {
     "tag": "tech"
     }
    }
   }
  }
}

ID字段定义为keyword

一般情况,如果ID字段不会被用作range类型搜索字段,都可以定义成keyword类型。这是因为keyword会被优化,以便进行terms查询。Integers等数字类的mapping类型,会被优化来进行range类型搜索。

将integers改成keyword类型之后,搜索性能大约能提升30%。

别让用户的无约束的输入拖累了ES集群的性能

为了不让用户无约束的查询语句拖累ES集群的查询性能,可以限制用户用来查询的keywords。对于可以用来查询的keyworkds,也可以写成文档来帮助用户更正确的使用。

以上就是本文的全部内容。欢迎小伙伴们积极留言交流~~~

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: Elasticsearch
最后更新:2022年 6月 9日

RubinChu

一个快乐的小逗比~~~

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复
文章目录
  • 核心概念
  • Elasticsearch分布式架构
    • 解析Elasticsearch的分布式架构
      • 分布式架构的透明隐藏特性
      • 扩容机制
      • rebalance
      • 主节点
      • 节点对等
  • 集群环境搭建
    • 节点搭建
    • 第二节点配置
    • 第三节点配置
    • Elasticsearch Head插件介绍及安装和验证主从环境
      • Elasticsearch Head插件介绍及安装
      • elasticsearch-head安装
  • 集群规划
    • 我们需要多大规模的集群
      • 需要从以下两个方面考虑
      • 推算的依据
      • 两类应用场景
    • 集群中的节点角色如何分配
      • 节点角色
    • 如何避免脑裂问题
    • 索引应该设置多少个分片
    • 分片应该设置几个副本
  • 分布式集群调优策略
    • Index(写)调优
      • 副本数置0
      • 自动生成doc ID
      • 合理设置mappings
      • 调整_source字段
      • 对analyzed的字段禁用norms
      • 调整索引的刷新间隔
      • 批处理
      • Document的路由处理
    • Search(读)调优
      • 数据分组
      • 使用Filter替代Query
      • ID字段定义为keyword
      • 别让用户的无约束的输入拖累了ES集群的性能
最新 热点 随机
最新 热点 随机
问题记录之Chrome设置屏蔽Https禁止调用Http行为 问题记录之Mac设置软链接 问题记录之JDK8连接MySQL数据库失败 面试系列之自我介绍 面试总结 算法思维
RabbitMQ之架构与实战 算法之排序 SpringBoot之日志框架 java并发编程之ForkJoinPool MySQL之事务和锁 java并发编程之并发容器

COPYRIGHT © 2021 rubinchu.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

京ICP备19039146号-1