Elasticsearch 6.x版本全文检索学习之分布式特性介绍

时间:2021-01-18 07:02:22

1、Elasticsearch 6.x版本全文检索学习之分布式特性介绍。

  1)、Elasticsearch支持集群默认,是一个分布式系统,其好处主要有两个。
    a、增大系统容量,如内存、磁盘、使得es集群可以支持PB级别的数据。
    b、提供系统可用性,即使部分节点停止服务,整个集群依然可以正常服务。
  2)、Elasticsearch集群由多个es实例组成。
    a、不同集群通过集群名字来区分,可以通过cluster.name进行修改,默认为elasticsearch。
    b、每个es实例本质上是一个JVM进程,且有自己的名字,通过node.name进行修改。

2、cerebro的安装与运行。Github地址:https://github.com/lmenezes/cerebro。下载,安装,部署。

 [root@slaver4 package]# wget https://github.com/lmenezes/cerebro/releases/download/v0.7.2/cerebro-0.7.2.tgz
---- ::-- https://github.com/lmenezes/cerebro/releases/download/v0.7.2/cerebro-0.7.2.tgz
正在解析主机 github.com (github.com)... 13.250.177.223
正在连接 github.com (github.com)|13.250.177.223|:... 已连接。
已发出 HTTP 请求,正在等待回应... Found
位置:https://github-production-release-asset-2e65be.s3.amazonaws.com/54560347/a5bf160e-d454-11e7-849b-758511101a2f?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20191101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20191101T012023Z&X-Amz-Expires=300&X-Amz-Signature=8b121e4e2a72d997441ebf78e2d8bea9deeeb322d1a3fbc676bc8398099b73a3&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Dcerebro-0.7.2.tgz&response-content-type=application%2Foctet-stream [跟随至新的 URL]
---- ::-- https://github-production-release-asset-2e65be.s3.amazonaws.com/54560347/a5bf160e-d454-11e7-849b-758511101a2f?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20191101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20191101T012023Z&X-Amz-Expires=300&X-Amz-Signature=8b121e4e2a72d997441ebf78e2d8bea9deeeb322d1a3fbc676bc8398099b73a3&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Dcerebro-0.7.2.tgz&response-content-type=application%2Foctet-stream
正在解析主机 github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)... 52.216.130.123
正在连接 github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)|52.216.130.123|:... 已连接。
已发出 HTTP 请求,正在等待回应... OK
长度: (50M) [application/octet-stream]
正在保存至: “cerebro-0.7..tgz” %[======================================================================================================================================================================================>] ,, .34MB/s 用时 30s -- :: (1.65 MB/s) - 已保存 “cerebro-0.7..tgz” [/]) [root@slaver4 package]# ls
cerebro-0.7..tgz elasticsearch-6.7..tar.gz erlang-solutions-1.0-.noarch.rpm filebeat-6.7.-linux-x86_64.tar.gz kibana-6.7.-linux-x86_64.tar.gz logstash-6.7..tar.gz materials rabbitmq-server-3.5.-.noarch.rpm
[root@slaver4 package]# tar -zxvf cerebro-0.7..tgz -C /home/hadoop/soft/

将cerebro赋予新创建的elsearch用户,用户组。

 [root@slaver4 package]# cd ../soft/
[root@slaver4 soft]# ls
cerebro-0.7. elasticsearch-6.7. filebeat-6.7.-linux-x86_64 kibana-6.7.-linux-x86_64 logstash-6.7.
[root@slaver4 soft]# chown elsearch:elsearch cerebro-0.7./
[root@slaver4 soft]# su elsearch
[elsearch@slaver4 soft]$ ls
cerebro-0.7. elasticsearch-6.7. filebeat-6.7.-linux-x86_64 kibana-6.7.-linux-x86_64 logstash-6.7.
[elsearch@slaver4 soft]$ ll
总用量
drwxr-xr-x. elsearch elsearch 11月 cerebro-0.7.
drwxr-xr-x. elsearch elsearch 10月 : elasticsearch-6.7.
drwxr-xr-x. elsearch elsearch 10月 : filebeat-6.7.-linux-x86_64
drwxr-xr-x. elsearch elsearch 10月 : kibana-6.7.-linux-x86_64
drwxr-xr-x. elsearch elsearch 10月 : logstash-6.7.
[elsearch@slaver4 soft]$

