单机的ES做数据存储与搜索,必然面临两个问题:
因此,考虑使用ES集群:
利用3个docker容器模拟3个es的节点:
version: '2.2'
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
container_name: es01
environment:
- node.name=es01
- cluster.name=es-docker-cluster # 这里集群名称一样,集群名称相同的节点会形成集群
- discovery.seed_hosts=es02,es03 # 集群中另外两个节点的IP,但这里我用容器模拟了,用容器名就能互连
- cluster.initial_master_nodes=es01,es02,es03 # 集群有主从之分,这三个节点参与选举,产生主节点
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data01:/usr/share/elasticsearch/data
ports:
- 9200:9200
networks:
- elastic # 网络
es02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
container_name: es02
environment:
- node.name=es02
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data02:/usr/share/elasticsearch/data
ports:
- 9201:9200 # 宿主机9200已用,这里+1
networks:
- elastic
es03:
image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
container_name: es03
environment:
- node.name=es03
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es02
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data03:/usr/share/elasticsearch/data
networks:
- elastic
ports:
- 9202:9200
volumes:
data01:
driver: local
data02:
driver: local
data03:
driver: local
networks:
elastic:
driver: bridge
vi /etc/sysctl.conf
vm.max_map_count=262144
sysctl -p
docker-compose up -d
# yum install docker-compose
kibana可以监控es集群,但新版需要依赖es的x-pack功能,配置复杂,这里用cerebro来监控es集群状态
# 官网
https://github.com/lmenezes/cerebro
# 网盘
链接:https://pan.baidu.com/s/1dj4HgTZsVfFSe6-hR2ydnA?pwd=9527
提取码:9527
创建索引库
集群中,每个索引库的分片数量、副本数量都是在创建索引库时指定的,并且分片数量一旦设置以后无法修改。
语法如下:
PUT /test
{
"settings": {
"number_of_shards": 3, // 分片数量
"number_of_replicas": 1 // 副本数量
},
"mappings": {
"properties": {
// mapping映射定义 ...
}
}
}
在cerebro中创建索引库:
填索引库名和分片数、副本数:
查看overview,实线为主分片,虚线为副本分片:
集群节点职责:
ES集群中,不同的节点有不同的职责:
以上角色的默认值都为ture,但不同的角色职责不同,对硬件的要求也不同,有的对CPU要求高,有的对硬盘要求高,因此,应该每个节点都有自己独立的角色。举个例子如下图,每个节点专门干一件事:
脑裂:
默认情况下,每个节点都是master eligible节点,因此一旦master节点宕机,其它候选节点会选举一个成为主节点。但当主节点只是与其他节点有暂时的网络通信故障时:
备选节点联系不上主节点,以为主节点宕机,选举出一个新的master,由此产生两个主节点,当网络恢复,就会出现数据不一致的情况。
为了避免脑裂,需要要求选票超过 ( eligible节点数量 + 1 )/ 2 才能当选为主,因此eligible节点数量最好是奇数。对应配置项是discovery.zen.minimum_master_nodes 。在es7.0以后,已经成为默认配置,因此一般不会发生脑裂问题
没启动kibana,直接调接口插入三条doc:(在9201,即es01节点插入数据)
查询文档,不管在9201、9202、9203,三个节点都能查到数据:
这是协调节点工作的结果,当新增文档时,它会将数据保存到不同分片,保证数据均衡。而coordinating node确实数据存到哪个分片是根据:
存储和查询都依赖这个算法,因此分片数量不能再变,否则按某个分分片数量存进去后,分片数量改变,等查的时候按这个算法计算找文档就找不到了。
新增文档流程:
当然,根据id查询,还是这么个流程。但如果不知道文档id,该怎么查,比如match_all
ES集群的分布式查询
coordinating node可能为其中任一个节点,就像上面match_all查询,不管访问哪个节点,最终都可以拿到三条数据。
集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它节点,确保数据安全,即故障转移。比如有条数据,存于三个节点的主分片分别为P-0、P-1、P-2,副本为R-0、R-1、R-2,此时node1节点宕机:
当然R0+P1+P2还是可以凑出这条数据,但此时数据已经不安全,需要迁移:
实际模拟一下,此时三个节点都正常,数据存在三分节点上:
//停掉es1容器,模拟节点宕机
docker stop es01
查看集群情况:变黄了,不健康了,数据分片0有两个(主副都在),但1、2分片都只有一个了
再等等,开始了数据迁移了:
docker start es01
分片回去了,数据还是均衡的,但es01已不再是主节点。这倒有点想Redis的哨兵模式。
总结: