使用ElasticSearch將近3個(gè)月了,在使用過程中丛忆,陸陸續(xù)續(xù)踩了不少坑,每次覺得無法逾越時(shí)仍秤,心里都想放棄熄诡,一是因?yàn)檫@東西要完全掌握不是那么容易,需要花很多時(shí)間诗力;二是如果繼續(xù)使用曾經(jīng)用過的zabbix凰浮,說不定可以很快滿足眼前的需求,從而可以抽身做其他事情苇本。但堅(jiān)持下來袜茧,就一定能從坑里爬起來,從而對(duì)這個(gè)系統(tǒng)更加了解瓣窄,并利用這頭”猛獸”幫助我做更多事情笛厦。原因很簡(jiǎn)單,ElasticSearch除了是一個(gè)分布式數(shù)據(jù)庫俺夕,還是一個(gè)擴(kuò)展性和可用性都很強(qiáng)的近實(shí)時(shí)搜索引擎裳凸。
目前為止,踩過以下幾個(gè)坑:
- 集群搭建不成功
- 未使用內(nèi)網(wǎng)IP劝贸,導(dǎo)致恢復(fù)緩慢
- 未使用隊(duì)列及l(fā)ogstash姨谷,導(dǎo)致數(shù)據(jù)丟失
- Master和DataNode未分離,導(dǎo)致集群不穩(wěn)定
- Logstash吞吐量問題
- Logstash如何創(chuàng)建Mapping
- head插件安裝錯(cuò)誤
犯了這么多錯(cuò)誤基本上都是使用不當(dāng)映九、以偏概全的原因菠秒,以為看了一點(diǎn)文檔,就憑直覺可以猜測(cè)到系統(tǒng)的所有內(nèi)容氯迂,造成了后續(xù)問題的不斷涌現(xiàn),下面就逐一說一下淌坑過程
集群搭建不成功
一開始是在單機(jī)上玩ElasticSearch的言缤,上生產(chǎn)環(huán)境肯定要使用它的集群功能嚼蚀,但文檔說只需要在elasticsearch.yml
中設(shè)置cluster.name
和node.name
即可,ElasticSearch節(jié)點(diǎn)啟動(dòng)時(shí)會(huì)自動(dòng)發(fā)現(xiàn)集群并加入到集群管挟,但全部設(shè)置完畢后轿曙,竟無法使各個(gè)節(jié)點(diǎn)組成集群,最后發(fā)現(xiàn)這種方法只在一臺(tái)機(jī)器上有效,而要組成集群导帝,需要在每臺(tái)節(jié)點(diǎn)做以下配置:
discovery.zen.ping.unicast.hosts: ["Node1_IP:9300", "Node2_IP:9300", "Node3_IP:9300"]
ElasticSearch一般會(huì)開兩個(gè)端口守谓,一個(gè)是集群維護(hù)端口,如上面的9300; 一個(gè)是對(duì)外提供的端口您单,默認(rèn)是9200斋荞。
未使用內(nèi)網(wǎng)IP,導(dǎo)致恢復(fù)緩慢
在部署集群時(shí)虐秦,我挑選了幾臺(tái)配置相近的同網(wǎng)段機(jī)器平酿,但當(dāng)時(shí)其中一臺(tái)機(jī)器操作系統(tǒng)沒有加載內(nèi)網(wǎng)網(wǎng)卡,為了偷一下懶悦陋,便直接使用了外網(wǎng)IP蜈彼,集群是跑起來了,運(yùn)行了一段時(shí)間也沒有什么問題俺驶,但隨著流量越來也大幸逆,終于有一天Master突然down掉了,我當(dāng)時(shí)心想暮现,ElasticSearch集群本身具有故障轉(zhuǎn)移功能还绘,馬上會(huì)分配一個(gè)Master節(jié)點(diǎn),然后我只需要把原先的Master節(jié)點(diǎn)重啟即可送矩,然而重啟了之后蚕甥,通過head頁面查看恢復(fù)情況,發(fā)現(xiàn)集群長時(shí)間處于黃色狀態(tài)(有replica shard丟失)栋荸,而丟失的shard一直處于未分配狀態(tài)菇怀,并沒有如我預(yù)期的:?jiǎn)?dòng)后,該節(jié)點(diǎn)可以重用在磁盤上的shard數(shù)據(jù)晌块,上報(bào)給Master爱沟,不需要數(shù)據(jù)拷貝,立馬恢復(fù)為綠色狀態(tài)匆背。過了幾分鐘后呼伸,我發(fā)現(xiàn)恢復(fù)的shard數(shù)正以緩慢的速度增加,便推導(dǎo)出這樣的錯(cuò)誤結(jié)論:ElasticSearch在某一臺(tái)機(jī)器掛掉后钝尸,只會(huì)從primary shard復(fù)制數(shù)據(jù)括享,即便節(jié)點(diǎn)迅速恢復(fù),也不會(huì)復(fù)用該節(jié)點(diǎn)上的數(shù)據(jù)珍促,如果是這種實(shí)現(xiàn)方式铃辖,我認(rèn)為這種恢復(fù)速度是無法接受的,頓時(shí)產(chǎn)生了無法繼續(xù)使用下去的念頭猪叙,當(dāng)時(shí)的心情是無比失落的娇斩。
而ElasticSearch的使用是相當(dāng)廣泛的仁卷,我們熟知的世界最大同性交友網(wǎng)站也是使用它來實(shí)現(xiàn)搜索功能的,所以可以斷定是我的使用方法有問題犬第,要么是我選的版本不穩(wěn)定锦积,要么是其他的原因,而穩(wěn)定版一般出問題的幾率不大歉嗓,因此在換版本之前丰介,需要找其他方面的原因,很久之前看過一篇google的slide遥椿,上面有一頁介紹了不同介質(zhì)數(shù)據(jù)的傳輸速度:外網(wǎng)的傳輸速度在10ms級(jí)別基矮,而內(nèi)網(wǎng)卻在20微秒級(jí),這種速度的差異便會(huì)造成以下幾個(gè)方面的影響
- 集群無法提供正常服務(wù):因?yàn)槊總€(gè)請(qǐng)求冠场,ElasticSearch節(jié)點(diǎn)都會(huì)經(jīng)過轉(zhuǎn)發(fā)和收集兩個(gè)過程家浇,如果使用外網(wǎng)網(wǎng)卡,便會(huì)造成延遲大碴裙,訪問量上不去钢悲,而流量到達(dá)一定程度后,集群很快便無法提供正常服務(wù)
- 由于ES集群已經(jīng)無法正常服務(wù)舔株,所以down機(jī)莺琳、恢復(fù)困難一系列綜合癥的情況便會(huì)陸續(xù)發(fā)生
后續(xù)我將集群切到了內(nèi)網(wǎng)中,再測(cè)試重啟某一個(gè)節(jié)點(diǎn)载慈,便不會(huì)再出現(xiàn)恢復(fù)一個(gè)節(jié)點(diǎn)需要半天的情況了惭等。
未使用隊(duì)列或logstash,導(dǎo)致數(shù)據(jù)丟失
最初用到的架構(gòu)非常簡(jiǎn)單: 使用ES(ElasticSearch縮寫)集群作為存儲(chǔ)办铡,beats和rsyslog作為shipper向ES集群發(fā)送數(shù)據(jù)辞做,使用這種架構(gòu)的主要原因是配置簡(jiǎn)單,ES本身是一個(gè)高可用集群寡具,直接把數(shù)據(jù)發(fā)過去就好秤茅。而自己心里還產(chǎn)生了為什么會(huì)有ELK架構(gòu),感覺Logstash是多余的想法童叠,在發(fā)生了幾次down機(jī)之后框喳,才發(fā)現(xiàn)之前的想法很傻很天真,之前的架構(gòu)也有明顯的問題
- 在某一個(gè)節(jié)點(diǎn)down掉后厦坛,如果不馬上恢復(fù)五垮,在不了解beats負(fù)載均衡機(jī)制的前提之下,很難判斷數(shù)據(jù)還會(huì)不會(huì)發(fā)送給down掉的節(jié)點(diǎn)杜秸,而新增一個(gè)節(jié)點(diǎn)拼余,需要修改所有beat的配置,即這里至少要使用一個(gè)負(fù)載均衡器給所有ES節(jié)點(diǎn)做負(fù)載均衡
- ES是一個(gè)高可用集群亩歹,但目前還沒有足夠的使用經(jīng)驗(yàn)匙监,所以可能今后還會(huì)出現(xiàn)集群故障的問題,而出故障小作,很可能造成數(shù)據(jù)的丟失亭姥,為了避免這種情況發(fā)生,需要在beats和ES集群之間構(gòu)建一套可持久化的隊(duì)列顾稀,最簡(jiǎn)單的隊(duì)列是redis达罗,而logstash放在redis兩邊分別作為生產(chǎn)者和消費(fèi)者。想到的方案便是
beats->logstash->redis->logstash->ES
静秆,這樣便解決了丟數(shù)據(jù)的問題粮揉,當(dāng)然最新版的logstash可以將數(shù)據(jù)持久化到磁盤上,也許可以對(duì)此模型進(jìn)行簡(jiǎn)化
Logstash和Redis的使用都非常簡(jiǎn)單抚笔,這里就不一一介紹扶认,值得注意的是,如果要使用redis做持久化殊橙,需要使用Redis的List的方式辐宾,而不是Sub-Pub的方式,以下是具體的架構(gòu)圖膨蛮,箭頭的方向是數(shù)據(jù)流動(dòng)的方向叠纹。
Master和DataNode未分離,導(dǎo)致集群不穩(wěn)定
在ES集群中敞葛,節(jié)點(diǎn)分為Master誉察、DataNode、Client等幾種角色惹谐,任何一個(gè)節(jié)點(diǎn)都可以同時(shí)具備以上所有角色持偏,其中比較重要的角色為Master和DataNode:
- Master主要管理集群信息、primary分片和replica分片信息豺鼻、維護(hù)index信息综液。
- DataNode用來存儲(chǔ)數(shù)據(jù),維護(hù)倒排索引儒飒,提供數(shù)據(jù)檢索等谬莹。
可以看到元信息都在Master上面,如果Master掛掉了桩了,該Master含有的所有Index都無法訪問附帽,文檔中說,為了保證Master穩(wěn)定井誉,需要將Master和Node分離蕉扮。而構(gòu)建master集群可能會(huì)產(chǎn)生一種叫做腦裂的問題,為了防止腦裂颗圣,需要設(shè)置最小master的節(jié)點(diǎn)數(shù)為eligible_master_number/2 + 1
腦裂的概念:
如果你有2個(gè)Master候選節(jié)點(diǎn)喳钟,并設(shè)置最小Master節(jié)點(diǎn)數(shù)為1屁使,則當(dāng)網(wǎng)絡(luò)抖動(dòng)或偶然斷開時(shí),2個(gè)Master都會(huì)認(rèn)為另一個(gè)Master掛掉了奔则,他們都被選舉為主Master蛮寂,則此時(shí)集群中存在兩個(gè)主Master,即物理上1個(gè)集群變成了邏輯上的2個(gè)集群易茬,而當(dāng)其中一個(gè)Master再次掛掉時(shí)酬蹋,即便它恢復(fù)后回到了原有的集群,在它作為主Master期間寫入的數(shù)據(jù)都會(huì)丟失抽莱,因?yàn)樗厦婢S護(hù)了Index信息范抓。
根據(jù)以上理論,我對(duì)集群做了如下更改食铐,額外選取3個(gè)獨(dú)立的機(jī)器作為Master節(jié)點(diǎn)匕垫,修改elasticsearch.yml配置
node.master = true
node.data = false
discovery.zen.minimum_master_nodes = 2
修改其他節(jié)點(diǎn)配置,將其設(shè)置為DataNode璃岳,最后挨個(gè)重啟
node.master = false
node.data = true
Logstash吞吐量問題
在使用了新的架構(gòu)后年缎,我發(fā)現(xiàn)了當(dāng)流量上來后,Redis的隊(duì)列會(huì)持續(xù)增長铃慷,消費(fèi)速度跟不上生產(chǎn)速度单芜,造成的問題是數(shù)據(jù)在Redis中堆積,圖表展示有大量的延遲犁柜。解決這個(gè)問題有以下幾個(gè)思路
- 可能是ES插入速度太慢洲鸠,需要調(diào)整參數(shù)提升插入性能
- 可能是Logstash吞吐量低,需要增加每次向Redis拿數(shù)據(jù)的緩存馋缅、增加向ES輸出的緩存扒腕、增加線程數(shù)、增加每次批量操作的
content length
等
對(duì)于ES調(diào)優(yōu)中萤悴,我調(diào)整了線程數(shù)瘾腰,增加線程隊(duì)列,增大shard數(shù)覆履,但都沒有解決問題蹋盆。
而Logstash調(diào)優(yōu),我首先調(diào)整了LS_HEAP_SIZE
參數(shù)硝全,讓Logstash可以同時(shí)處理大量的數(shù)據(jù)栖雾,然后主要專注在調(diào)整Logstash的Input和Output插件參數(shù)上,插件中可以設(shè)置線程數(shù)伟众、batch_count
數(shù)值等析藕,而當(dāng)我將Redis插件參數(shù)改為batch_count=>10000
后,發(fā)現(xiàn)隊(duì)列不再一直增長了凳厢,它會(huì)漲到一定程度后账胧,瞬間減少到2-3位數(shù)竞慢,即隊(duì)列的長度在一定范圍內(nèi)浮動(dòng),當(dāng)時(shí)欣喜若狂治泥,以為自己解決了梗顺,但跑了大概5個(gè)小時(shí)候,發(fā)現(xiàn)隊(duì)列又開始不斷增長了车摄,問題并沒有得到解決。而產(chǎn)生解決了的假象應(yīng)該是我增加了Logstash內(nèi)存的原因仑鸥,數(shù)據(jù)只是先把Logstash內(nèi)存填滿吮播,再開始填隊(duì)列,而填滿Logstash內(nèi)存花了幾個(gè)小時(shí)眼俊,關(guān)鍵的Logstash到ES的吞吐量還是沒有上去意狠,在access日志中,無論如何也無法讓bulk API的content length
增加疮胖,如下圖中的長度一直維持在2K左右环戈。
最后,我采用了替換Logstash版本的策略澎灸,更新了時(shí)下最新的5.1.1版本院塞,由于新版的配置和舊版配置不一樣,所以認(rèn)真研究了一下配置性昭,在這個(gè)過程中拦止,我發(fā)現(xiàn)了一個(gè)-b
參數(shù)可以修改批量插入的大小,也許就是我需要的糜颠。果然汹族,將這個(gè)參數(shù)由默認(rèn)的125改為了1000,順利的解決了這個(gè)難題其兴,同時(shí)也證明了并不是版本問題顶瞒,還是使用問題,而這個(gè)參數(shù)也正是修改content length
的方法元旬,順便說一下榴徐,如果你使用nginx作為負(fù)載均衡器,你需要同時(shí)增加client_max_body_size
參數(shù)法绵,避免產(chǎn)生content length
過大而返回413錯(cuò)誤碼箕速。
Logstash如何創(chuàng)建Mapping
當(dāng)使用Logstash進(jìn)行轉(zhuǎn)發(fā)時(shí),有可能你的數(shù)據(jù)都在一個(gè)Index中朋譬,當(dāng)然你也可以設(shè)置不同的Index盐茎,這篇文章中就有根據(jù)type來劃分Index的方法,不管劃不劃分Index徙赢,都會(huì)默認(rèn)生成一個(gè)或多個(gè)mapping結(jié)構(gòu)字柠,mapping結(jié)和不同的type即對(duì)應(yīng)MySQL中的數(shù)據(jù)庫和表結(jié)構(gòu)信息探越,當(dāng)然我這里不是為了說明它們的區(qū)別,而是我們無法自定義字段的類型窑业。
這會(huì)產(chǎn)生各種各樣的問題钦幔,比如它會(huì)默認(rèn)產(chǎn)生analyzed類型的string字段,會(huì)自動(dòng)將帶有連接符的字符串分為兩個(gè)字符串輸出常柄,即"idc-1"這樣的字符串會(huì)輸出為"idc"和"1"鲤氢,這并不是我想要的,讓我相當(dāng)困擾西潘,而Mapping在生成后是無法修改字段的卷玉,除非你換一個(gè)新的字段。
解決這個(gè)問題的方法并不在mapping上喷市,而我卻花了很多時(shí)間在這個(gè)上面相种,最終答案卻是使用template,在template中可以定義你需要的mapping品姓,這樣便解決以上問題寝并。到此,我還是不能完全理解里面的機(jī)制腹备,以后抽空了解后再補(bǔ)上衬潦。
head插件安裝失敗
上文有介紹head插件,它是一個(gè)可以顯示集群狀態(tài)及操作ES集群的UI馏谨,可以取代官方的X-Pack别渔,后者只有30天的試用期,因?yàn)閯?chuàng)業(yè)公司惧互,能用免費(fèi)的盡量采用免費(fèi)的哎媚。在集群中,有幾個(gè)節(jié)點(diǎn)安裝該插件會(huì)失敗喊儡,提示:Unable to veryfy checksum for download plugin ...
拨与,google上查了一圈仍然沒有找到解決辦法,最后試著手動(dòng)將該插件下載然后解壓到/usr/share/elasticsearch/plugins/
目錄下艾猜,并將目錄改為head
即可解決該問題买喧。
以上問題是我這段時(shí)間來碰到的坑,每個(gè)都花了不少時(shí)間去解決匆赃,自己也比較幸運(yùn)淤毛,花在上面的時(shí)間沒有白費(fèi)。因?yàn)閭€(gè)人覺得這個(gè)技術(shù)棧實(shí)在是比較好算柳,而資料主要以英文的為主低淡,把自己的經(jīng)歷寫下來,希望今后不再犯同樣的錯(cuò)誤,也希望可以幫助其他使用該技術(shù)的同學(xué)蔗蹋。