ElasticSearch大資料分散式彈性搜尋引擎使用

weixin_33896726發表於2018-01-02

閱讀目錄:

  1. 背景
  2. 安裝
    1. 查詢、下載rpm包 、執行rpm包安裝
    2. 配置elasticsearch專屬賬戶和組
    3. 設定elasticsearch檔案所有者
    4. 切換到elasticsearch專屬賬戶測試能否成功啟動
    5. 安裝自啟動elasticsearch servicewrapper包
      1. 下載elasticsearch servicewrapper 包
      2. elasticsearch servicewrapper開源包的配置小bug
      3. servicewrapper安裝
      4. chkconfig -add 加入linux啟動服務列表
    6. 安裝_plugin/head管理外掛(輔助管理)
    7. 安裝chrom中的elasticsearch客戶端外掛
    8. 使用elasticsearch自帶的_cat工具
    9. clone 虛機(修改IP、HWaddr、UUID配置,最後修改下系統時間)
  3. 配置
    1. elasticsearch.yml配置
      1. IP訪問限制、預設埠修改9200
      2. 叢集發現IP列表、node、cluster 名稱
      3. master node 啟動切換
    2. linux 開啟最大檔案數設定(用作index時候的系統閥值)
    3. 安裝中文分詞器ik(注意對應版本問題)
    4. elasticsearch叢集規劃
  4. 開發
    1. 連線叢集
      1. net nest使用(使用pool連線es叢集)
      2. java jest使用(使用pool連線es叢集)
    2. index開發
      1. mapping 配置
      2. mapping template配置
      3. index routing索引路由配置
  5. 總結

1.背景

兩年前有機會接觸過elasticsearch,但是未做深入學習,只是工作中用到了。越來越發現es是個不錯的好東西,所以花了點時間好好學習了下。在學習過程中也發現了一些問題,網上大多資料都很零散,大部分都是實驗性的demo,很多問題並沒有講清楚也並沒有系統的講完整一整套方案,所以耐心的摸索和總結了一些東西分享出來。

畢竟當你用生產使用的標準來使用es時會有很多問題,這對你的學習提出來了新的標準。

比如,使用elasticsearch servicewrapper進行自啟動的時候難道就沒發現它的配置中有一個小bug導致load不了elasticsearch jar包中的class嗎。

還有es不同版本之間的差異巨大,比如,1.0中的分散式routing在2.0中進行了巨大差異的修改。原本routing是跟著mapping一起配置的,到了2.0卻跟著index動態走了。這個調整的本質目的是好的,讓同一個index的不同type都有機會選擇shard的片鍵。如果是跟著mapping走的話就只能限定於當前index的所有type。

es是個好東西,現在越來越多的分散式系統都需要用到它來解決問題。從ELK這種系統層的工具到電商平臺的核心業務交易系統的設計都需要它來支撐實時大資料搜尋分析。比如,商品中心的上千萬的sku需要實時搜尋,再到海量的線上訂單實時查詢都需要用到搜尋。

在一些DevOps的工具中都需要es來提供強大的實時搜尋功能。值得花點時間好好研究學習下。

作為電商架構師,所以沒有什麼理由不去學習和使用它來提高系統的整體服務水平。本篇文章將自己這段時間學習的經驗總結出來分享給大家。

2.安裝

首先你需要幾臺linux機器,你跑虛機也行。你可以在一臺虛擬機器上完成安裝和配置,然後將當前虛擬機器clone出多份修改下IP、HWaddr、UUID即用,這樣方便你使用,而不需要再重複的安裝配置。

1.我本地是三臺Linux centos6.5,IP分別是,192.168.0.10、192.168.0.20、192.168.0.30。

(我們先在192.168.0.10上執行安裝配置,然後一切就緒之後我們將這個節點clone出來修改配置,然後再配置叢集引數,最後形成可以工作的以三個node組成的叢集例項。)

2.由於ElasticSearch是java語言開發的,所以我們需要預先安裝好java相關環境。我使用的是JDK8,直接使用yum安裝即可,yum倉庫有最新的源。

先檢視你當前機器是否安裝了java環境:

yum info installed |grep java*

16

如果已經存在java環境且這個環境不是你想要的,你可以解除安裝然後重新安裝你想要的版本。(yum –y remove xxx)如果解除安裝不乾淨,你可以直接find 查詢相關檔案,然後直接物理刪除。linux的系統都是基於檔案的,只要能找到基本上都可以刪除。

先看下有哪些版本:

yum search java

java-1.8.0-openjdk.x86_64 : OpenJDK Runtime Environment(找到這個源)

然後執行安裝:

yum –y install java-1.8.0-openjdk.x86_64

安裝好之後檢視java 相關引數:

java –version

14

預備工作我們已經做好,接下來我們將執行ElasticSearch的環境安裝和配置。

2.1.查詢、下載rpm包、執行rpm包安裝

你可以有幾種方式安裝。使用yum repository是最快最便捷的,但是一般這裡面的版本應該是比較滯後的。所以我是直接到官網下載rpm包安裝的。

elasticsearch官方下載地址:https://www.elastic.co/downloads/elasticsearch

1

找到你對應的系統型別檔案,當然如果你是windows系統那就直接下載zip包使用就行了。這裡我需要rpm檔案。

你也可以安裝本地yum 源,然後還是使用yum命令安裝。

我是使用wget 工具直接下載RPM檔案到本地的。(如果你的包有依賴建議還是yum方式安裝。)

(如果你的wget命令不起作用,記得先安裝:yum -y install wget)

wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/rpm/elasticsearch/2.4.0/elasticsearch-2.4.0.rpm

然後等待下載完成。

