目录
一、概述
1.1、介绍及特性
1.2、ES和solr的对比
二、Elasticsearch 架构与原理(重点)
2.1、ElasticSearch中的核心名词概念(重点)索引、类型、文档、映射、分片、副本是什么?
索引(index)
类型(type)——7已经废弃
文档(document)
映射(mapping)
分片(shards)
副本(repica)
三、Elasticsearch结合Kinaba安装
3.1、elasticsearch、kibana安装包下载
3.2、elasticsearch安装
3.3、elasticsearch-head可视化工具安装
3.4、安装kibana
3.5、安装IK分词器
3.6、自定义扩展热词
四、语法使用(重点)
4.1、ElasticSearch 常用字段类型
4.2、Restful Api风格操作文档语法
4.2.1、使用kibana操作文档
4.2.2、高级操作
五、SpringBoot操作Elasticsearch的Api接口(重点)
六、疑问(重点)
6.1、什么是全文索引
6.2、什么是倒排索引?怎么实现的?有什么作用?
6.3、Elasticsearch走那个节点的路由规则是怎样的?
6.4、ES写入数据的工作过程?
6.5、如何提高elasticsearch的查询性能?为什么?
6.6、Node主从节点数据是怎么同步的?
6.7、Elasticsearch集群是如何选举主节点的?
6.8、怎么查看ES的索引大小?
七、安装常见问题
7.1、Linxu安装elasticsearch启动时“elasticsearch max virtual memory areas vm.max_map_count [65530] is too low......报错”
7.2、inux安装elasticsearch一直启动失败:max file descriptors [4096] for elasticsearch process is too low, incr...
7.3、添加用户命令:
7.4、目录赋予指定用户权限:
小故事:
多年前,一个叫做Shay Banon的程序员失业后,跟随其媳妇去伦敦学习厨师。在他找工作的过程中为妻子写了一个食谱的搜索引擎,他开始使用早期版本的Lucene。后来他认为基于Lucene开发比较困难,所以开始抽象Lucene代码以便Java程序员可以在应用中添加搜索功能。他发布了第一个开源项目,叫做”Compass”;后来他又重新写了Compass使其成为一个高性能、实施的、分布式搜索引擎, 并且可以独立部署的服务,叫做Elasticsearch。
受欢迎程度:
Elasticsearch(ES)是一个基于 Lucene 构建的开源 分布式搜索分析引擎,可以近实时的索引、检索数据。具备高可靠、易使用、社区活跃等特点,在全文检索、日志分析、监控分析等场景具有广泛应用。
由于高可扩展性,集群可扩展至百节点规模,处理PB级数据。通过简单的 RESTful API 即可实现写入、查询、集群管理等操作。
除了检索,还提供丰富的统计分析功能。以及官方功能扩展包 XPack 满足其他需求,如数据加密、告警、机器学习等。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr。
中文文档地址:Elasticsearch: 权威指南 | Elastic。
首先 Lucene 是一款高性能的信息检索库,提供索引和检索基本功能。ES和Solr都是 在此基础上解决可靠性、分布式集群管理等问题最终形成产品化的全文检索系统。
Elasticsearch和Solr比较:
基本概念 :
Elasticsearch是面向文档,json格式存储:ElasticSearch类比传统数据库
Relational DB |
Elasticsearch |
数据库(Databases) |
索引(Indices) |
表(Tables) |
类型(Types)——7版本已经弃用 |
行(Rows) |
文档(Documents) |
字段(Columns) |
域 (Fields) |
Elasticsearch(集群)中可以包含多个索引(数据库),每个索引中可以包含多个类型(表),每个类型中又包含多个文档(行),每个文档中又包含多域(列)。
一个索引就是一个文档的集合。每个索引的名字都是唯一的,通过索引名字可以来操作索引。一个集群中可以有任意多个索引。
类型是索上的逻辑分类或分区。在ES6之前,一个索引可以存放多个类型,比如一个索引存放用户数据,也可存放博客数据;但从ES7开始,一个索引中只能有一个类型。新版本类型已经被废弃。
一个可以被索引的数据单元。例如一个用户的文档、一个产品的文档等。文档以json格式存储或展现。一个文档里面有多个field,每个field就是一个数据字段。
mapping是用来定义个文档(document),以及它所包含的属性(field)是如何存储和索引的。
单台机器无法存储大量数据,es可以将一个索引中的数据切分为多个分片,分布在多台服务器上存储。有了分片就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上执行,提升吞度量和性能。每个分片都是一个lunene index。创建索引时可指定分片数量。
任何一个服务器随时可能故障或宕机。副本可以在分片故障时提供备用服务,保证数据不丢失,多个副本还可以提升搜索操作的吞度量和性能。新增副本数,分片重分配。
声明:JDK >=1.8。
安装包地址:Download Elasticsearch | Elastic
解压安装包后目录启动:
下载kinaba地址:Download Kibana Free | Get Started Now | Elastic
解压安装包后目录启动:
链接地址:Past Releases of Elastic Stack Software | Elastic
# tar -zxvf elasticsearch-7.2.0-linux-x86_64.tar.gz
# chown -R elastic:elastic /opt
# su elastic
# cd elasticsearch-7.2.0
# ls
# mkdir data logs
# vim elasticsearch.yml
# ======================== Elasticsearch Configuration ========================= # # NOTE: Elasticsearch comes with reasonable defaults for most settings. # Before you set out to tweak and tune the configuration, make sure you # understand what are you trying to accomplish and the consequences. # # The primary way of configuring a node is via this file. This template lists # the most important settings you may want to configure for a production cluster. # # Please consult the documentation for further information on configuration options: # https://www.elastic.co/guide/en/elasticsearch/reference/index.html # # ---------------------------------- Cluster ----------------------------------- # # Use a descriptive name for your cluster: # 集群名称 cluster.name: my-application # # ------------------------------------ Node ------------------------------------ # # Use a descriptive name for the node: # #node.name: node-1 # # Add custom attributes to the node: #自定义节点名称(集群时,节点名称不能一样) node.name: node-1 # # Add custom attributes to the node: # #node.attr.rack: r1 # # ----------------------------------- Paths ------------------------------------ # # Path to directory where to store the data (separate multiple locations by comma): # 设置数据目录 path.data: /home/elastic/data # # Path to log files: # 设置日志目录 path.logs: /home/elastic/logs # # ----------------------------------- Memory ----------------------------------- # # Lock the memory on startup: # #bootstrap.memory_lock: true # # Make sure that the heap size is set to about half the memory available # on the system and that the owner of the process is allowed to use this # limit. # # Elasticsearch performs poorly when the system is swapping the memory. # # ---------------------------------- Network ----------------------------------- # # Set the bind address to a specific IP (IPv4 or IPv6): # 设置绑定主机ip(4个0表示主机,且任何机器都可以访问本机的ip) network.host: 0.0.0.0 # # Set a custom port for HTTP: # http访问端口 http.port: 9200 # # For more information, consult the network module documentation. # # --------------------------------- Discovery ---------------------------------- # # Pass an initial list of hosts to perform discovery when this node is started: # The default list of hosts is ["127.0.0.1", "[::1]"] # discovery.seed_hosts: ["192.168.48.129", "192.168.48.130","192.168.48.131"] # # Bootstrap the cluster using an initial set of master-eligible nodes: # cluster.initial_master_nodes: ["node-1"] # # For more information, consult the discovery and cluster formation module documentation. # # ---------------------------------- Gateway ----------------------------------- # # Block initial recovery after a full cluster restart until N nodes are started: # #gateway.recover_after_nodes: 3 # # For more information, consult the gateway module documentation. # # ---------------------------------- Various ----------------------------------- # # Require explicit names when deleting indices: # #action.destructive_requires_name: true |
# cd /opt/elasticsearch-7.2.0/bin
# ./elasticsearch
验证集群高可用:停掉机器(192.168.48.129)的elasticsearch服务,再看主节点(已经变成了130机器):
备注:elasticsearch5之后可以直接安装chrome插件使用,无需独立部署。
浏览器打开一个新的窗口时,选择扩展程序的对应elasticsearch head插件启动使用。
# tar -zxvf kibana-7.2.0-linux-x86_64.tar.gz
# cd /opt/kibana-7.2.0-linux-x86_64/config
# vim kibana.yml
备注:server.name指定的时部署的机器,easticsearch.hosts是链接的elasticsearch服务的http访问地址,数组形,如果集群则配置多个。
浏览器访问kibana, 默认访问端口5601:
http://192.168.48.129:5601/
点击左边菜单栏”dev_tools”进入es索引操作界面:
安装包下载地址:Releases · medcl/elasticsearch-analysis-ik · GitHub
注意:IK的版本一定要与elasticsearch的版本一致,否则elasticsearch无法启动。
#mkdir ik
# unzip elasticsearch-analysis-ik-7.2.0.zip
找到elasticsearch的ik目录,在该目录下新建一个自定义的目录扩展热词的目录,并新建一个文件,以”.dic”结尾(如下目录为custom, 文件名为new_word.dic, 输入自定义热词”斗罗大陆”):
配置自定义热词文件的加载(编辑文件ik/config/IKAnalyzer.cfg.xml, 在key=”ext_dict”的地方配置自定义热词文件的加载的路径, 该文件默认地址在ik目录下寻找):
重启elasticsearch,可以看到加载了自定义热词文件:
测试效果:
不支持聚合。
#插入|更新此字段的值时,有3种表示方式
"2020-04-18"、"2020/04/18 09:00:00"
1610350870
1641886870000 |
比如招聘要求年龄在[20, 40]上,mapping: age:{ "type" : "integer_range" } 插入|更新文档|字段时,值写成json对象的形式: "age" : { "gte" : 20, "lte" : 40 } gt是大于,lt是小于,e是equals等于。 |
method |
描述 |
操作文档用法 |
PUT |
创建文档(指定文档id) |
Ip:端口/索引名/文档id |
POST |
更新文档 |
Ip:端口/索引名/文档id/_update |
DELETE |
删除文档 |
IP:端口/索引名/文档id |
GET |
查询文档 |
Ip:端口/索引名/_search |
PUT 索引名 |
DELETE 索引名 |
PUT 索引名/_mapping { "properties": { "字段名1" : { "type" : "字段类型" }, "字段名2" : { "type" : "字段类型" }, ... } } |
PUT 索引名/_doc/文档id { "字段名":字段值, .. } |
POST 索引名/_update/文档id { "doc":{ "字段名":字段值, ... } } |
备注:如果使用put更新,没传值的字段则会被覆盖置为空值,推荐使用post更新。
GET 索引名/_search |
GET _cat/indices |
GET 索引名 |
备注:只看索引结构,可以使用“GET 索引名/_mapping?pretty”。
GET 索引名/_doc/文档id |
GET 索引名/_search { "query":{ "match":{ "字段名":字段值 } } } 或 GET 索引名/_search { "query": { "match":{ "字段名":"条件1 条件2" } } } |
备注:query 表示查询;match 要匹配的条件信息,支持模糊查询左右或中间模糊)。一个字段如果匹配多条件,则空格隔开条件值(支持数组模糊查询)。
GET 索引名/_search { "query": { "match":{ "字段名":字段值} }, "_source":["展示的字段名1","展示的字段名2","展示的字段名3"] } |
备注:_source的值可以时单个字符串,也可以是字符串数组。
POST _bulk {"index":{"_index":"索引名","_id":文档id }} {"字段名1":字段值,"字段名2":"字段值"} {"index":{"_index":"索引名","_id":文档id }} {"字段名1":字段值,"字段名2":"字段值"} |
备注:id不存在则写入,已存在则更新。
POST 索引名/_update_by_query { "query": { "match": { "字段名":字段值 } }, "script": { "source":"ctx._source['字段名']=字段值;" } } |
POST 索引名/_update_by_query { "script": { "lang": "painless", "inline": "if(ctx._source.字段名== 条件值){ctx._source.字段名= 新值}" } } |
备注:inline表示脚本写在查询语句内,“lang”:“painless”表示脚本语言为painless(es5推出了简单安全且高效的painless脚本替代原有的一些脚本语言)。
GET 索引名/_search { "from": 2, "size": 2 } |
备注:“from”——起始值,下标0开始;“size”——页大小
GET 索引名/_search { "sort":{ "字段名":{"order":"desc"} } } |
备注:order的值:desc倒序,asc正序。”text”类型默认是不支持排序的,如果要支持排序则要设置Fielddata值为true。 但Fielddata是没有限制的,并且它的结果会被缓存在堆中,并且不会被GC掉。
GET 索引名/_search { "query": { "bool": { "must": [ {"match": {"字段名1":字段值} }, {"match":{"字段名2":字段值} } ] } } } |
备注:must是并且逻辑, 是个数组类型,里面可以跟多个条件,多个条件都满足才匹配; must_not是相反逻辑,不满足条件里的才匹配。
GET 索引名/_search { "query": { "bool": { "should": [ {"match": {"字段名1":字段值} }, {"match":{"字段名2":字段值} } ] } } } |
备注:shoud是或逻辑, 是个数组类型,里面只要其中一个条件符合就会匹配。
GET 索引名/_search { "query": { "bool": { "filter": { "range": { "字段名": { "gte": 条件1, "lte": 条件2 } } } } } } |
备注:range里可以添加多个条件;gte(大于等于),lte(小于等于),gt(大于),lt(小于)。
GET 索引/_search { "query":{ "term":{ "字段名":字段值 } } } 或 GET user/_search { "query":{ "bool":{ "should": [ {"term":{"字段名1":字段值} }, {"term":{"字段名2":字段值} } ] } } } |
备注:term是精确查询,使用倒排索引精确查询。
GET 索引名/_search { "query":{ "bool":{ "must":[ { "range": { "字段名": { "gte": 21, "lte":22 }}} ] } } } |
备注:gte(大于等于),lte(小于等于),gt(大于),lt(小于)
GET 索引名/_search { "query": { "match": { "字段名": 字段值 } }, "highlight": { "fields": { "字段名": {} } } } 或自定义hmtl标签 GET 索引名/_search { "query": { "match": { "字段名": 字段值 } }, "highlight": { "pre_tags": "", "post_tags": "", "fields": { "字段名": {} } } } |
备注:匹配到的值会以html的em标签包装返回。使用“pre_tags”和“post_tags”可以自定义高亮标签。
这里在user索引下创建了8个文档。
#新建索引 PUT user #新建索引规则 PUT user/_mapping { "properties":{ "name":{"type":"keyword"}, "age":{"type":"long"}, "address":{"type":"text","fielddata":true}, "birthday":{"type":"date"}, "sort":{"type":"long"}, "level":{"type":"long"}, "tags":{"type":"text"} } } #添加数据 PUT user/_doc/1 { "name":"唐三", "age":23, "address":"斯莱克学院", "birthday":"1999-01-01", "sort":"1", "level": "102", "tags":["控制系魂师","强攻系魂师","敏功系魂师","蓝银草","昊天锤"] } PUT user/_doc/2 { "name":"小舞", "age":22, "address":"斯莱克学院", "birthday":"2000-01-01", "create_time":1657261332, "sort":"7", "level": "100", "tags":["敏功系魂师","柔骨兔"] } PUT user/_doc/3 { "name":"戴沐白", "age":25, "address":"斯莱克学院", "birthday":"2007-01-01", "create_time":1657261359, "sort":"2", "level": "100", "tags":["强攻系魂师", "白虎"] } PUT user/_doc/4 { "name":"朱竹青", "age":21, "address":"斯莱克学院", "birthday":"2002-01-01", "create_time":1657261371, "sort":"4", "level": "100", "tags":["敏攻系魂师", "幽冥灵猫"] } PUT user/_doc/5 { "name":"宁荣荣", "age":21, "address":"斯莱克学院", "birthday":"2001-01-01", "create_time":1657261382, "sort":"6", "level": "100", "tags":["辅助系魂师", "九宝琉璃塔"] } PUT user/_doc/6 { "name":"奥斯卡", "age":24, "address":"斯莱克学院", "birthday":"1998-01-01", "create_time":1657261382, "sort":"5", "level": "100", "tags":["食物系魂师","香肠"] } PUT user/_doc/7 { "name":"马红俊", "age":22, "address":"河南", "birthday":"2000-01-01", "create_time":1657261382, "sort":"3", "level": "100", "tags":["敏攻系魂师", "火凤凰"] } PUT user/_doc/10 { "name":"唐昊", "age":45, "address":"昊天宗", "birthday":"1977-01-01", "create_time":1657261382, "sort":"10", "level": "97", "tags":["强攻系魂师","昊天锤"] } |
PUT 索引名 { “settings”:{ “number_of_shards”:5, “number_of_replicas”:1 } } |
GET / |
官方javadoc文档地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.2/java-rest-high.html
Maven配置:
|
elasticsearch-rest-high-level-client内部依赖两个核心jar,如下:
Java配置类准备:
@Configuration public class ElasticSearchClientConfig { @Bean public RestHighLevelClient restHighLevelClient(){ return new RestHighLevelClient( RestClient.builder( new HttpHost("192.168.48.129", 9200, "http"), new HttpHost("192.168.48.130", 9200, "http"), new HttpHost("192.168.48.131", 9200, "http"))); } } |
@SpringBootTest(classes = SpringbootEsApplication.class) class SpringbootEsApplicationTests { @Autowired private RestHighLevelClient restHighLevelClient; private static final String STUDY_INDEX_NAME = "study_index"; private static final String USER_INDEX_NAME = "user"; /** * 功能描述:创建索引 */ @Test public void createIndexTest() throws IOException { //1、创建索引请求 CreateIndexRequest createIndexRequest = new CreateIndexRequest(STUDY_INDEX_NAME); //2、客户端执行请求 IndicesClient,请求后获得响应 CreateIndexResponse response = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT); System.out.println(response); } /** * 功能描述:判断索引是否存在 */ @Test public void isExistIndexTest() throws IOException { GetIndexRequest getIndexRequest = new GetIndexRequest(STUDY_INDEX_NAME); boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT); } /** * 功能描述:删除索引 */ @Test public void deleteIndexTest() throws IOException { DeleteIndexRequest getIndexRequest = new DeleteIndexRequest(STUDY_INDEX_NAME); AcknowledgedResponse response = restHighLevelClient.indices().delete(getIndexRequest, RequestOptions.DEFAULT); System.out.println(response); } /** * 功能描述:创建文档 */ @Test public void createDocTest() throws IOException, ParseException { //创建对象 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date birthday = simpleDateFormat.parse("1978-01-01"); User user = User.builder() .name("比比东") .age(44) .address("武魂殿") .birthday(birthday) .sort(9) .level(99) .tags(new String[]{"强攻系魂师","死亡蛛皇","噬魂蛛皇"}) .createTime(new Date()) .build(); //创建请求 IndexRequest request = new IndexRequest(USER_INDEX_NAME); //设置请求规则 request.id("9"); request.timeout("1s"); //将对象转换成json字符串放入请求 String value = JSON.toJSONString(user); request.source(value, XContentType.JSON); //客户端发送请求 IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT); System.out.println(response + ">>" + response.status()); } /** * 功能描述:判断文档是否存在 */ @Test public void isExistDocTest() throws IOException { GetRequest getRequest = new GetRequest(USER_INDEX_NAME, "9"); //不获取返回的_source的上下文了 // getRequest.fetchSourceContext(new FetchSourceContext(false)); // getRequest.storedFields("_none"); boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT); System.out.println(exists); } /** * 功能描述:获取文档 */ @Test public void getDocTest() throws IOException { GetRequest getRequest = new GetRequest(USER_INDEX_NAME, "9"); GetResponse response = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); //打印文档数据内容 System.out.println(response.getSourceAsString()); //打印文档全部内容 System.out.println(response); } /** * 功能描述:更新文档 */ @Test public void updateDocTest() throws IOException { UpdateRequest updateRequest = new UpdateRequest(USER_INDEX_NAME, "9"); // updateRequest.timeout("1s"); User user = new User(); user.setAddress("武魂帝国"); updateRequest.doc(JSON.toJSONString(user), XContentType.JSON); UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); System.out.println(response + ">>" + response.status()); } /** * 功能描述:删除文档 */ @Test public void deleteDocTest() throws IOException { DeleteRequest deleteRequest = new DeleteRequest(USER_INDEX_NAME, "9"); // deleteRequest.timeout("1s"); DeleteResponse response = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT); System.out.println(response + ">>" + response.status()); } /** * 功能描述:批量插入文档 */ @Test public void bulkDocTest() throws IOException, ParseException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date tangchengBirthday = simpleDateFormat.parse("1958-01-01"); Date ayingBirthday = simpleDateFormat.parse("1978-01-01"); BulkRequest bulkRequest = new BulkRequest(); bulkRequest.timeout("1s"); ArrayList User tangchengUser = User.builder() .name("唐晨") .age(66) .address("昊天宗") .birthday(tangchengBirthday) .sort(8) .level(99) .tags(new String[]{"强攻系魂师","昊天锤"}) .createTime(new Date()) .build(); User ayingUser = User.builder() .name("阿银") .age(44) .address("斗罗森林") .birthday(ayingBirthday) .sort(11) .level(75) .tags(new String[]{"控制系魂师","蓝银草"}) .createTime(new Date()) .build(); arrayList.add(tangchengUser); arrayList.add(ayingUser); arrayList.stream().forEach(user ->{ IndexRequest source = new IndexRequest(USER_INDEX_NAME) .id(user.getSort() + "") .source(JSON.toJSONString(user), XContentType.JSON); bulkRequest.add(source); }); BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); System.out.println(response.hasFailures() + ">>" + response.status()); } /** * 功能描述:查询文档 */ @Test public void searchDocTest() throws IOException { SearchRequest searchRequest = new SearchRequest(USER_INDEX_NAME); //构建查询条件 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // TermQueryBuilder queryBuilder = QueryBuilders.termQuery("address", "斯莱克学院"); QueryBuilder queryBuilder = QueryBuilders.matchQuery("address", "斯莱克学院"); sourceBuilder.query(queryBuilder); sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); searchRequest.source(sourceBuilder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(searchResponse.getHits())); System.out.println("-------------------------"); for (SearchHit fields : searchResponse.getHits().getHits()) { System.out.println(fields.getSourceAsMap()); } } } |
答:通过一个程序扫描文本中的每一个单词,针对单词建立索引,并保存该单词在文本中的位置、以及出现的次数。用户搜索时,通过之前建立好的索引来查询,将索引中单词对应的文本位置、出现的次数返回给用户。
答:请看ES的倒排索引介绍。
答:有个公式:shard = hash(routing) % number_of_primary_shards.
答:
答:
一个好的分片策略,首先要对业务和增长有一个预先的预判:首先控制每个分片的占用硬盘空间,不能超过es最大jvm的堆空间设定,一般是不超过32G。第二考虑一下node节点的数量,一般设定分片数不超过节点数的3倍,假如节点数是3,那么分片数最多不能超过9,是节点数的倍数。
副本数的个数,一方面考虑高可用让容灾,另一方面副本数可以根据请求流量的qps等参数,适当的提高副本数,来提高读性能。
答:ES内部集成了文件复制的算法,通过PacificA是微软亚洲研究院提出的一种用于日志复制系统的分布式一致性算法。es的master监控集群和健康状态,分发索引分片到集群节点。
扩展:
当一个Replica故障时,ES会将其移除,当故障超过一定时间,ES会分配一个新的Replica到新的Node上,此时需要全量同步数据。但是如果之前故障的Replica回来了,就可以只回补故障之后的数据,追平后加回来即可,实现快速故障恢复。实现快速故障恢复的条件有两个,一个是能够保存故障期间所有的操作以及其顺序,另一个是能够知道从哪个点开始同步数据。
答:Elasticsearch的选主是Zen Discovery(集群发现机制)模块负责的, Zen Discovery封装了节点发送(ping)。
扩展:
发现新节点:ES内置自动发现实现 Zen discovery,当一个节点启动后,通过联系集群成员列表即可加入集群。集群中由其中一个节点担任主节点,用于集群元数据管理,维护分片在节点间的分配关系。当新节点加入集群后,Master 节点会自动迁移部分分片至新节点,均衡集群负载。
移除故障节点:分布式集群难免有节点故障。主节点会定期探测集群其他节点存活状态,当节点故障后,会将节点移出集群,并自动在其他节点上恢复故障节点上的分片。
答:在kibana上可以通过“GET _cat/indices?v”查看。
问题因素:虚拟机内存太小。
解决办法:
问题因素:原因是进程不够用了
解决方法:
(1)切换到root用户,修改文件/etc/security/limits.conf
//在文件末尾添加下面的参数值,注意前面带*号 * soft nofile 65536 * hard nofile 131072 * soft nproc 4096 * hard nproc 4096 |
切换到root: useradd 用户名
切换到root: chown -R elasticsearch:elasticsearch /opt