GitHub此前的搜索使用Solr實(shí)現,新上線(xiàn)的搜索基于elasticsearch,運行在多個(gè)集群上。由于代碼搜索索引很大,GitHub專(zhuān)門(mén)為其指定了一個(gè)集群。目前該集群包括26個(gè)存儲節點(diǎn)和8個(gè)客戶(hù)端節點(diǎn)。存儲節點(diǎn)負責保存構成搜索索引的數據,而客戶(hù)端節點(diǎn)負責協(xié)調查詢(xún)活動(dòng)。每個(gè)搜索節點(diǎn)中有2TB的SSD存儲。
發(fā)生故障時(shí),整個(gè)集群保存了大概17TB的代碼。數據以分片方式跨越整個(gè)集群存儲,每個(gè)分片(shard)在另一個(gè)節點(diǎn)上有一份復制作為冗余,整個(gè)索引用去大約34TB存儲空間。整個(gè)存儲容量占用了集群總存儲空間的67%左右。代碼搜索集群運行在Java 6和elasticsearch 0.19.9上。當時(shí)這個(gè)集群已經(jīng)正常運行了好幾個(gè)月。
在1月17日、星期四,準備上線(xiàn)這個(gè)代碼搜索功能,以完成整個(gè)統一搜索的實(shí)現。后來(lái)發(fā)現elasticsearch已經(jīng)發(fā)布了0.20.2版本,其中包括多個(gè)功能修復和性能改進(jìn)。
他們決定推遲代碼搜索上線(xiàn),先升級elasticsearch,希望這可以讓新功能的上線(xiàn)更加順暢。
在1月17日完成了升級,集群中所有節點(diǎn)都成功上線(xiàn),而且恢復到正常的集群狀態(tài)。
問(wèn)題就此開(kāi)始出現。
從這次升級開(kāi)始,集群中出現兩次故障。
elasticsearch與其他使用大量單一索引存儲數據的索引服務(wù)不同,它使用分片模式切分數據,這樣可以很容易地將數據分布在整個(gè)集群中,而且易于管理。每個(gè)分片自己是一個(gè)Lucene索引,elasticsearch使用Lucene合并索引來(lái)聚合所有的分片搜索查詢(xún)。
在升級后兩個(gè)小時(shí),第一次故障出現了,恢復的過(guò)程中要重啟整個(gè)集群。我們在索引日志中發(fā)現的錯誤信息指出:有些分片無(wú)法分配到特定節點(diǎn)上。進(jìn)一步檢查后,我們發(fā)現:這些數據分片有些區段的緩存文件已經(jīng)損壞,其他在磁盤(pán)上已經(jīng)丟失,但elasticsearch仍然可以恢復有損壞區段緩存的分片,它也可以恢復丟失了一份復制的分片,但是總計510個(gè)分片中有7個(gè)分片,主分片和副本都已經(jīng)丟失了。
我們復核了發(fā)生故障的環(huán)境,當時(shí)的結論是:我們發(fā)現的問(wèn)題,來(lái)源于集群恢復帶來(lái)的高負載。對問(wèn)題的進(jìn)一步研究后,沒(méi)有發(fā)現其他elasticsearch用戶(hù)遇到過(guò)類(lèi)似問(wèn)題。在那個(gè)周末,集群沒(méi)有問(wèn)題,因此我們決定發(fā)布新功能。
下一次故障出現在1月24日、星期四。引起團隊注意的,是他們的異常跟蹤和監控系統,其中檢測到大量的異常爆發(fā)。進(jìn)一步調查指出:大部分異常來(lái)自代碼查詢(xún)的超時(shí),以及加入新數據時(shí)更新代碼搜索索引的后臺作業(yè)。
這一次,我們開(kāi)始同時(shí)檢查集群中全部節點(diǎn)的整體狀態(tài)和elasticsearch的日志。我們發(fā)現:看似隨機性的多個(gè)存儲節點(diǎn)出現高負載。大多數節點(diǎn)的CPU使用率都是個(gè)位數,有幾個(gè)消耗量幾乎100%可用的CPU核。我們可以消除系統和IO引起的負載,在這些服務(wù)器上唯一導致高負載的是運行elasticsearch的Java進(jìn)程?,F在搜索和索引還是會(huì )超時(shí),我們也在日志中注意到:一些節點(diǎn)被很快選為master,此后又很快被移除。為了消除這種快速切換master角色帶來(lái)的潛在問(wèn)題,我們決定:最好的方法,是讓集群完全停機,然后將其啟動(dòng),禁止數據分片的分配和重新平衡。
這種方式讓集群恢復上線(xiàn),但是他們發(fā)現elasticsearch日志中有一些問(wèn)題。集群重啟后,他們發(fā)現有些節點(diǎn)無(wú)法重新加入到集群中,有些數據分片試圖二次分配到同一個(gè)節點(diǎn)上。這次,他們求助于elasticsearch公司的技術(shù)人員,并確認:
這些無(wú)法分配的分片(主分片與復制合計23個(gè))都有數據丟失。除數據丟失外,集群花費很多時(shí)間試圖恢復剩余的分片。在這次恢復過(guò)程中,我們必須多次重啟整個(gè)集群,因為我們加入了多次升級和配置變更,必須要驗證和再次恢復分片。這是這次故障中最耗時(shí)的部分,因為多次從磁盤(pán)中加載17TB索引數據十分緩慢。
和elasticsearch的技術(shù)人員一起,他們發(fā)現集群中有些地方配置錯誤,或是需要調優(yōu)配置,才能得到最佳性能。這次問(wèn)題也讓elasticsearch的技術(shù)人員也發(fā)現了elasticsearch的兩個(gè)bug。還有一個(gè)很重要的原因:
我們當時(shí)運行的Java 6是2009年早期的版本,其中包含多個(gè)嚴重bug,影響elasticsearch和Lucene,同時(shí)造成大量?jì)却娣峙?,導致高負載。
根據他們的建議,我們馬上升級了Java和elasticsearch,并按他們的推薦調整了配置。具體做法是:在我們的Puppetmaster上,針對這些特定變更,創(chuàng )建了一個(gè)新的話(huà)題分支,并在環(huán)境中的這些節點(diǎn)上運行了Puppet。使用了新的配置、新版本elasticsearch和Java7之后,此前兩次故障中遇到的負載不穩定和快速master選舉問(wèn)題再也沒(méi)有出現了。
但是,1月28日,又出現一次故障。不過(guò)這次與之前沒(méi)有關(guān)系,完全是人為錯誤。
一名工程師要把包含有Java和elasticsearch更新的特性分支合并到我們的生產(chǎn)環(huán)境中。過(guò)程中,工程師將代碼搜索節點(diǎn)上的Puppet環(huán)境回滾到了生產(chǎn)環(huán)境中,這是在部署合并代碼之前。這導致elasticsearch在節點(diǎn)上重啟,因為Puppet運行在上面。
我們馬上就發(fā)現了問(wèn)題根源,并停下集群,防止在一個(gè)集群中運行多個(gè)版本Java和elasticsearch導致任何問(wèn)題。當合并代碼部署后,我們在所有代碼搜索節點(diǎn)上再次運行Puppet,啟動(dòng)集群。我們沒(méi)有選擇在集群處于降級狀態(tài)時(shí)建立索引和查詢(xún),而是等它完全恢復。當集群完成恢復后,我們將代碼搜索功能打開(kāi)。
總結這幾次故障,Will指出:
在將代碼搜索集群中的elasticsearch升級到0.20.2版本之前,我們沒(méi)有在我們的基礎設施中對其進(jìn)行足夠測試,也沒(méi)在其他集群中測試。還有一個(gè)原因是:對于代碼搜索集群,我們沒(méi)有足夠的上線(xiàn)前(staging)環(huán)境。
現在運行的Java版本已經(jīng)經(jīng)過(guò)elasticsearch團隊測試,而且代碼集群配置也經(jīng)過(guò)他們審核,未來(lái)的審核過(guò)程也已經(jīng)安排確定。
對于周一的故障,我們正在開(kāi)發(fā)自動(dòng)化過(guò)程,保證這樣的效果:如果GitHub上的分支比Puppetmaster上分支更超前,確保這個(gè)環(huán)境中的Puppet不會(huì )運行。
最后,elasticsearch團隊提供了對運行大集群的幾點(diǎn)優(yōu)化建議:
1.設置ES_HEAP_SIZE環(huán)境變量,保證JVM使用的最大和最小內存用量相同。如果設置的最小和最大內存不一樣,這意味著(zhù)當jvm需要額外的內存時(shí)(最多達到最大內存的大?。?,它會(huì )阻塞java進(jìn)程來(lái)分配內存給它。結合使用舊版本的java情況就可以解釋為什么集群中的節點(diǎn)會(huì )停頓、出現高負載和不斷的進(jìn)行內存分配的情況。elasticsearch團隊建議給es設置50%的系統內存
2.縮短recover_after_time超時(shí)配置,這樣恢復可以馬上進(jìn)行,而不是還要再等一段時(shí)間。
3.配置minimum_master_nodes,避免多個(gè)節點(diǎn)長(cháng)期暫停時(shí),有些節點(diǎn)的子集合試圖自行組織集群,從而導致整個(gè)集群不穩定。
4.在es初始恢復的時(shí)候,一些節點(diǎn)用完了磁盤(pán)空間。這個(gè)不知道是怎樣發(fā)生的,因為整個(gè)集群只使用了總空間的67%,不過(guò)相信這是由于之前的高負載和舊java版本引起的。elasticsearch的團隊也在跟進(jìn)這個(gè)問(wèn)題。
原文地址