安装了jvm即java就可以运行了。我启动报了如下错误,修改一下日志记录的路径。

 [elsearch@slaver4 bin]$ ./cerebro
::, |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
::, |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
::, |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/home/hadoop/soft/cerebro-0.7./conf/logback.xml]
::, |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
::, |-INFO in ch.qos.logback.core.joran.action.ConversionRuleAction - registering conversion word coloredLevel with class [play.api.libs.logback.ColoredLevel]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.FileAppender]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [FILE]
::, |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
::, |-INFO in ch.qos.logback.core.FileAppender[FILE] - File property is set to [./logs/application.log]
::, |-ERROR in ch.qos.logback.core.FileAppender[FILE] - Failed to create parent directories for [/home/hadoop/soft/cerebro-0.7././logs/application.log]
::, |-ERROR in ch.qos.logback.core.FileAppender[FILE] - openFile(./logs/application.log,true) call failed. java.io.FileNotFoundException: ./logs/application.log (没有那个文件或目录)
at java.io.FileNotFoundException: ./logs/application.log (没有那个文件或目录)
at at java.io.FileOutputStream.open0(Native Method)
at at java.io.FileOutputStream.open(FileOutputStream.java:)
at at java.io.FileOutputStream.<init>(FileOutputStream.java:)
at at ch.qos.logback.core.recovery.ResilientFileOutputStream.<init>(ResilientFileOutputStream.java:)
at at ch.qos.logback.core.FileAppender.openFile(FileAppender.java:)
at at ch.qos.logback.core.FileAppender.start(FileAppender.java:)
at at ch.qos.logback.core.joran.action.AppenderAction.end(AppenderAction.java:)
at at ch.qos.logback.core.joran.spi.Interpreter.callEndAction(Interpreter.java:)
at at ch.qos.logback.core.joran.spi.Interpreter.endElement(Interpreter.java:)
at at ch.qos.logback.core.joran.spi.Interpreter.endElement(Interpreter.java:)
at at ch.qos.logback.core.joran.spi.EventPlayer.play(EventPlayer.java:)
at at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:)
at at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:)
at at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:)
at at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:)
at at ch.qos.logback.classic.util.ContextInitializer.configureByResource(ContextInitializer.java:)
at at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:)
at at org.slf4j.impl.StaticLoggerBinder.init(StaticLoggerBinder.java:)
at at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:)
at at play.api.libs.logback.LogbackLoggerConfigurator.configure(LogbackLoggerConfigurator.scala:)
at at play.api.libs.logback.LogbackLoggerConfigurator.configure(LogbackLoggerConfigurator.scala:)
at at play.api.inject.guice.GuiceApplicationBuilder$$anonfun$applicationModule$.apply(GuiceApplicationBuilder.scala:)
at at play.api.inject.guice.GuiceApplicationBuilder$$anonfun$applicationModule$.apply(GuiceApplicationBuilder.scala:)
at at scala.Option.foreach(Option.scala:)
at at play.api.inject.guice.GuiceApplicationBuilder.applicationModule(GuiceApplicationBuilder.scala:)
at at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:)
at at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:)
at at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:)
at at play.core.server.ProdServerStart$.start(ProdServerStart.scala:)
at at play.core.server.ProdServerStart$.main(ProdServerStart.scala:)
at at play.core.server.ProdServerStart.main(ProdServerStart.scala)
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
::, |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [play] to INFO
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [application] to INFO
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebean.config.PropertyMapLoader] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebeaninternal.server.core.XmlConfigLoader] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebeaninternal.server.lib.BackgroundThread] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.gargoylesoftware.htmlunit.javascript] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to ERROR
::, |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [FILE] to Logger[ROOT]
::, |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
::, |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@53aac487 - Registering current configuration as safe fallback point ::, |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
::, |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
::, |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/home/hadoop/soft/cerebro-0.7./conf/logback.xml]
::, |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
::, |-INFO in ch.qos.logback.core.joran.action.ConversionRuleAction - registering conversion word coloredLevel with class [play.api.libs.logback.ColoredLevel]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.FileAppender]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [FILE]
::, |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
::, |-INFO in ch.qos.logback.core.FileAppender[FILE] - File property is set to [./logs/application.log]
::, |-ERROR in ch.qos.logback.core.FileAppender[FILE] - Failed to create parent directories for [/home/hadoop/soft/cerebro-0.7././logs/application.log]
::, |-ERROR in ch.qos.logback.core.FileAppender[FILE] - openFile(./logs/application.log,true) call failed. java.io.FileNotFoundException: ./logs/application.log (没有那个文件或目录)
at java.io.FileNotFoundException: ./logs/application.log (没有那个文件或目录)
at at java.io.FileOutputStream.open0(Native Method)
at at java.io.FileOutputStream.open(FileOutputStream.java:)
at at java.io.FileOutputStream.<init>(FileOutputStream.java:)
at at ch.qos.logback.core.recovery.ResilientFileOutputStream.<init>(ResilientFileOutputStream.java:)
at at ch.qos.logback.core.FileAppender.openFile(FileAppender.java:)
at at ch.qos.logback.core.FileAppender.start(FileAppender.java:)
at at ch.qos.logback.core.joran.action.AppenderAction.end(AppenderAction.java:)
at at ch.qos.logback.core.joran.spi.Interpreter.callEndAction(Interpreter.java:)
at at ch.qos.logback.core.joran.spi.Interpreter.endElement(Interpreter.java:)
at at ch.qos.logback.core.joran.spi.Interpreter.endElement(Interpreter.java:)
at at ch.qos.logback.core.joran.spi.EventPlayer.play(EventPlayer.java:)
at at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:)
at at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:)
at at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:)
at at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:)
at at ch.qos.logback.classic.util.ContextInitializer.configureByResource(ContextInitializer.java:)
at at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:)
at at org.slf4j.impl.StaticLoggerBinder.init(StaticLoggerBinder.java:)
at at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:)
at at play.api.libs.logback.LogbackLoggerConfigurator.configure(LogbackLoggerConfigurator.scala:)
at at play.api.libs.logback.LogbackLoggerConfigurator.configure(LogbackLoggerConfigurator.scala:)
at at play.api.inject.guice.GuiceApplicationBuilder$$anonfun$applicationModule$.apply(GuiceApplicationBuilder.scala:)
at at play.api.inject.guice.GuiceApplicationBuilder$$anonfun$applicationModule$.apply(GuiceApplicationBuilder.scala:)
at at scala.Option.foreach(Option.scala:)
at at play.api.inject.guice.GuiceApplicationBuilder.applicationModule(GuiceApplicationBuilder.scala:)
at at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:)
at at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:)
at at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:)
at at play.core.server.ProdServerStart$.start(ProdServerStart.scala:)
at at play.core.server.ProdServerStart$.main(ProdServerStart.scala:)
at at play.core.server.ProdServerStart.main(ProdServerStart.scala)
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
::, |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [play] to INFO
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [application] to INFO
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebean.config.PropertyMapLoader] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebeaninternal.server.core.XmlConfigLoader] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebeaninternal.server.lib.BackgroundThread] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.gargoylesoftware.htmlunit.javascript] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to ERROR
::, |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [FILE] to Logger[ROOT]
::, |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
::, |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@53aac487 - Registering current configuration as safe fallback point
::, |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
::, |-INFO in ch.qos.logback.core.joran.action.ConversionRuleAction - registering conversion word coloredLevel with class [play.api.libs.logback.ColoredLevel]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.FileAppender]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [FILE]
::, |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
::, |-INFO in ch.qos.logback.core.FileAppender[FILE] - File property is set to [/home/hadoop/soft/cerebro-0.7./logs/application.log]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
::, |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [play] to INFO
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [application] to INFO
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebean.config.PropertyMapLoader] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebeaninternal.server.core.XmlConfigLoader] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.avaje.ebeaninternal.server.lib.BackgroundThread] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.gargoylesoftware.htmlunit.javascript] to OFF
::, |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to ERROR
::, |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
::, |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [FILE] to Logger[ROOT]
::, |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
::, |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@534a5a98 - Registering current configuration as safe fallback point [info] play.api.Play - Application started (Prod)
[info] p.c.s.NettyServer - Listening for HTTP on /::::::::

