环境准备

jdk版本

[root@iz2zefc352jeey9szh60wlz ~]# java -version
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)

Linux操作系统

[root@iz2zefc352jeey9szh60wlz ~]# cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)

ElasticSearch版本

elasticsearch-7.6.2-linux-x86_64.tar.gz

服务器(三台)

115.29.193.155
121.5.111.192
182.92.6.145

安装及测试(先三台各自独立启动测试)

下载

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.6.2-linux-x86_64.tar.gz

解压

tar -zxvf elasticsearch-7.6.2-linux-x86_64.tar.gz
mv elasticsearch-7.6.2 /usr/local

修改配置文件

cd /usr/local/elasticsearch-7.6.2/
vim config/elasticsearch.yml

具体修改项(对于单台独立启动,下面的配置暂且够用):

cluster.name: my-application #集群名称
node.name: node-1 #当前节点名称
#数据和日志的存储目录
path.data: /usr/local/elasticsearch-7.6.2/data
path.logs: /usr/local/elasticsearch-7.6.2/logs
#设置绑定的ip,设置为0.0.0.0以后就可以让任何计算机节点访问到了
network.host: 0.0.0.0
http.port: 9200 #端口
#设置在集群中的所有节点名称,这个节点名称就是之前所修改的,当然你也可以采用默认的也行,目前是单机,放入一个节点即可
cluster.initial_master_nodes: ["node-1"]

上面看到配置了一个数据目录,这个需要我们自己创建

mkdir data

默认给ElasticSearch配置的JVM内存很高,我服务器内存太小了,会跑不起的。所以改小一点。

vim config/jvm.options

改成

-Xms256m
-Xmx256m

root用户默认是无法启动elasticsearch的,所以需要增加一个Linux用户

useradd elasticsearch
chown elasticsearch /usr/local/elasticsearch-7.6.2/ -R

修改sysctl文件:vim /etc/sysctl.conf ,增加下面配置项

vm.max_map_count=262144

使其生效

sysctl -p

修改文件:vim /etc/security/limits.conf ,增加下面配置项

elasticsearch soft nproc 65565
elasticsearch hard nproc 65565

切换用户

su elasticsearch

查看进程数

ulimit -Hu
ulimit -Su

启动(-d 是后台启动)

/usr/local/elasticsearch-7.6.2/bin/elasticsearch -d

访问,大功告成~