這裡有個東西需要提醒下,就是你是否要安裝最新版本的elasticsearch,個人建議還是安裝稍微低一個版本的,我本地安裝的是2.3.4的版本。為什麼要這樣強調尼,因為當你安裝了很高的版本之後有一個很大的問題就是中文分詞器能否支援到這個版本。從2.3.5之後就直接到2.4.0的版本了,我當時安裝的是2.3.5的版本後來發現一個問題就是ik中文分詞器我得git clone下來編譯後才能有輸出部署檔案。所以建議大家安裝2.3.4的版本,2.3.4的版本中文分詞器就可以直接在linux伺服器裡下載部署,很方便。

執行安裝:

rpm -iv elasticsearch-2.3.4.rpm

然後等待安裝完成。

不出什麼意外,安裝就應該完成了。我們進行下基本的安裝資訊檢視,是否安裝之後缺少什麼檔案。因為有些包裡面會缺少一些config配置。如果缺少我們還得補充完整。

為了方便檢視安裝涉及到的檔案,你可以導航到根目錄下 find。

cd /

find . –name elasticsearch

./var/lib/elasticsearch 
./var/log/elasticsearch 
./var/run/elasticsearch 
./etc/rc.d/init.d/elasticsearch 
./etc/sysconfig/elasticsearch 
./etc/elasticsearch 
./usr/share/elasticsearch 
./usr/share/elasticsearch/bin/elasticsearch

基本上差不多了,你還得看下是否缺少config,因為我安裝的時候是缺少的。

cd /usr/share/elasticsearch/

ll

drwxr-xr-x. 2 root          root           4096 9月   4 01:10 bin 
drwxr-xr-x. 2 root          root           4096 9月   4 01:10 lib 
-rw-r--r--. 1 root          root          11358 6月  30 19:22 LICENSE.txt 
drwxr-xr-x. 5 root          root           4096 9月   4 01:10 modules 
-rw-r--r--. 1 root          root            150 6月  30 19:22 NOTICE.txt 
drwxr-xr-x. 2 elasticsearch elasticsearch  4096 6月  30 19:32 plugins 
-rw-r--r--. 1 root          root           8700 6月  30 19:22 README.textile

大概看下你應該也是缺少config資料夾的。我們還得把這個資料夾建好,同時還需要一個elasticsearch.yml配置檔案。要不然啟動的時候肯定是報錯的。

mkdir config

cd config

vim elasticsearch.yml

找一下elasticsearch.yml配置貼上去,或者你用檔案的方式傳送也行。這些配置都是基本的,回頭還需要根據情況調整配置的。有些配置在配置檔案中是沒有的,還需要到官方上去查詢的。所以這裡無所謂配置檔案的全或者不全。關於配置項網上有很多資料,所以這個無所謂的。

儲存下elasticsearch.yml檔案。

你還需要一個logging.yml日誌配置檔案。es作為伺服器後臺執行的服務是肯定需要日誌檔案的。這部分日誌會被你的日誌平臺收集和監控,用來做為運維健康檢查。logging.yml本質上是一個log4j的配置檔案,這個應該大家都比較熟悉了。跟elasticsearch.yml類似,要麼複製貼上要麼檔案傳送。

日誌的輸出在logs目錄下,這個目錄會被自動建立。但是我還是喜歡建立好,不喜歡有不確定因素,也許它就不會自動建立。

mkdir logs

最後需要設定下剛才我們新增的檔案的執行許可權。要不然你的檔名字應該是白色的,是不允許被執行。

2

cd ..

chmod –R u+x config/

3

現在基本上安裝算是完成了,試著cd到檔案的啟動目錄下啟動es,來檢查下是否能正常啟動。

不出意外你會收到一個 “java.lang.RuntimeException: don't run elasticsearch as root”異常。這說明我們完成了第一步安裝過程,下節我們來看有關啟動賬戶的問題。

4

2.2.配置elasticsearch專屬賬戶和組

預設情況下es是不允許root賬戶啟動的,這是為了安全起見。es預設內嵌了groovy指令碼引擎的功能,還有很多plugin指令碼引擎外掛,確實不太安全。es剛出來的時候還有groovy漏洞,所以建議在產線的es instance 關掉這個指令碼功能。雖然預設不是開啟的,安全起見還是檢查一下你的配置。

所以我們需要為es配置獨立的賬戶和組。在建立es專用賬戶之前先檢視下系統裡面是否已經有了es專用賬戶。因為在我們前面rpm安裝的時候會自動安裝elasticsearch組和使用者。先檢視下,如果你的安裝沒有帶上專用組和使用者然後你在建立。這樣以免你自己增加的和系統建立的搞混淆。

檢視下組:

cat /etc/group

5

 

 

檢視下使用者:

cat /etc/passwd

6

基本上都建立好了。499的group在passwd中也建立了對應的elasticsearch賬號。

如果你係統裡沒有自動建立對應的組和賬號,你就動手自己建立,如下:

建立組:

groupadd elasticsearch_group

7

建立使用者:

useradd elasticsearch_user -g elasticsearch_group -s /sbin/nologin

8

注意:此賬戶是不具有登入許可權的。它的shell是在/sbin/nologin。

為了演示,在我的電腦上有兩組elasticsearch專用賬戶,我將刪除“_group”和“_user”結尾的賬號,以rpm自動安裝的為es的啟動賬號(elasticsearch)。

2.3.設定elasticsearch檔案所有者

接下來我們需要做的就是關聯es檔案和elasticsearch賬號,將es相關的檔案設定成elasticsearch使用者為所有者,這樣elasticsearch使用者就可以沒有任何許可權限制的使用es所有檔案。

導航到elasticsearch上級目錄:

cd /usr/share

ll

9

chown -R elasticsearch:elasticsearch elasticsearch/

10

此時,你的elasticsearch檔案的owner是elasticsearch。

2.4.切換到elasticsearch專屬賬戶測試能否成功啟動

為了測試啟動es例項,我們需要暫時的將elasticsearch的使用者切換到/bin/bash。這樣我們就可以su elasticsearch,然後啟動es例項。

