1. 程式人生 > >ElasticSearch大數據分布式彈性搜索引擎使用

ElasticSearch大數據分布式彈性搜索引擎使用

幫我 127.0.0.1 term github上 層次 tab 多個 elf 業務

閱讀目錄:

  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*

技術分享圖片

如果已經存在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

技術分享圖片

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

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

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

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

技術分享圖片

找到你對應的系統類型文件,當然如果你是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

最後需要設置下剛才我們添加的文件的執行權限。要不然你的文件名字應該是白色的,是不允許被執行。

技術分享圖片

cd ..

chmod –R u+x config/

技術分享圖片

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

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

技術分享圖片

2.2.配置elasticsearch專屬賬戶和組

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

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

查看下組:

cat /etc/group

技術分享圖片

查看下用戶:

cat /etc/passwd

技術分享圖片

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

如果你系統裏沒有自動創建對應的組和賬號,你就動手自己創建,如下:

創建組:

groupadd elasticsearch_group

技術分享圖片

創建用戶:

useradd elasticsearch_user -g elasticsearch_group -s /sbin/nologin

技術分享圖片

註意:此賬戶是不具有登錄權限的。它的shell是在/sbin/nologin。

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

2.3.設置elasticsearch文件所有者

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

導航到elasticsearch上級目錄:

cd /usr/share

ll

技術分享圖片

chown -R elasticsearch:elasticsearch elasticsearch/

技術分享圖片

此時,你的elasticsearch文件的owner是elasticsearch。

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

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

su elasticsearch

cd /usr/share/elasticsearch/bin

./elasticsearch

技術分享圖片

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

netstat –tnl

技術分享圖片

繼續查看下HTTP服務是否啟動正常。

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

技術分享圖片

由於此時我們並沒有安裝任何輔助管理工具,如,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

技術分享圖片

復制 git repository 地址到剪貼板,然後直接clone到本地。

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

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

然後等待clone完成。

技術分享圖片

查看下clone下來的本地倉庫文件情況。進入elasticsearchwrapper,查看當前git 分支。

cd /root/elasticsearch-servicewrapper

git branch

*master

ll

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

技術分享圖片

我們需要將service文件copy到elasticsearch/bin目錄下。

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

cd /usr/share/elasticsearch/bin/

技術分享圖片

service裏的安裝文件需要在elasticsearch/bin目錄下工作。
cd service/

ll

./elasticsearch

技術分享圖片

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

技術分享圖片

在安裝之前,我們需要暫時在前臺運行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

技術分享圖片

第一次看到這個我有點蒙,這個ElasticsearchF是個什麽對象。命名有點特殊,再進一步查看Exception的信息,其實是一個ClassNotFoundException異常。說明找不到這個ElasticSearchF類。

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

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

我們查看下service/elasticsearch.conf配置文件裏是不是有這個‘elasticsearchF’字符串。(wrapper包是使用當前目錄下的elasticsearch.conf作為配置文件使用的)

grep –i elasticsearchf elasticsearch.conf

技術分享圖片

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

技術分享圖片

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

./elasticsearch console

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

技術分享圖片

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

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

vim ./elasticsearch

esc

:/console

找下console在哪裏,然後加上調試文本信息,輸出到界面上。

技術分享圖片

再運行,查看命令參數是否有問題。

技術分享圖片

查看了下,輸出的參數基本都沒有問題。一時無解。好奇心作怪,本想再進一步看下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,有兩處需要設置,我們再看輸出信息。

技術分享圖片

是輸出了一些有用的信息,可以查看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啟動文件。

技術分享圖片

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

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

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

chkconfig --add elasticsearch

chkconfig –list

技術分享圖片

已經添加好系統自啟動服務列表中。

service elasticsearch start

啟動es實例,等待端口啟動完成,稍等片刻查看端口情況。

netstat –tnl

技術分享圖片

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

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

技術分享圖片

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給我們帶來的清晰的集群節點管理視圖。

技術分享圖片

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

安裝head插件還是比較方便的,你也可以直接copy文件的方式使用。在elasticsearch的home目錄下有一個plugins目錄,它是所有插件的目錄,所有的插件都會在這個文件夾查找和加載。

我們看下安裝head插件方法。在elasticsearch/bin 目錄下有一個plugin可執行文件,它是專門用來安裝插件用的程序。

./plugin -install mobz/elasticsearch-head

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

技術分享圖片

看到這個界面基本安裝成功了,node-1默認是master節點。

2.7.安裝chrom中的elasticsearch客戶端插件

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

技術分享圖片

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

技術分享圖片

elasticsearch toolbox 可以很方便的查詢和導出數據。

技術分享圖片

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情況)

技術分享圖片

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

http://192.168.0.20:9200/_cat/shards?v(查看shards情況)

技術分享圖片

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

技術分享圖片

你可以查看系統 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

技術分享圖片

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

這個時候試著重啟三臺機器的es實例,看能不能在_plugin/head中查看到三臺機器的集群狀態。(記得訪問安裝了head插件的那臺機器,我這裏是在10機器上安裝的)

技術分享圖片

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

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

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

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

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

技術分享圖片

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

技術分享圖片

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

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

技術分享圖片

這也比較簡單,我這裏就不重復了。安裝好之後重啟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輔助編寫,會比較方便。

技術分享圖片

但是一般都不會這麽做,一般都是使用sdk連接集群。直接使用dsl的大多是在測試數據的時候或者在調試的時候。看sdk輸出的dsl是否正確。就跟調試SQL差不多。

4.1.1.net nest使用(使用pool連接es集群)

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

技術分享圖片

官網地址: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
}

技術分享圖片

通過查看創建好的索引信息確認是否是你提交的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的。

技術分享圖片

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

5.總結

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

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

ElasticSearch大數據分布式彈性搜索引擎使用