修改vim logback.xml,这个配置文件,<file>/home/hadoop/soft/cerebro-0.7.2/logs/application.log</file>,配置成自己的日志文件路径即可。

 <configuration>

     <conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel"/>

     <appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/home/hadoop/soft/cerebro-0.7.2/logs/application.log</file>
<encoder>
<pattern>%date - [%level] - from %logger in %thread %n%message%n%xException%n</pattern>
</encoder>
</appender> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%coloredLevel %logger{} - %message%n%xException{}</pattern>
</encoder>
</appender> <logger name="play" level="INFO"/>
<logger name="application" level="INFO"/> <!-- Off these ones as they are annoying, and anyway we manage configuration ourself -->
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF"/>
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF"/>
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF"/>
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF"/> <root level="ERROR">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root> </configuration>

重新启动,如下所示:

 [root@slaver4 bin]$ ./cerebro
[info] play.api.Play - Application started (Prod)
[info] p.c.s.NettyServer - Listening for HTTP on /::::::::

现在启动你的Elasticseach。访问地址http://192.168.110.133:9000,界面如下所示:

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

连上如下所示:

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

3、Elasticsearch快速构建集群。指定集群名称cluster.name、path.data的名称、node.name的名称、http.port端口号。最后的-d参数在后台运行。

 [elsearch@slaver4 bin]$ ./elasticsearch -Ecluster.name=my_cluster -Epath.data=my_cluster_node1 -Enode.name=node1 -Ehttp.port= -d