su elasticsearch

cd /usr/share/elasticsearch/bin

./elasticsearch

11

啟動完成,此時應該沒發生任何異常。看下系統埠是否啟動成功。

netstat –tnl

12

繼續檢視下HTTP服務是否啟動正常。

curl –get http://192.168.0.103:9200/_cat

13

由於此時我們並沒有安裝任何輔助管理工具,如,plugin/head。所以用內建的_cat rest endpoit還是挺方便的。

curl -get http://192.168.0.103:9200/_cat/nodes

192.168.0.103 192.168.0.103 4 64 0.00 d * node-1

可以看見,目前只有一個節點在工作,192.168.0.103,且它是一個data node。

(備註:為了節省時間,我暫時先使用一臺103的乾淨環境作為安裝和環境搭建演示,當搭建叢集的時候我會clone出來和修改IP。)

2.5.安裝自啟動elasticsearch servicewrapper包

es的系統自啟動有一個開源的wrapper包可以使用。如果你不使用這個wrapper也可以自己去寫shell指令碼,但是裡面的很多引數需要你搞的非常清楚才行,在加上有些關鍵引數需要設定。所以還是建議在elasticsearchwrapper包的基礎上進行修改效率會高點,而且你還能在elasticsearch shell中看見一些es深層次的配置和原理。

(備註:如果你是.neter,你可以將servicewrapper理解成是開源.net topshelf。本質就是將程式包裝成具有系統服務功能,你可以安裝、解除安裝,也可以直接啟動、停止,或者乾脆直接前臺執行。)

2.5.1.下載elasticsearch servicewrapper 包

elasticsearchwrapper github首頁,https://github.com/elastic/elasticsearch-servicewrapper

17

複製 git repository 地址到剪貼簿,然後直接clone到本地。

git clone https://github.com/elastic/elasticsearch-servicewrapper.git

(你需要在當前linux機器上安裝git客戶端:yum –y install git,我安裝的是預設1.7的版本。)

然後等待clone完成。

18

檢視下clone下來的本地倉庫檔案情況。進入elasticsearchwrapper,檢視當前git 分支。

cd /root/elasticsearch-servicewrapper

git branch

*master

ll

一切都很正常,說明我們clone下來沒問題,包括分支也是很清晰的。service檔案就是我們要安裝的安裝檔案。

20

我們需要將service檔案copy到elasticsearch/bin目錄下。

cp -R service/ /usr/share/elasticsearch/bin/

cd /usr/share/elasticsearch/bin/

21

service裡的安裝檔案需要在elasticsearch/bin目錄下工作。 
cd service/

ll

./elasticsearch

22

參考github上elasticsearchwrapper使用說明。elasticsearch servicewrapper的功能還是蠻多的,status、dump都是很好的檢查和除錯工具。

19

在安裝之前,我們需要暫時在前臺執行es例項,這樣可以檢視一些log是否有異常情況。Parameter的各個引數寫的很清楚,我們這裡使用console控制檯輸出啟動es例項。

./elasticsearch console

2.5.2 elasticsearch servicewrapper開源包的配置小bug

此時你應該會收到一個Error的提示:

WrapperSimpleApp Error: Unable to locate the class org.elasticsearch.bootstrap.ElasticsearchF : java.lang.ClassNotFoundException: org.elasticsearch.bootstrap.ElasticsearchF

23

第一次看到這個我有點蒙,這個ElasticsearchF是個什麼物件。命名有點特殊,再進一步檢視Exception的資訊,其實是一個ClassNotFoundException異常。說明找不到這個ElasticSearchF類。

兩種可能性,第一就是java elasticsearch相關包的問題,確實缺少這個類。但是這個可能性很小,因為我們之前直接執行elasticsearch是成功的。我當時用jd-gui翻了下es的包,確實沒有這個類。

第二就是這裡的配置錯誤,應該就個手誤,確實沒有ElasticsearchF這個類。

我們檢視下service/elasticsearch.conf配置檔案裡是不是有這個‘elasticsearchF’字串。(wrapper包是使用當前目錄下的elasticsearch.conf作為配置檔案使用的)

grep –i elasticsearchf elasticsearch.conf

24

確實有這個字串,我們進行編輯儲存,去掉最後的‘F’。

25

然後我們在進行啟動嘗試。

./elasticsearch console

我不知道你是不是會和我的情況一樣,提示相關命令都是不規範的。

26

這個執行鏈路基本上經過三個路徑,第一個就是service/elasticsearch shell啟動指令碼,然後獲取命令分析命令再啟動exec下的相關java servicewrapper程式。

這個java servicewrapper程式,版本是3.5.14。根據上述思路,通過檢視elasticsearch shell程式,它在接收到外部的命令之後會啟動exec下的java servicewrapper程式。我想試著編輯了下elasticsearch shell檔案,輸出一些資訊出來,檢視下是不是獲取相關路徑或者引數之類的導致錯誤。(遇到問題不怕,至少我們要一路跟下去,看下究竟是怎麼回事。)

vim ./elasticsearch

esc

:/console

找下console在哪裡,然後加上除錯文字資訊,輸出到介面上。

27

再執行,檢視命令引數是否有問題。

28

檢視了下,輸出的引數基本都沒有問題。一時無解。好奇心作怪,本想再進一步看下exec/elasticsearch-linux-x86-64.so檔案的,後來發現開啟根本就看不懂。所以就另尋其他方法,我找了windows版本servicewrapper,發現windows的elasticsearchservicewrapper是沒有32位的servicewrapper的。我試著執行起來基本上也是報相同的錯誤,但是windows的wrapper的error資訊比較多點,提示出錯的原因在哪裡。

我想修改下日誌的輸出級別,看能否輸出一些可以用的資訊。編輯service/elasticsearch.conf wrapper包專用配置。

