Elasticsearch集群
1.集群节点
- ELasticsearch的集群是由多个节点组成的,通过cluster.name设置集群名称,并且用于区分其它的集群,每个节点通过node.name指定节点的名称。在Elasticsearch中,节点的类型主要有4种:
- master节点
- 配置文件中node.master属性为true(默认为true),就有资格被选为master节点。
- master节点用于控制整个集群的操作。比如创建或删除索引,管理其它非master节点等。
- data节点
- 配置文件中node.data属性为true(默认为true),就有资格被设置成data节点。
- data节点主要用于执行数据相关的操作。比如文档的CRUD。
- 客户端节点
- 配置文件中node.master属性和node.data属性均为false。
- 该节点不能作为master节点,也不能作为data节点。
- 可以作为客户端节点,用于响应用户的请求,把请求转发到其他节点
- 部落节点
- 当一个节点配置tribe.*的时候,它是一个特殊的客户端,它可以连接多个集群,在所有连接的集群上执行搜索和其他操作。
2.使用docker搭建集群
- 创建配置容器映射的相关配置文件目录
mkdir -p /data/es-cluster
cd /data/es-cluster
mkdir node01
mkdir node02
- 复制安装目录下的elasticsearch.yml、jvm.options文件
- 下载elasticsearch-6.5.4的压缩包 然后上传的自己的虚拟机并解压 找到里面的配置文件
链接:https://pan.baidu.com/s/1njjaDVZ6n1vvr3u7va01Nw
提取码:6wea
复制这段内容后打开百度网盘手机App,操作更方便哦
cp /usr/local/linux/elasticsearch/conf/elasticsearch.yml /data/es-cluster/node01
cp /usr/local/linux/elasticsearch/conf/jvm.options /data/es-cluster/node01
cp /usr/local/linux/elasticsearch/conf/elasticsearch.yml /data/es-cluster/node02
cp /usr/local/linux/elasticsearch/conf/jvm.options /data/es-cluster/node02
- 编辑node01的elasticsearch.yml
#修改:
cluster.name: es-cluster
node.name: node01
network.host: 192.168.56.132
http.port: 9200
#有几个虚拟机就写几个虚拟机的地址["ip1","ip2"]
discovery.zen.ping.unicast.hosts: ["192.168.56.132"]
#成为主节点最少需要多少个从节点同意
discovery.zen.minimum_master_nodes: 1
#跨域
http.cors.enabled: true
http.cors.allow-origin: "*"
#增加:
#是否可以成为主节点
node.master: true
#是否可以成为从节点
node.data: true
- 编辑node02的elasticsearch.yml
#修改:
cluster.name: es-cluster
node.name: node02
network.host: 192.168.56.132
http.port: 9201
discovery.zen.ping.unicast.hosts: ["192.168.56.132"]
discovery.zen.minimum_master_nodes: 1
http.cors.enabled: true
http.cors.allow-origin: "*"
#增加:
node.master: false
node.data: true
- 修改node01、node02的 jvm.options 的jvm运行内存大小 都改为128m(生产环境至少512m)
-Xms512m
-Xmx512m
- 给 /data/es-cluster/ 赋予权限 因为elasticsearch要以非root用户启动 会没有权限报错
chmod 777 -R /data/es-cluster/
- 创建容器(ik分词器和拼音分词器参考上篇博客)
docker create --name es-node01 --net host \
-v /data/escluster/node01/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /data/es-cluster/node01/jvm.options:/usr/share/elasticsearch/config/jvm.options \
-v /data/es-cluster/ik:/usr/share/elasticsearch/plugins/ik
-v /data/es- cluster/pinyin:/usr/share/elasticsearch/plugins/pinyin
-v /data/es-cluster/node01/data:/usr/share/elasticsearch/data \
elasticsearch:6.5.4
docker create --name es-node02 --net host \
-v /data/escluster/node02/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /data/es-cluster/node02/jvm.options:/usr/share/elasticsearch/config/jvm.options \
-v /data/es-cluster/ik:/usr/share/elasticsearch/plugins/ik
-v /data/es- cluster/pinyin:/usr/share/elasticsearch/plugins/pinyin
-v /data/es-cluster/node02/data:/usr/share/elasticsearch/data \
elasticsearch:6.5.4
- 启动容器
docker start es-node01 && docker logs -f es-node01
docker start es-node02 && docker logs -f es-node02
- 查询集群状态:http://192.168.56.132:9200/_cluster/health
#响应:
{
"cluster_name": "es-itcast-cluster"
"status": "green",
"timed_out": false,
"number_of_nodes": 2,
"number_of_data_nodes": 2,
"active_primary_shards": 5,
"active_shards": 10,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"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": 100
}
集群状态的三种颜色:
颜色 | 意义 |
green | 所有主要分片和复制分片都可用 |
yellow | 所有主要分片可用,但不是所有复制分片都可用 |
red | 不是所有的主要分片都可用 |
3.分片和副本
为了将数据添加到Elasticsearch,我们需要索引(index)——一个存储关联数据的地方。实际上,索引只是一个用来指向一个或多个分片(shards)的“逻辑命名空间(logical namespace)”.
- 一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存了索引中所有数据的一部分。
- 我们需要知道是分片就是一个Lucene实例,并且它本身就是一个完整的搜索引擎。应用程序不会和它直接通信。
- 分片可以是主分片(primary shard)或者是复制分片(replica shard)。
- 索引中的每个文档属于一个单独的主分片,所以主分片的数量决定了索引最多能存储多少数据。
- 复制分片只是主分片的一个副本,它可以防止硬件故障导致的数据丢失,同时可以提供读请求,比如搜索或者从别的shard取回文档。
- 当索引创建完成的时候,主分片的数量就固定了,但是复制分片的数量可以随时调整。
故障转移
- 安装可视化工具"elasticsearch-head"参考我的博客:
1.准备工作
- 为了测试故障转移,需要再向集群中添加一个节点,并且将所有节点的node.master设置为true。
docker create --name es-node03 --net host \
-v /data/es-cluster/node03/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /data/es-cluster/node03/jvm.options:/usr/share/elasticsearch/config/jvm.options \
-v /data/es-cluster/ik:/usr/share/elasticsearch/plugins/ik
-v /data/es- cluster/pinyin:/usr/share/elasticsearch/plugins/pinyin
-v /data/es-cluster/node03/data:/usr/share/elasticsearch/data \
elasticsearch:6.5.4
#重启所有节点
docker stop es-node01 es-node02
docker start es-node01 es-node02 es-node03
- 查看集群状态(此时没有任何索引):node02为主节点。
- 创建测试索引haoke:
- 分片结果
2.将 data节点停止
- 停止node01
docker stop es-node01
- 说明:
- 需要连接到node2或node03的端口进行查看状态
- 当前集群状态为黄色,表示主节点可用,副本节点不完全可用
- 过一段时间观察,发现节点列表中看不到node01,副本节点分配到了node02和node03,集群状态恢复到绿色。
- 只有当副本数+1=现有节点数才会剔除掉下线的节点 不然集群状态还是黄色 下线的节点不会剔除
- 将node01恢复:
docker start es-node01
可以看到,node01恢复后,重新加入了集群,并且重新分配了节点信息。
2.将master节点停止
- 将node02停止
docker stop es-node02
- 从结果中可以看出,集群对master进行了重新选举,选择node03为master。并且集群状态变成黄色。
集群状态从黄色变为了绿色。 - 恢复node02节点
docker start es-node02
3.脑裂问题
- 解决方案:
- 思路:不能让节点很容易的变成master,必须有多个节点认可后才可以。
- 设置minimum_master_nodes的大小为2
- 官方推荐:(N/2)+1,N为集群中节点数
- 这里修改我们三个配置文件的 minimum_master_nodes=2(3/2=1.5,所以取2)
- 测试
- node02为主,宕机之后
- node02恢复后,正常加入到了集群:
分布式文档
1.文档路由
- 当我们想一个集群保存文档时,文档该存储到哪个节点呢? 是随机吗? 是轮询吗?
实际上,在ELasticsearch中,会采用计算的方式来确定存储到哪个节点,计算公式如下:
shard = hash(routing) % number_of_primary_shards
- routing值是一个任意字符串,它默认是_id但也可以自定义。
- 这个routing字符串通过哈希函数生成一个数字,然后除以主切片的数量得到一个余(remainder),余数的范围永远是0到number_of_primary_shards - 1,这个数字就是特定文档所在的分片。
- 这就是为什么创建了主分片后,不能修改的原因。
2.文档的写操作
- 在主分片和复制分片上成功新建、索引或删除一个文档必要的顺序步骤:
- 客户端给 Node 1 发送新建、索引或删除请求。
- 节点使用文档的 _id 确定文档属于分片 0 。它转发请求到 Node 3 ,分片 0 位于这个节点上。
- Node 3 在主分片上执行请求,如果成功,它转发请求到相应的位于 Node 1 和 Node 2 的复制节点上。当所有的复制节点报告成功, Node 3 报告成功到请求的节点,请求的节点再报告给客户端。
- 客户端接收到成功响应的时候,文档的修改已经被应用于主分片和所有的复制分片。你的修改生效了。
3.搜索文档(单个文档)
- 文档能够从主分片或任意一个复制分片被检索。
- 在主分片或复制分片上检索一个文档必要的顺序步骤:
- 客户端给 Node 1 发送get请求。
- 节点使用文档的 _id 确定文档属于分片 0 。分片 0 对应的复制分片在三个节点上都有。此时,它转发请求到 Node 2 。
- Node 2 返回文档(document)给 Node 1 然后返回给客户端。
- 对于读请求,为了平衡负载,请求节点会为每个请求选择不同的分片——它会循环所有分片副本。
- 可能的情况是,一个被索引的文档已经存在于主分片上却还没来得及同步到复制分片上。这时复制分片会报告文档未找到,主分片会成功返回文档。一旦索引请求成功返回给用户,文档则在主分片和复制分片都是可用的。
- 所以必须在返回写入成功之后再读
4.全文搜索
对于全文搜索而言,文档可能分散在各个节点上,那么在分布式的情况下,如何搜索文档呢?
搜索,分为2个阶段,搜索(query)+取回(fetch)。
- 搜索(query)
查询阶段包含以下三步:
- 客户端发送一个 search(搜索) 请求给 Node 3 , Node 3 创建了一个长度为 from+size 的空优先级队
- Node 3 转发这个搜索请求到索引中每个分片的原本或副本。每个分片在本地执行这个查询并且结果将结果到一个大小为 from+size 的有序本地优先队列里去。
- 每个分片返回document的ID和它优先队列里的所有document的排序值给协调节点 Node 3 。 Node 3 把这些值合并到自己的优先队列里产生全局排序结果。
- 取回(fetch)
分发阶段由以下步骤构成:
- 协调节点辨别出哪个document需要取回,并且向相关分片发出 GET 请求。
- 每个分片加载document并且根据需要丰富(enrich)它们,然后再将document返回协调节点。
- 一旦所有的document都被取回,协调节点会将结果返回给客户端。