OpenJDK -Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
[elsearch@slaver4 bin]$

4、Cluster state。

  答:Elasticsearch集群相关的数据称为cluster state,主要记录如下信息。cluster state有版本控制的,创建索引以后,版本更新。
    节点信息,比如节点名称、连接地址等等。
    索引信息,比如索引名称、配置等等。
    五角星代表的是主节点、圆代表的是Coordinating节点、方框代表的是data节点。

5、Master Node。

  答:可以修改cluster state的节点称为master节点,一个集群只能有一个。
    cluster state存储在每个节点上,master维护最新版本并同步给其他节点。
    master节点是通过集群中所有节点选举产生的,可以被选举的节点称为master-eligible节点,相关配置如下所示:node.master:true。
6、Coordinating Node。

  答:处理请求的节点即为coordinating节点,该节点为所有节点的默认角色,不能取消。
    路由请求到正确的节点处理,比如创建索引的请求到master节点。

7、Data Node。

  答:存储数据的节点即为data节点,默认节点都是data类型,相关配置如下。node.data:true。

8、解决单点问题,如果单节点,一个节点挂了,集群停止服务,可以通过新增节点保障集群健壮性,运行如下命令,可以启动一个es节点实例。启动多个节点依次类推。

  ./elasticsearch -Ecluster.name=my_cluster -Epath.data=my_cluster_node2 -Enode.name=node2 -Ehttp.port=5300 -d。

 [root@slaver4 ~]# su elsearch
[elsearch@slaver4 root]$ cd /home/hadoop/soft/
[elsearch@slaver4 soft]$ ls
cerebro-0.7. elasticsearch-6.7. filebeat-6.7.-linux-x86_64 kibana-6.7.-linux-x86_64 logstash-6.7.
[elsearch@slaver4 soft]$ cd elasticsearch-6.7./
[elsearch@slaver4 elasticsearch-6.7.]$ ls
bin config data lib LICENSE.txt logs modules my_cluster_node1 NOTICE.txt plugins README.textile
[elsearch@slaver4 elasticsearch-6.7.]$ cd bin/
[elsearch@slaver4 bin]$ ./elasticsearch -Ecluster.name=my_cluster -Epath.data=my_cluster_node2 -Enode.name=node2 -Ehttp.port= -d
OpenJDK -Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
[elsearch@slaver4 bin]$ ./elasticsearch -Ecluster.name=my_cluster -Epath.data=my_cluster_node1 -Enode.name=node1 -Ehttp.port= -d
OpenJDK -Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
[elsearch@slaver4 bin]$