# Log Level for console output.  (See docs for log levels) 
wrapper.console.loglevel=TRACE

# Log Level for console output.  (See docs for log levels) 
wrapper.console.loglevel=TRACE

我們將日誌輸出級別設定成trace,有兩處需要設定,我們再看輸出資訊。

29

是輸出了一些有用的資訊,可以檢視log檔案詳情。

WrapperManager Debug: Received a packet LOGFILE : /usr/share/elasticsearch/logs/service.log

但是有關於error的資訊還是隻有一條。

這裡就告一段落。我們的目的是為了使用console來執行,想檢視下一些執行日誌,但是跑不起來也無所謂,我們繼續執行安裝操作。

(哪位博友如果知道問題在哪裡的可以分享出來,我覺得這個問題不是一個偶發性問題,應該都會遇到。我先丟擲問題,至少可以服務將來的使用者。這裡先謝謝了。)

其實,如果你不使用elasticsearch servicewrapper來包裝而是自己去下載java serivcewrapper來包裝elasticsearch也是可以的,實現起來也很方便。

我們回到主題,既然我們無法console執行,也看不了一些wrapper console執行時的情況,那我們就只能進行安裝了。

2.5.3 servicewrapper安裝 (elasticsearch init.d 啟動檔案設定user、openfile、configpath)

按照elasticsearch servicewrapper parameter引數指示,我們執行安裝。

./elasticsearch install

Installing the Elasticsearch daemon..

守護程式安裝完成。我們還是前去系統目錄下檢視是不是安裝成功(技術人員始終保持一個嚴謹的心態是有必要的。)前往/etc/init.d/目錄下檢視。

ll /etc/init.d/

-rwxrwxr--. 1 root root  4496 10月  4 01:43 elasticsearch

我這裡設定過chmod u+x ./elasticsearch。別忘記設定檔案的執行許可權,這在我們【2.1節】裡將結果,這裡就不重複了。

我們開始編輯elasticsearch啟動檔案。

30

主要就是這段,填寫好配置的es的專用賬戶(elasticsearch【2.2.節】),還有相應的檔案路徑。這裡先忽略MAX_OPEN_FILES、MAX_MAP_COUNT兩個配置項,在後面【3.3.節】配置部分會講解到。

2.5.4 chkconfig -add 加入linux啟動服務列表

將其新增到系統服務中,以便被系統自動啟動。

chkconfig --add elasticsearch

chkconfig –list

31

已經新增好系統自啟動服務列表中。

service elasticsearch start

啟動es例項,等待埠啟動完成,稍等片刻檢視埠情況。

netstat –tnl

32

9300埠比9200埠先啟動,因為9300埠是 cluster內部管理埠。9200是rest endpoint 服務埠。當然,這個時間延長不會很長。

埠都啟動成功之後,我們檢視下能否正常訪問es例項。

curl -get http://192.168.0.103:9200/ 

  "name" : "node-1", 
  "cluster_name" : "orderSearch_cluster", 
  "version" : { 
    "number" : "2.3.4", 
    "build_hash" : "e455fd0c13dceca8dbbdbb1665d068ae55dabe3f", 
    "build_timestamp" : "2016-06-30T11:24:31Z", 
    "build_snapshot" : false, 
    "lucene_version" : "5.5.0" 
  }, 
  "tagline" : "You Know, for Search" 
}

我們還是使用_cat rest endpoint來檢視。

curl -get http://192.168.0.103:9200/_cat/nodes 
192.168.0.103 192.168.0.103 4 61 0.00 d * node-1

如果你可以在本機訪問,但是在外部瀏覽器中無法訪問,很可能是防火牆的設定問題,你可以去設定下防火牆。

33

vim /etc/sysconfig/iptables

重啟網路服務,以便載入防火牆設定項。

service network restart

然後再嘗試看能否外部訪問,如果不行你就telnet埠下。

因為訪問不了還有一個原因是和elasticsearch.yml一個配置項有關係。見【3.1.1節】。

 

重啟機器,檢視es例項是否會自動啟動。

shutdown –r now

稍等片刻,然後嘗試連線機器。

如果沒出什麼意外,都應該正常的,埠也啟動成功了。說明我們完成了es例項自啟動功能,它現在作為linux系統服務被自動管理。

安裝成服務之後,elasticsearch servicewrapper和我們就沒有太多關係了。因為它的parameter都是圍繞者我們基於servicewrapper來使用的。

2.6.安裝_plugin/head管理外掛(輔助管理)

為了很好的管理叢集,我們需要相應的工具,head是比較流行和通用的,而且是免費的。當然還有很多好用的其他工具,如,Bigdesk、Marvel(商用收費)。plugin的安裝都大同小異,我們這裡就使用通用的head工具。

先看下,head給我們帶來的清晰的叢集節點管理檢視。

34

這是有三個節點的es叢集例項。它是一個二維矩陣排列,最上面橫向是索引,最左邊是節點,交叉的地方是索引的分片資訊和分片比例。

安裝head外掛還是比較方便的,你也可以直接copy檔案的方式使用。在elasticsearch的home目錄下有一個plugins目錄,它是所有外掛的目錄,所有的外掛都會在這個資料夾查詢和載入。

我們看下安裝head外掛方法。在elasticsearch/bin 目錄下有一個plugin可執行檔案,它是專門用來安裝外掛用的程式。

./plugin -install mobz/elasticsearch-head

外掛的查詢路徑有幾個elasticsearch官網是一個,github是一個。這裡會先嚐試在github上查詢,稍等片刻,等待安裝完成。我們嘗試訪問head外掛地址rest地址/_plugin/head。

35

看到這個介面基本安裝成功了,node-1預設是master節點。

2.7.安裝chrom中的elasticsearch客戶端外掛