[elasticsearch@iz2zefc352jeey9szh60wlz elasticsearch-7.6.2]$ curl 127.0.0.1:9200
{
  "name" : "node-1",
  "cluster_name" : "my-application",
  "cluster_uuid" : "tkwKzDHuRSSURkA3jnljqQ",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_elasticsearch


安装上面的步骤。配置完剩下俩台

springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_结点_02


springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_结点_03

集群化配置(将上面三台关连起来)

必要字段解释
cluster.name: my-application        # 集群名字,用于将同一个集群的结点关连起来
node.name: "node-1"                   # 当前结点的名字,用于区分同一个集群中的结点
node.master: false                  #  在其它主结点宕机的情况下,是否有被选举成为主结点的资格
node.data: false                    #  当前结点存储数据
network.host: 0.0.0.0   #让所有网络都可以访问
http.port: 9200 #针对开发人员使用的端口
discovery.zen.ping.timeout: 60s      # 用于发现其它结点的超时时间
transport.tcp.port: 9300             # 配置结点之间的客户端端口,下面就使用到
#discovery.zen.ping.unicast.hosts: ["localhost:9300"]  # 其它结点的IP 这个版本6.x用的
discovery.seed_hosts: ["localhost:9300"]  # 其它结点的IP 这个版本7.x用的(因为当前就是7.x所以用这个)
cluster.initial_master_nodes: ["localhost"]  #填master结点有资格的备选结点
network.publish_host: 182.92.6.145  # 必填!!!必填,外网IP,否则集群无法关联起来
http.cors.enabled: true

http.cors.allow-origin: "*"  # 跨域配置
discovery.zen.fd.ping_timeout: 1000s  # 用于发现其它主机的发现时间,可以设置长一点防止网络不好就导致连接超时异常而失败
discovery.zen.fd.ping_retries: 10
182.92.6.145

data与master都设置为false就是用来做负载均衡服务器用。

cluster.name: my-application #集群名称
node.name: node-1 #当前节点名称
#数据和日志的存储目录
path.data: /usr/local/elasticsearch-7.6.2/data
path.logs: /usr/local/elasticsearch-7.6.2/logs
##设置绑定的ip,设置为0.0.0.0以后就可以让任何计算机节点访问到了
network.host: 0.0.0.0
http.port: 9200 #端口
##设置在集群中的所有节点名称,这个节点名称就是之前所修改的,当然你也可以采用默认的也行,目前是单机,放入一个节点即可

discovery.seed_hosts: ["182.92.6.145:9300","121.5.111.192:9300","115.29.193.155:9300"]
cluster.initial_master_nodes: ["182.92.6.145","121.5.111.192","115.29.193.155"]
## ping超时时长,默认3S,适当修改,防止脑裂
discovery.zen.fd.ping_timeout: 1000s
discovery.zen.fd.ping_retries: 10
network.publish_host: 182.92.6.145

http.cors.enabled: true

http.cors.allow-origin: "*"

transport.tcp.port: 9300
#discovery.zen.ping.unicast.hosts: ["182.92.6.145:9300", "121.5.111.192:9300","115.29.193.155:9300"]
discovery.zen.minimum_master_nodes: 2
115.29.193.155

针对上面需要改变的地方

node.name: node-2 #当前节点名称
network.publish_host: 115.29.193.155
121.5.111.192

针对上面需要改变的地方

node.name: node-3 #当前节点名称
network.publish_host: 121.5.111.192

最后分别启动即可

测试

浏览器输入:http://xiaowuqin.cn:9200/_cat/nodes访问即可,如下:

springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_vim_04

调式过程中踩坑记录

1.如果第一次启动elasticsearch用的root用户

如果第一次启动没有切换到其它用户,那么第二次尽管切换到了其它用户,依然会启动不了。
因为logs目录下的文件有几个被加载到了root用户下,其它用户没有权限执行读写,就会报错。
解决:改变文件所属用户为当前用户就行了。

chgrp -R es my-elasearch_server.json 
chown -R es my-elasearch_server.json 
...
2. 版本7.x相比6.x配置区别

相较于6.x配置文件 7.x的如下

cluster.initial_master_nodes:  # 是7.x新引入的配置(配置候选主节点集合)
discovery.seed_hosts:  # 对应旧版本的discovery.zen.ping.unicast.hosts(用于发现其它结点)
3.必配置项,如果不配置,会导致结点之间无法关联起来组成集群
network.publish_host: 115.29.193.155 # 当前结点的云服务器的外网IP
4.如果之前分别单独启动了结点

然后分别完成修改配置文件(改成了将单个结点关联起来的集群化配置),需要分别将它们的data目录删除掉才能启动成功。(data目录不存在它会自己创建)。这里的data目录相当于有了一个缓存需要清除。

参数调优

swap调优
首先明白什么是swap?

从性能上来说,swap上的数据读写速度不如RAM内存
从应用的运行稳定性上来说,swap相当于是一个保险。保险一般用不上,但是如果没有,真正发生意外的时候又后悔莫及。
从LInux的内核机制来说,要尽量保证每一个运行的应用都可以正常运行。因此当一个新的应用请求内存空间时,如果当时的内存空间不太够时,就会触发swap机制,让一些不常用的已经加载到内存中的文件回收进swap,从而释放出内存给新来的应用使用。而这个回收进swap的文件要再次被使用的时候,就会又重新加载到内存,这就称为swap交换。

而这elasticsearch为了实现极高的读写速度,就要尽量避免这种swap交换,影响性能。

如何配置swap?

yml中加入配置:

bootstrap.memory_lock: true   # 单单从字母意思上就可以看出锁住内存,不让交换

修改/etc/security/limits.conf (因为是修改系统级配置,要使用root用户)
加入:

elasticsearch hard memlock unlimited
elasticsearch soft memlock unlimited

springboot整合及使用

新建一个springboot项目(然后勾选一个web就行了)

springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_elasticsearch_05


引入依赖(注意版本号一定要与你实际部署的一致,我的是7.6.2)

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.2</version>
</dependency>

另外注意这里的版本也要确认真的加载进来的是一致的版本号

springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_vim_06


如果不一样就配置这个,自定义

<!--        自己定义elasticsearch版本-->
 <elasticsearch.version>7.6.2</elasticsearch.version>

代码

RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("115.29.193.155", 9200, "http"),
                        new HttpHost("121.5.111.192", 9200, "http"),
                        new HttpHost("182.92.6.145", 9200, "http")));
        
        MainResponse info = client.info(RequestOptions.DEFAULT);
        System.out.println("集群名字:"+info.getClusterName());
        System.out.println("当前获得的结点名字"+info.getNodeName());
        client.close();

运行结果

springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_elasticsearch_07


可以看到获取到的是node-2结点,然后我去把node-2 kill-9掉,模拟下宕机

springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_结点_08


再次获取,发现获取到的是node-3了,好了收工~

springboot集成es如何在连接不上es的时候仍然启动服务 springboot配置es集群_vim_09


最后附上多条件查询及高亮代码demo

SearchRequest request = new SearchRequest("xiaowuqin");
        //构建搜索条件
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //分页
//        builder.from(0);
//        builder.size(10);
        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name");
        highlightBuilder.preTags("<span style='color:red;'>");
        highlightBuilder.postTags("</span>");
        builder.highlighter(highlightBuilder);


        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();


        //分词匹配
        MatchQueryBuilder query = QueryBuilders.matchQuery("name", "山芯");
        TermQueryBuilder query1 = QueryBuilders.termQuery("age", 3);
        boolQueryBuilder.should(query1);
        boolQueryBuilder.should(query);//多条件的或查询

        //条件封装
        //SearchSourceBuilder source = builder.query(query);
        SearchSourceBuilder source = builder.query(boolQueryBuilder);

        request.source(source);
        SearchResponse search = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = search.getHits();
        SearchHit[] hits1 = hits.getHits();
        for(SearchHit t:hits1){
            //关键字高亮
            Map<String, HighlightField> highlightFields = t.getHighlightFields();
            HighlightField name = highlightFields.get("name");
            Map<String, Object> sourceAsMap = t.getSourceAsMap();//原来的结果
            //解析高亮字段
            if(name!=null){
                Text[] fragments = name.fragments();
                String newname="";
                for(Text tt:fragments){
                    newname+=tt;
                }
                sourceAsMap.put("name",newname);
            }


            System.out.println(sourceAsMap);