如果使用的是虚拟机,一定要将此配置修改为这样,不然你是将节点加不到一个集群里面的。

[elsearch@slaver4 config]$ vim elasticsearch.yml

 network.host: 0.0.0.0

效果如下所示:

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

9、提供系统可用性。

  答:服务可用性:2个节点的情况下,允许其中1个节点停止服务。
    数据可用性。a、引入副本(Replication)解决。b、每个节点上都有完备的数据。

10、elasticsearch的副本和分片。

  如何将数据分布到所有节点上,引入分片(Shard)解决问题。

  分片是ES支持PB级数据的基石,特点:a、分片存储了部分数据,可以分布于任意节点上。b、分片数在索引创建时指定且后续不允许再更改,默认为5个。c、分片有主分片和副本分片之分,以实现数据的高可用。d、副本分片的数据由主分片同步,可以有多个,从而提高读取的吞吐量。

创建索引的两种方式,第一种,直接使用api进行创建即可,如下所示:

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

在集群中test_index索引,创建3个分片和1个副本。Primary Shard主分片、Replication Shard副本分片。

# 在集群中test_index索引,创建3个分片和1个副本。Primary Shard主分片、Replication Shard副本分片。
PUT test_index
{
"settings": {
"number_of_shards": ,
"number_of_replicas":
}
}

方式二,直接使用页面创建即可,如下所示:

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

实线表示主分片,虚线表示副分片,主分片和副本分片一一对应。效果如下所示:

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

11、如果集群是三个节点,此时增加节点是否能提高test_index的数据容量?

  答:不能,因为只有3个分片,已经分布在3台节点上,新增的节点无法利用。

12、如果集群是三个节点,此时增加副本数是否能提高test_index的读取吞吐量?。

  答:不能,因为新增的副本是分布在3个节点上,还是利用了同样的资源,如果要增加吞吐量,还需要增加节点。

13、分片数的设定非常重要,需要提前规划好。

  分片数太少,导致后续无法通过增加节点实现水平扩容。
  分片数过大,导致一个节点上分布多个分片,造成资源浪费,同时会影响查询性能。

14、集群状态Cluster Health。三种状态只是代表分片的工作状态,并不是代表整个es集群是否能够对外提供服务。Rest api获取状态:GET _cluster/health。

  通过如下api可以查看集群健康状况,包括以下三种:
    a、green 健康状态,指所有主副分片都正常分配。
    b、yellow 指所有主分片都正常分配,但是有副本分片未正常分配。
    c、red 有主分片未分配。但是可以访问该集群的。
Elasticsearch 6.x版本全文检索学习之分布式特性介绍

Rest api获取状态:GET _cluster/health。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

15、elasticsearch故障转移。图文参考:https://blog.csdn.net/weixin_40792878/article/details/86096009#2_84

备注:红色截图来源于慕课网,尊重版权,从你我做起,谢谢。

  假设集群由3个节点组成,此时集群状态是green。初始状态,node1节点(P0、R1分片)、node2节点(P1、R2分片)、node3节点(P2、R0分片)。
  如果node1(node1节点是主节点)所在机器宕机导致服务终止,此时集群会如何处理?
    第一步、node2和node3发现node1无法响应一段时间后会发起master选举,比如这里选举node2为master节点,此时由于主分片P0下线,集群状态变为red。
    第二步、node2发现主分片P0未分配,将R0提升为主分片。此时由于所有主分片都正常分配,集群状态变为yellow。node2节点(P1、R2分片)、node3节点(P2、P0分片)。
    第三步、node2发现主分片P0和P1生成新的副本,集群状态变为green。node2节点(P1、R2、R0分片)、node3节点(P2、P0、R1分片)。