chrom中有很多可以使用的elasticsearch客戶端外掛,便於開發和維護,建議直接使用chrom中的外掛。只要搜尋下elasticsearch關鍵字就會出來很多。

36

有兩個比較常用,也比較好用,EalsticSearch Toolbox、Sense(自動提示dsl編輯工具)。chrom外掛都是那麼的酷,使用起來都很賞心悅目。

37

elasticsearch toolbox 可以很方便的查詢和匯出資料。

38

sense可以讓你編輯elasticsearch dsl 特定語言會有啟動提示幫助,這樣編寫起復雜的dsl效率會高而且不易出錯。其他的工具我也沒用過,感覺都可以嘗試用用看。

(備註:如果你無法訪問chrom商店中心就需要特殊處理下,這裡就不解釋了。)

2.8.使用elasticsearch自帶的_cat工具

在一些特殊的情況下你可能無法直接使用plugin來幫你管理或者檢視叢集情況。此時你可以直接使用elasticsearch自帶的rest _cat檢視叢集情況,比如,你可能發現_plugin/head有一些節點沒有上來,但是你又不確定發生了什麼情況,你就可以使用/_cat/nodes來檢視所有node的情況。有時候確實有的節點沒有啟動起來,但是大多數情況下都是各自為政(腦裂),你可能需要讓他們重新選舉或者加快的選舉過程。

http://192.168.0.20:9200/_cat/nodes?v (檢視nodes情況)

39

_cat rest端點帶有一個v的引數,這個引數是幫助你閱讀的引數。_search rest端點帶有pretty引數,這個引數是幫助查詢資料閱讀的。每一個端點基本上都有各自的輔助閱讀引數。

http://192.168.0.20:9200/_cat/shards?v(檢視shards情況)

40

http://192.168.0.20:9200/_cat/ (檢視所有可以cat的功能)

41

你可以檢視系統 aliases別名、segments片段(看下每個片段的提交版本一致性)、indices索引集合等等。

2.9.clone 虛機(修改IP、HWaddr、UUID配置,最後修改下系統時間)

當我們完成了對一臺機器的安裝之後,接下來就需要搭建分散式系統。分散式系統就需要多節點機器,按照es分散式叢集搭建最佳實踐,你至少需要三個節點。所以我們將已經安裝完成的這個機器clone出來兩臺,一共三臺組成可以工作的三個節點的分散式系統。

首先clone當前安裝完成的機器,192.168.0.103,clone好之後啟動起來修改幾個配置即可。(因為你是clone出來的,所以配置已經重複,比如,網路卡地址、IP地址)

編輯網路卡配置檔案:

vim /etc/sysconfig/network-scripts/ifcfg-eth0

DEVICE=eth3 
HWADDR=00:0C:29:CF:48:23 
TYPE=Ethernet 
UUID=b848e750-d491-4c9d-b2ca-c853f21bf40b 
ONBOOT=yes 
NM_CONTROLLED=yes 
BOOTPROTO=static 
BROADCAST=192.168.233.255 
IPADDR=192.168.0.103 
NETMASK=255.255.255.0 
GATEWAY=192.168.0.1

DEVICE 是網路卡標示,根據你本地的網路卡標識修改成對應的即可,可以通過ifconfig檢視。HWADDR網路卡地址,隨意修改下,保證在你的網段內不重複即可。UUID也是和HWADDR一樣修改。

IP地址修改成你自己覺得合適的IP,最好參考你當前物理機器的相關配置。GATEWAY閘道器地址要參考你物理機器的閘道器地址,如果你的虛擬機器使用的是橋接模式的網路連線,這裡就需要設定,要不然網路就連線不上。

重啟網路服務:

service network restart

稍等片刻,ssh重新連線,然後ifconfig看下網路相關引數是否正確,最後再ping一下外部網址和你當前物理機器的IP,保證網路都是通暢的。

最後我們需要修改下linux的系統時間,這是為了防止伺服器時間不一致,導致很多細微的問題,比如,es叢集master選舉的時間戳問題、log4j輸出的日誌的記錄問題等等。在分散式系統中,時鐘非常重要。

date -s '20161008 20:47:00'

時區的話如果你需要也可以設定,這裡暫時不需要。

根據你自己的需要,你clone幾臺機器。按照預設的方式我們大概約定為,192.168.0.10、192.168.0.20、192.168.0.30,這三臺機器將組成一個es分散式叢集。

3.配置

叢集的各個節點我們已經準備好了,我們接下來準備配置叢集,讓這三個節點可以連線在一起。這裡涉及的配置比較簡單,只是完成叢集的一個基本常用功能,如有特殊的需求可以自行檢視elasticsearch官網或者百度,這方面的資料已經很豐富了。

這裡的一些配置我們其實已經受益於elasticsearch servicewrapper簡化了很多。

從這裡開始,我們將對三臺機器進行配置,192.168.160.10、192.168.160.20、192.168.160.30。

3.1.elasticsearch.yml配置

在elasticsearch的config目錄下都是配置檔案。導航到 cd /usr/share/elasticsearch/config目錄。

3.1.1.IP訪問限制、預設埠修改9200

這裡有兩個需要提醒下,第一個就是IP訪問限制,第二個就是es例項的預設埠號9200。IP訪問限制可以限定具體的IP訪問伺服器,這有一定的安全過濾作用。

# Set the bind address to a specific IP (IPv4 or IPv6): 

network.host: 0.0.0.0

如果設定成0.0.0.0則是不限制任何IP訪問。一般在生產的伺服器可能會限定幾臺IP,通常用於管理使用。

預設的埠9200在一般情況下也有點風險,可以將預設的埠修改成另外一個,這還有一個原因就是怕開發人員誤操作,連線上叢集。當然,如果你的公司網路隔離做的很好也無所謂。


# Set a custom port for HTTP: 

http.port: 9200 
transport.tcp.port: 9300

