本次博文發兩塊,前部分是怎樣搭建一個Elastic集羣,後半部分是基於Java對數據進行寫入和聚合統計。html
1、Elastic集羣搭建java
1. 環境準備。node
該集羣環境基於VMware虛擬機、CentOS 7系統,公司目前用的服務器系統基本全是CentOS系統,所以就選了這個。Elasticsearch須要依賴的最低環境就是JDK8,且要配置好環境變量JAVA_HOME. Elasticsearch的安裝也能夠查看官網給出的安裝說明。git
虛擬機系統採用的是最小化安裝,沒有安裝桌面程序。安裝完程序再安裝JDK,配置環境變量便可。github
2. 集羣搭建。web
2.1 安裝包解壓spring
下載完成後的Elastic包爲elasticsearch-6.3.2.tar.gz,對其解壓。apache
# 將elastic包加壓到目錄 /data/elastic 下 tar zxvf elasticsearch-6.3.2.tar.gz -C /data/elastic
2.2 配置文件修改json
解壓後的路徑爲/data/elastic/elasticsearch-6.3.2,在/data/elastic目錄下新增兩個文件夾,爲data,logs,其中data用來存儲節點數據,logs用來存儲日誌,下面在修改配置文件中須要用到。修改config/elasticsearch.yml以下。服務器
# 集羣名稱 cluster.name: elastic_test # 節點名稱 node.name: node-1 # 數據目錄,剛纔建立的data目錄 path.data: /data/elastic/data #日誌路徑 ,剛纔建立的logs目錄 path.logs: /data/elastic/logs #綁定地址,修改成任何機器都能訪問 network.host: 0.0.0.0 #端口,默認9200,不作修改 #http.port: 9200 # 集羣節點,當節點啓動後平臺就會發現 discovery.zen.ping.unicast.hosts: ["172.16.106.190", "172.16.106.191", "172.16.106.192"] # 最小主節點數量,配置2
# 該配置告訴ELasticsearch當沒有足夠的master候選節點的時候,不進行master節點選舉,等master節點足夠了才進行選舉 discovery.zen.minimum_master_nodes: 2
2.3 其餘機器修改
修改完一臺機器後,一樣其餘兩臺機器相似修改,注意把節點名稱改成不同的就能夠了。
2.4 集羣啓動
啓動說明:elasticsearch的啓動不能使用root用戶,因此要新建一個普通用戶。如下是具體操做。
# 新建一個用戶組爲elasticgp groupadd elasticgp # 新建一個用戶名爲elastic的用戶,而且歸屬到elasticgp用戶組 useradd -g elasticgp elastic # 給用戶設置密碼 passwd elastic # 上面已經減了一個文件夾,/data/elastic,該文件夾存儲了elastic軟件和數據目錄data及日誌目錄logs # 如今將elastic目錄的歸屬組修改爲elastgp chgrp -R elasticgp elastic/ # 將文件目錄/data/elastic所屬用戶修改成用戶elastic chown -R elastic elastic/
用戶配置好後切換到elastic用戶進行啓動程序。
# 切換到elastic用戶 su elastic # 切換到程序目錄下 cd /data/elastic/elasticsearch-6.3.2 # 後臺啓動程序 ./bin/elasticsearch -d # 查看輸出日誌 tailf ../logs/elastic_test.log
2.5 問題排查
啓動的時候可能會出現如下兩個問題
問題1:將當前用戶的軟硬限制調大
修改文件 /etc/security/limits.conf
# elastic用戶的軟限制 固然也可用*代替,標識修改全部用戶 elastic soft nofile 65535 # elastic用戶的硬限制 固然也可用*代替,標識修改全部用戶 elastic hard nofile 65537
問題2:修改/etc/sysctl.conf
vm.max_map_count=262144
問題3: 啓動內存設置
在內存不充足的狀況下,能夠修改elastic的初始內存,在/data/elastic/elasticsearch-6.3.2/config目錄下有配置文件
# 將內存使用設置爲512M -Xms512M -Xmx512M
問題4:端口是否開放
elastic須要用到9200和9300兩個端口,能夠用telnet來查看端口是否開放,如下是修改防火牆打開端口的命令。
集羣中的節點經過端口 9300 彼此通訊。若是這個端口沒有打開,節點將沒法造成一個集羣。
# 永久開放9200端口 firewall-cmd --permanent --zone=public --add-port=9200/tcp # 永久開放9300端口 firewall-cmd --permanent --zone=public --add-port=9300/tcp #從新加載防火牆配置,使開放端口生效 firewall-cmd --reload
2.6 集羣狀態查看
以下圖,經過訪問某一個節點,查看全部的節點,其中node-1爲主節點。
以下圖,查看集羣健康狀態
以上爲elasticsearch集羣具體安裝過程。具體的API調用說明能夠查看官網CAT_API和Cluster_APIs等等。
2.7 kibana 使用
集羣搭建好以後,可用經過kibana來訪問集羣的一個節點,而後作一下簡單的測試。先去官網下載kibana安裝包
https://www.elastic.co/downloads/kibana
我是下載的mac客戶端,其餘客戶端應該也是同樣的。
解壓kibana安裝包後,在bin目錄下執行
# 查看kibana命令幫助
./bin/kibana -h
會看到以下提示:
Usage: bin/kibana [command=serve] [options] Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Commands: serve [options] Run the kibana server help <command> Get the help for a specific command "serve" Options: -h, --help output usage information -e, --elasticsearch <uri> Elasticsearch instance -c, --config <path> Path to the config file, can be changed with the CONFIG_PATH environment variable as well. Use multiple --config args to include multiple config files. -p, --port <port> The port to bind to -q, --quiet Prevent all logging except errors -Q, --silent Prevent all logging --verbose Turns on verbose logging -H, --host <host> The host to bind to -l, --log-file <path> The file to log to --plugin-dir <path> A path to scan for plugins, this can be specified multiple times to specify multiple directories --plugin-path <path> A path to a plugin which should be included by the server, this can be specified multiple times to specify multiple paths --plugins <path> an alias for --plugin-dir
其中咱們須要用的就是 -e 參數,來鏈接指定的elasticsearch
# 啓動kibana,鏈接到制定的Elastic服務節點 ./bin/kibana -e http://172.16.106.201:9200
啓動成功後能夠訪問localhost:5601,以下圖,點擊監控菜單看到集羣的一些狀態信息。indices是索引數量,除了本身新建的索引Elasticsearch自己也有一些索引。
以下圖,點擊DevTools菜單,能夠對集羣節點上的數據進行查詢了。
2、Java客戶端對數據存儲和查詢
1. 客戶端配置,能夠查看官網詳細配置
採用maven管理,添加依賴的pom配置便可
<!-- Java High Level REST Client --> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>6.3.2</version> <exclusions> <exclusion> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> </exclusion> </exclusions> </dependency> <!-- Client 包缺乏一些東西,所以引入此包 能夠具體查看ISSUE https://github.com/elastic/elasticsearch/issues/26959 --> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>6.3.2</version> </dependency>
2. 如下是測試主要代碼
package com.woasis.elastic.demo; import org.apache.http.HttpHost; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; @RestController public class IndexController { private static RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("172.16.106.201",9200, "http"), new HttpHost("172.16.106.202",9200, "http"), new HttpHost("172.16.106.203",9200, "http") ) ); /** * 向索引下增長數據 * @param indexName * @param type * @return */ @GetMapping("/putdata") public String putDataForIndex(String indexName, String type){ if (StringUtils.isEmpty(indexName)){ return "請指定索引名稱"; } SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); StringBuilder indexBuilder = new StringBuilder(); indexBuilder.append(indexName); indexBuilder.append("-"); indexBuilder.append(simpleDateFormat.format(new Date())); String fullIndexName = indexBuilder.toString(); System.out.println("索引名稱是:"+fullIndexName); Random random = new Random(); try { XContentBuilder contentBuilder = XContentFactory.jsonBuilder(); contentBuilder.startObject(); contentBuilder.field("name", "people"+System.currentTimeMillis()); contentBuilder.field("age", random.nextInt(30)); contentBuilder.field("createDate", new Date()); contentBuilder.endObject(); //索引請求 IndexRequest indexRequest = new IndexRequest(fullIndexName, type).source(contentBuilder); IndexResponse indexResponse = client.index(indexRequest); System.out.println(indexResponse.getIndex()); // client.close(); } catch (IOException e) { e.printStackTrace(); } return "SUCCESS"; } /** * 根據索引名稱,type,id獲取數據 * @return */ @GetMapping("/getdata") public String getData(){ //Get請求 GetRequest getRequest = new GetRequest("people-2018-07-31","student", "DfLL72QBGxN1JyvW1KG4"); try { GetResponse response = client.get(getRequest); System.out.println("index:"+response.getIndex()); System.out.println("type:"+response.getType()); System.out.println("id:"+response.getId()); System.out.println("sourceString:"+response.getSourceAsString()); } catch (IOException e) { e.printStackTrace(); } return "SUCCESS"; } /** * 搜索數據 * @return */ @GetMapping("/searchdata") public String searchData(){ //Search請求 SearchRequest searchRequest = new SearchRequest("people-2018-07-31"); //查詢過濾條件 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.termQuery("name","people1533031470255")); searchRequest.source(searchSourceBuilder); try { SearchResponse searchResponse = client.search(searchRequest); SearchHits searchHits = searchResponse.getHits(); for (SearchHit hit : searchHits){ System.out.println("index:"+hit.getIndex()); System.out.println("type:"+hit.getType()); System.out.println("id:"+hit.getId()); System.out.println("sourceString:"+hit.getSourceAsString()); } } catch (IOException e) { e.printStackTrace(); } return "SUCCESS"; } }
官方在各個API使用方式上都有詳細的講解,有用到的能夠在官網查看。跳轉地址
該demo程序使用spring boot搭建,能夠查看Github源碼https://github.com/liuzwei/elastic-demo