16、elasticsearch文档分布式存储。

  文档最终会存储在分片上,elasticsearch使用文档存储算法。假设doc1存储到分片P1,doc1是如何存储到分片P1的呢,需要文档到分片的映射算法,目的使得文档均匀分布在所有分片上, 以充分利用资源。elasticsearch的分布式文档存储方案使用的是hash算法。

elasticsearch通过如下公式计算文档对应的分片。
shard=hash(routing)%number_of_primary_shards。
解释如下所示:
hash算法保证可以将数据均匀的分散在分片中。
routing是一个关键参数,默认是文档id,也可以自行指定。
number_of_primary_shards是主分片数。该算法与主分片数相关,这也是分片数一旦确定后便不能更改的根本原因。

17、elasticsearch文档创建流程。

  第一步、Client客户端向node3发起创建文档的请求。
  第二步、node3通过routing计算该文档应该存储在Shard1上,查询cluste state后确认主分片P1在node2上,然后转发创建文档的请求到node2。
  第三步、P1接受并执行创建文档的请求后,将同样的请求发送到副本分片R1。
  第四步、R1接收并执行创建文档请求后,通知P1成功的结果。
  第五步、P1接收副本分片结果后,通过node3创建成功。
  第六步、node3返回结果到client。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

18、elasticsearch文档读取流程。
  第一步、Client向node3发起创建文档的请求。
  第二步、node3通过routing计算该文档应该存储在Shard1上,查询cluste state后获取Shard1的主副分片列表,然后以轮询的机制获取一个shard,比如这里是R1,然后转发读取文档的请求到node1。
  第三步、R1接收并执行创建文档的请求后,将结果返回给node3。
  第四步、node3返回结果给Client。
Elasticsearch 6.x版本全文检索学习之分布式特性介绍

19、elasticsearch文档批量创建的流程。
  第一步、Client向node3发起批量创建文档的请求(bulk)。
  第二步、node3通过routing计算所有文档对应的shard,然后按照主shard分配对应执行的操作,同时发送请求到涉及的主shard,比如这里3个主shard都需要参与。
  第三步、主shard接受并执行请求后,将通过的请求同步到对应的副本shard。
  第四步、副本shard执行结果后返回结果到主shard,主shard再返回node3。
  第五步、node3整合结果后返回Client。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

20、elasticsearch文档批量读取的流程。
  第一步、Client向node3发起批量获取文档的请求(mget)。
  第二步、node3通过routing计算所有文档对应的shard,然后以轮询的机制获取要参与的shard,按照shard构建mget请求,同时发送请求到涉及的shard,比如这里有2个shard需要参与。
  第三步、R1、R2返回文档结果。
  第四步、node3返回结果给Client。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

21、elasticsearch的脑裂问题。脑裂问题,英文为split-brain,是分布式系统中的经典网络问题。

如果node1和node2、node3网络隔离了。这个时候会发生如下所示的情况。
  node2与node3会重新选举master,比如node2成为了新master,此时会更新cluster state,然后node1自己组成集群后,也会更新cluster state。同一个集群有两个master,而维护不同的cluster state,网络恢复后无法选择正确的master。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

如何解决脑裂问题,解决方案为仅在可选举master-eligible节点数大于等于quorum时候才可以进行master选举。

quorum = master-eligible 节点数/2 + 1,例如 3个master-eligible节点时,quorum为2。

解决:设置config/elasticsearch.yml参数配置 discovery.zen.mininum_master_nodes为quorum的值即可避免脑裂。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

22、倒排索引生成不能更改。倒排索引一旦生成,不能更改。

好处,如下所示:
  a、不用考虑并发写文件的问题,杜绝了锁机制带来的性能问题。
  b、由于文件不再更改,可以充分利用文件系统缓存,只允许载入一次,只要内存足够。
  c、对该文件的读取都会从内存读取,性能高。
  d、利于生成缓存数据。
  e、利于对文件进行压缩存储,节省磁盘和内存存储空间。

坏处,如下所示:
  a、写入新文档时,必须重新构建倒排索引文件,然后替换老文件后,新文档才能被检索,导致文档实时性受到影响。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