這裡的9300是叢集內部通訊使用的埠,這個也可以修改掉。因為連線叢集的方式有兩種,通過扮演叢集node也是可以進入叢集的,所以還是安全起見,修改掉預設的埠。

(備註:記得修改三個節點的相同配置,要不然節點之間無法建立連線工作,也會報錯。)

3.1.2.叢集發現IP列表、node、cluster名稱

緊接著修改叢集節點IP地址,這樣可以讓叢集在規定的幾個節點之間工作。elasticsearch,預設是使用自動發現IP機制。就是在當前網段內,只要能被自動感知到的IP就能自動加入到叢集中。這有好處也有壞處。好處就是自動化了,當你的es叢集需要雲化的時候就會非常方便。但是也會帶來一些不穩定的情況,如,master的選舉問題、資料複製問題。

導致master選舉的因素之一就是叢集有節點進入。當資料複製發生的時候也會影響叢集,因為要做資料平衡複製和冗餘。這裡面可以獨立master叢集,剔除master叢集的資料節點能力。

固定列表的IP發現有兩種配置方式,一種是互相依賴發現,一種是全量發現。各有優勢吧,我是使用的依賴發現來做的。這有個很重要的參考標準,就是你的叢集擴充套件速度有多快。因為這有個問題就是,當全量發現的時候,如果是初始化叢集會有很大的問題,就是master全域性會很長,然後節點之間的啟動速度各不一樣。所以我採用了靠譜點的依賴發現。

你需要在192.168.0.20的elasticsearch中配置成:

# --------------------------------- Discovery ---------------------------------- 

# Pass an initial list of hosts to perform discovery when new node is started: 
# The default list of hosts is ["127.0.0.1", "[::1]"] 

discovery.zen.ping.unicast.hosts: [ "192.168.0.10:9300" ]

讓他去發現10的機器,以此內推,完成剩下的30的配置。

(備註:網上有很多針對不同場景的發現配置,大家可以就此拋磚引玉,對這個主題感興趣的可以百度很多資料的。)

然後你需要配置下叢集名稱,就是你當前節點所在叢集的名稱,這有助於你規劃你的叢集。只有叢集名稱一樣才能組成一個邏輯叢集。

# ---------------------------------- Cluster ----------------------------------- 

# Use a descriptive name for your cluster: 

cluster.name: orderSearch_cluster 

# ------------------------------------ Node ------------------------------------ 

# Use a descriptive name for the node: 

node.name: node-2

以此類推,完成另外兩個節點的配置。cluster.name的名稱必須保持一樣。然後分別設定node.name。

3.1.3.master node 啟動切換

這裡有一個小小的經驗分享下,就是我在使用叢集的時候,因為我是虛擬化出來的機器所以經常會關閉和重啟叢集。有時候發現叢集master宣酒會有一個問題就是,如果你的叢集關閉的方式不對,會直接影響下個master選舉的邏輯。

我查了下選舉的大概邏輯,它會根據分片的資料的前後新鮮程度來作為選舉的一個重要邏輯。(日誌、資料、時間都會作為叢集master全域性的重要指標)

因為考慮到資料一致性問題,當然是用最新的資料節點作為master,然後進行新資料的複製和重新整理其他node。

如果你發現有一個節點遲遲進不了叢集,可以嘗試重啟下es服務,讓叢集master重新全域性。

3.2.linux 開啟最大檔案數設定(用作index時候的系統閥值)

在linux系統中,要想使用最大化的系統資源需要向作業系統去申請。由於elasticsearch需要在index的時候用到大量的檔案控制程式碼資源,在原來linux預設的資源下可能會不夠用。所以這裡就需要我們在使用的時候事先設定好。

這個配置在《ElasticSearch 可擴充套件的開源彈性搜尋解決方案》一書中作為重點配置介紹,可想而知還是有不少人踩到過的坑。

這個配置在elasticsearch service wrapper中幫我們配置好了。

vim /etc/init.d/elasticsearch

42

這個配置會被啟動的時候設定到es例項中去。

這個時候試著重啟三臺機器的es例項,看能不能在_plugin/head中檢視到三臺機器的叢集狀態。(記得訪問安裝了head外掛的那臺機器,我這裡是在10機器上安裝的)

43

紅色的就是你設定的node.name節點名稱,他們在一個叢集裡工作。

3.3.安裝中文分詞器ik(注意對應版本問題)

此時叢集應該可以工作了,我們還需要配置中文分詞器,畢竟我們使用的中文,elasticsearch的自帶的分詞器對中文分詞支援的不太適合本土。

我是使用的ik分詞器,在github上的地址:https://github.com/medcl/elasticsearch-analysis-ik

先別急的clone,我們先來看下ik分詞器所支援的elasticsearch對應的版本。

44

我們使用的elasticsearch版本為2.3.4。所以我們要找對應的ik版本,要不然啟動的時候就直接報載入不了對應版本的ik外掛。切換到release版本列表,找到對應的版本然後下載下來。

45

你可以直接下載到Linux機器上,也可以下載到你的宿主機器上然後複製到虛擬機器上。如果你的elasticsearch版本是最新的,你可能就需要下載ik原始碼下來編譯之後再部署。

當然你可以使用git+maven的方式安裝,詳細的安裝步驟可以參見:https://github.com/medcl/elasticsearch-analysis-ik

46

這也比較簡單,我這裡就不重複了。安裝好之後重啟es例項。

3.4.elasticsearch叢集規劃(master儘量不要作為data節點,獨立master為commander)

可以這樣規劃一個叢集。master可以兩臺,這兩個節點都是作為commander統籌叢集層面的事務,取消這兩臺的data權利。然後在規劃出三個節點的data叢集,取消這三個節點的master權利。讓他們安心的做好資料儲存和檢索服務。這是最小的粒度叢集結構,可以基於這個結構進行擴充套件。

這樣做有一個好處,就是職責分明,可以最大限度的防止master節點有事data節點,導致不穩定因素髮生。比如,data節點的資料複製,資料平衡,路由等等,直接影響master的穩定性。進而可能會發生腦裂問題。

4.開發

我們進入最後一個環節,所有的東西都準備好了,我們是不是應該操作操作這個強大的搜尋引擎了。come on。

4.1.接入叢集方式

說到叢集,就會有相應的問題隨之而來,高可用、高併發、大資料、橫向擴充套件等等。那麼elasticsearh的叢集大概是個什麼原理。

首先client的在接入叢集的時候為了保證高可用不是採用 vip漂移實現高可用,類似keepalived 這種。elasticserach在客戶端連線的時候使用配置多個IP的方式來首先客戶端sdk的負載。這已經是分散式系統常見的做法了。只有類似DB、cache這樣中心化的叢集需要使用,以為是它們的使用特點決定了。(資料一致性)

elasticsearch的所有節點都可以處理請求,節點越多併發QPS越高,相應的TPS會下降,但是下降的效能不是根據節點的正比例來的。(它使用quorum(法定人數)演算法,保證可用性。)所以節點的複製不是我們想當然的那樣。

連線es叢集的方式有兩種,效能高點的就是直接將client扮演成cluster node進去叢集,同時取消自己的data權利。這通常都是用來做二次開發用的,你可以github clone下來原始碼新增自己的場景然後進入叢集,可能你會干預選舉,也可能會干預sharding,也可能會干預叢集平衡。

elasticsearch 使用自己定義的一套DSL語言,使用restful方式使用,根據不同的rest end point來使用。比如,_search、_cat、_query等等。這些都是指點的rest端點。然後你可以post dsl到elasticsearch伺服器處理。

elasticsearch search dsl:https://www.elastic.co/guide/en/elasticsearch/reference/current/search.html

elasticsearch dsl api:http://elasticsearch-dsl.readthedocs.io/en/latest/

例:

POST _search 

"query": { 
        "bool" : { 
            "must" : { 
                "query_string" : { 
                    "query" : "query some test" 
                } 
            }, 
            "filter" : { 
                "term" : { "user" : "plen" } 
            } 
        } 
    } 
}

可讀性很強,在通過chrome外掛Sense輔助編寫,會比較方便。

47

但是一般都不會這麼做,一般都是使用sdk連線叢集。直接使用dsl的大多是在測試資料的時候或者在除錯的時候。看sdk輸出的dsl是否正確。就跟除錯SQL差不多。

4.1.1.net nest使用(使用pool連線es叢集)

.NET程式有開源包nest,直接在Nuget上搜尋安裝即可。

48

官網地址:https://www.elastic.co/guide/en/elasticsearch/client/net-api/1.x/nest-connecting.html

使用pool高可用的方式連線叢集。

var node1 = new Uri("http://192.168.0.10:9200"); 
var node2 = new Uri("http://192.168.0.20:9200"); 
var node3 = new Uri("http://192.168.0.30:9200");

var connectionPool = new SniffingConnectionPool(new[] { node1, node2, node3 });

var settings = new ConnectionSettings(connectionPool);

var client = new ElasticClient(settings);

此時使用client物件就是軟負載的,它會根據一定的策略來均衡的連線後臺三個node。(可能是平均的、可能是權重的,具體沒研究)

4.1.2.java jest使用

java 的話我是使用jest。我們建立一個maven專案,然後新增jest 相應的jar包maven引用。

<dependencies>
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>2.3.5</version>
</dependency>
</dependencies>
 
JestClientFactory factory = new JestClientFactory();

List<String> nodes = new LinkedList<String>();
nodes.add("http://192.168.0.10:9200");
nodes.add("http://192.168.0.20:9200");
nodes.add("http://192.168.0.30:9200");

HttpClientConfig config = new HttpClientConfig.Builder(nodes).multiThreaded(true).build();
factory.setHttpClientConfig(config);
JestHttpClient client = (JestHttpClient) factory.getObject();

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.queryStringQuery("中華人名共和國"));
searchSourceBuilder.field("name");

Search search = new Search.Builder(searchSourceBuilder.toString()).build();

JestResult rs = client.execute(search);
System.out.println(rs.getJsonString());
 
 


  "took": 71, 
  "timed_out": false, 
  "_shards": { 
    "total": 45, 
    "successful": 45, 
    "failed": 0 
  }, 
  "hits": { 
    "total": 6, 
    "max_score": 0.6614378, 
    "hits": [ 
      { 
        "_index": "posts", 
        "_type": "post", 
        "_id": "1", 
        "_score": 0.6614378, 
        "fields": { 
          "name": [ 
            "王清培" 
          ] 
        } 
      }, 
      { 
        "_index": "posts", 
        "_type": "post", 
        "_id": "5", 
        "_score": 0.57875806, 
        "fields": { 
          "name": [ 
            "王清培" 
          ] 
        } 
      }, 
      { 
        "_index": "posts", 
        "_type": "post", 
        "_id": "2", 
        "_score": 0.57875806, 
        "fields": { 
          "name": [ 
            "王清培" 
          ] 
        } 
      }, 
      { 
        "_index": "posts", 
        "_type": "post", 
        "_id": "AVaKENIckgl39nrAi9V5", 
        "_score": 0.57875806, 
        "fields": { 
          "name": [ 
            "王清培" 
          ] 
        } 
      }, 
      { 
        "_index": "class", 
        "_type": "student", 
        "_id": "1", 
        "_score": 0.17759356 
      }, 
      { 
        "_index": "posts", 
        "_type": "post", 
        "_id": "3", 
        "_score": 0.17759356, 
        "fields": { 
          "name": [ 
            "王清培" 
          ] 
        } 
      } 
    ] 
  } 
}