文档搜索实时性,解决新文档查询慢的问题,解决方案是新文档直接生成新的倒排索引文件,查询的时候同时查询所有的倒排文件,然后做结果的汇总计算即可。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

23、Lucene 中的segment、Elasticsearch中的Index的概念理解。

  a、Lucene采用了这种方案,它构建的单个倒排索引称为segment,合在一起称为Index(Lucene中的名称,是segment的集合),与Elasticsearch中的Index(逻辑上document文档集合)概念不同,Elasticsearch中的一个Shard对应一个Lucene Index。
  b、Lucene会有一个专门的文件来记录所有的segment信息,称为 Commit Point。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

24、文档搜索实时性概念refresh。利用缓存来提升查询实时性。

  a、segment写入磁盘的过程依然很耗时,可以借助文件系统缓存的特性,先将segment在缓存(即内存)中创建并开放查询来进一步提升实时性,该过程在es中被称为refresh。

  b、在refresh之前文档会先存储在一个buffer中,refresh时将buffer中的所有文档清空并生成segment。

  c、Elasticsearch默认每1秒执行一次refresh,因此文档的实时性被提高到1秒,这也是es被称为近实时(Near Real Time)的原因。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

refresh将缓存中的文件清空并在磁盘上面生成segment。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

25、文档搜索实时性概念translog。处理缓存易丢失的情况。

如果在内存中的segment还没有写入磁盘前发生了宕机,那么其中的文档就无法恢复了,如何解决这个问题呢?
  a、Elasticsearch引入了translog机制,写入文档到buffer的时候,同时将该操作写入translog。
  b、translog文件会即时写入磁盘(fsync),6.x默认每个请求都会落盘,可以修改为每5秒写一次,这样风险便是丢失5秒内的数据,相关配置为index.translog.*。
  c、Elasticsearch启动的时候会检查translog文件,并从中恢复数据。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

26、文档搜索实时性概念flush。持久化缓存中的segment。 

flush负责将内存中的segment写入磁盘,主要做如下的工作。
  a、将translog写入磁盘。
  b、将index buffer清空,其中的文档生成一个新的segment,相当于一个refresh操作。
  c、更新commit point并写入磁盘。
  d、执行fsync操作,将内存中的segment写入磁盘。
  e、删除旧的translog文件。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

27、文档搜索实时性概念refresh。

refresh发生的时机主要有如下几种情况。
  a、间隔时间达到的时候,通过index.settings.refresh_interval来设定,默认是1秒。
  b、index.buffer占满时,其大小通过indices.memory.index_buffer_size设置,默认为jvm heap的10%,所有shard共享。
  c、flush发生的时候也会发生refresh。

28、文档搜索实时性概念flush。

flush发生的时机主要有以下几种情况:
  a、间隔时间达到时,默认是30分钟,5.x之前可以通index.translog.flush_threshold_period修改;之后发布的版本无法设置。
  b、translog占满时,其大小可以通过index.translog.flush_threshold_size控制,默认是512MB;每个index有自己的translog。

29、文档搜索实时性,删除与更新文档。

1)、segment一旦生成就不能更改,那么如果你要删除文档该如何操作呢?
  a、Lucene专门维护一个.del的文件,记录所有已经删除的文档,注意,.del上记录的是文档在Lucene内部的id。

  b、在查询结果返回前会过滤掉.del中的所有文档。
2)、更新文档如何进行呢?
  a、首先删除文档,然后再创建新文档。

Elasticsearch 6.x版本全文检索学习之分布式特性介绍

30、Elasticsearch中的Segment Merge。

a、随着segment的增多,由于一次查询的segment数增多,查询速度会变慢。
b、es会定时在后台进行segment merge的操作,减少segment的 数量。
c、通过force_merge api可以手动强制做segment merge的操作。

aaarticlea/jpeg;base64,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" alt="" />

作者:别先生

博客园:https://www.cnblogs.com/biehongli/

如果您想及时得到个人撰写文章以及著作的消息推送,可以扫描上方二维码,关注个人公众号哦。