返回的資料橫跨多個索引。你可以通過不斷的debug來檢視連結IP是不是會啟動切換,是不是會起到可用性的作用。

4.2.index開發

索引開發一般步驟比較簡單,首先建立對應的mapping對映,配置好各個type中的field的特性。

4.2.1.mapping 配置

mapping是es例項用來在index的時候,作為各個欄位的操作依據。比如,username,這個欄位是否要索引、是否要儲存、長度大小等等。雖然elasticsearch可以動態的處理這些,但是出於管理和運維的目的還是建議建立對應的索引對映,這個對映可以儲存在檔案裡,以便將來重建索引用。

POST /demoindex 

   "mappings": { 
      "demotype": { 
         "properties": { 
            "contents": { 
               "type": "string", 
               "index": "analyzed" 
            }, 
            "name": { 
               "store": true, 
               "type": "string", 
               "index": "analyzed" 
            }, 
            "id": { 
               "store": true, 
               "type": "long" 
            }, 
            "userId": { 
               "store": true, 
               "type": "long" 
            } 
         } 
      } 
   } 
}

這是一個最簡單的mapping,定義了索引名稱為demoindex,型別為demotype的mapping。各個欄位分別是一個json物件,裡面有型別有索引是否需要。

這個在sense裡編輯,然後直接post提交。


   "acknowledged": true 
}

50

通過檢視建立好的索引資訊確認是否是你提交的mapping設定。

4.2.2.mapping template配置

每次都通過手動的建立類似的mapping始終是個低效率的事情,elasticserach支援建立mapping模板,然後讓模板自動匹配使用哪個mapping定義。

PUT log_template 

   "order": 10, 
   "template": "log_*", 
   "settings": { 
      "index": { 
         "number_of_replicas": "2", 
         "number_of_shards": "5" 
      } 
   }, 
   "mappings": { 
      "_default_": { 
         "_source_": { 
            "enable": false 
         } 
      } 
   } 
}

建立一個log型別的索引mapping。我們設定了兩個基本的屬性, "number_of_replicas": "2" 複製分數, "number_of_shards": "5" 分片個數。mappings裡面設定了source欄位預設不開啟。

當我們提交所有以“log_xxx”名字格式的索引時將自動命中這個mapping模板。

可以通過_template rest端點檢視已經存在的mapping模板,或者通過head外掛的右上角的”資訊”裡面的”模板”選單檢視。

{
  "mq_template" : {
    "order" : 10,
    "template" : "mq*",
    "settings" : {
      "index" : {
        "number_of_shards" : "5",
        "number_of_replicas" : "2"
      }
    },
    "mappings" : {
      "_default_" : {
        "_source_" : {
          "enable" : false
        }
      }
    },
    "aliases" : { }
  },
  "log_template" : {
    "order" : 10,
    "template" : "log_*",
    "settings" : {
      "index" : {
        "number_of_shards" : "5",
        "number_of_replicas" : "2"
      }
    },
    "mappings" : {
      "_default_" : {
        "_source_" : {
          "enable" : false
        }
      }
    },
    "aliases" : { }
  },
  "error_template" : {
    "order" : 10,
    "template" : "error_*",
    "settings" : {
      "index" : {
        "number_of_shards" : "5",
        "number_of_replicas" : "2"
      }
    },
    "mappings" : {
      "_default_" : {
        "_source_" : {
          "enable" : false
        }
      }
    },
    "aliases" : { }
  }
}
這通常用於一些業務不想關的儲存中,比如日誌、訊息、重大錯誤預警等等都可以設定,只要這些重複的mapping是有規律的。

4.2.3.index routing索引路由配置

在es對資料進行分片的時候是採用hash取餘的方式進行的,所以你可以傳遞一個固定的key,那麼這個key將作為你固定的路由規則。在建立mappings的時候可以設定這個_routing引數。這在1.0的版本中是這樣的設定的,也就是說你當前type下的所有document都是隻能用著這個路由key進行。但是在es2.0之後routing跟著index後設資料走,這樣可以控制單個index的路由規則,在提交index的時候可以單獨制定_routing引數,而不是直接設定mappings上。

在2.0之後已經不再支援mappings配置_routing引數了。

https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking_20_mapping_changes.html#migration-meta-fields

在1.0裡,比如,你可以將userid作為routing key,這樣就可以將當前使用者的所有資料都在一個分片上,當查詢的時候就會加快查詢速度。


  "mappings": { 
    "post": { 
      "_routing": { 
        "required": true, 
        "path":"userid" 
      }, 
      "properties": { 
        "contents": { 
          "type": "string" 
        }, 
        "name": { 
          "store": true, 
          "type": "string" 
        }, 
        "id": { 
          "store": true, 
          "type": "long" 
        }, 
        "userId": { 
          "store": true, 
          "type": "long" 
        } 
      } 
    } 
  } 
}

這個_routing是設定在mapping上的,作用於所有type。會使用userid作為sharding的key。但是在2.0裡,是必須明確指定routing path的。

51

在你新增好mappings之後,建立當前索引的時候必須指定&routing=xxx,引數。這有個很大的好處就是你可以根據不同的業務維度自由調整分片策略。

5.總結

孰能生巧,分散式的東西還是有很多比較特殊和挑戰的地方,尤其是他的分佈性,同時還要解決很多一致性問題、可用性問題等等。我對elasticsearch的使用也只是個簡單的皮毛而已,它的分散式特性深深的吸引了我,期待下篇文章更加深入的分享。比如,routing的內部原理,複製平衡演算法等等。這篇文章是我對elasticsearch使用的一個簡單的總結,希望能對各位博友有點幫助,謝謝閱讀,謝謝支援。

參考書籍《ElasticSearch 可擴充套件的開源彈性搜尋解決方案》、《ElastcSearch權威指南》。

相關文章