由Elasticsearch的API命令,引发的金融业生产故障
作者介紹
李猛,數據領域專家,Elastic Stack國內頂尖實戰專家,國內首批Elastic官方認證工程師21人之一。2012年入手Elasticsearch,對Elastic Stack技術棧開發、架構、運維、源碼、算法等方面有深入實戰經驗。負責過多種Elastic Stack項目,包括大數據分析領域、機器學習預測領域、業務查詢加速領域、日志分析領域、基礎指標監控領域等。十余年技術實戰從業經驗,擅長大數據多種技術棧混合,系統架構領域。
序言
圖示:Elasticsearch目前在DB-Engine綜合排名第8
Elasticsearch博大精深,提供了非常豐富的應用場景功能,也提供了豐富的API命令操作,有些API非常好用,有的API用一用就要出大事,防不勝防。
以下圍繞某客戶一次客戶端應用程序錯用Cluster State命令展開,從問題定位到問題解決,記錄自己的過程與方法,還有一些心得總結(注:具體客戶信息不便透漏,以下部分圖片信息僅為示意圖)。
一、案例介紹
1、項目背景概要介紹
客戶用ES來解決日常的數據查詢與存儲,利用ES非常好的橫向擴展特性,滿足多種場景應用。
ES集群版本屬于5.6.x,已經超出Elastic官方支持的版本,集群節點數不到10個,節點硬件配置屬于均衡一致性,標準的性能型合理范圍硬件配置,應用于業務系統提供查詢或者更新等,日常都有提供定期巡檢,基本正常穩定,不過一直側重的是集群運維本身,很少會深入到應用端程序去巡檢分析,業務線太多,經費有限。
ES集群設置并未采用Master與Data分離設計,所有節點均是同等角色權限。ES集群數據量也是屬于正常支撐能力范圍,集群索引的分片數量在2w以上,注意這個數字,后面會基于此來突破尋找問題。
客戶端應用程序基于Spring data elasticsearch開發框架,引用Trasnport-client直連模式,中間未采用任何代理Proxy負載產品。
客戶端應用程序部署了多個實例,按照2的倍數增加,需要做一些“大量”數據的寫入與查詢,瞬間并發的操作ES集群,無論怎么操作,ES的并發數并不高,但應用端程序就是運行不快,這很不合常理也不合事宜,常識告訴我這不正常。
圖示:客戶公司的應用項目架構示意圖,客戶端采用Transport-client直連模式
2、問題現象與事故原因
客戶端應用程序只要開始運行,ES集群立刻會慢起來,但查看ES集群整體資源消耗,ES所在節點CPU/MEM/硬盤IO并不高,其數據節點甚至非常低,遠遠沒有達到節點的瓶頸。
經過細細觀察發現,集群的Master節點流量特別高,其余節點數據流量都傳給Master節點,超出了Master單節點網絡IO的極限,這顯然不正常。但在生產環境上并不容易排查。后面經過在本地開發環境模擬壓測,終于確定了問題來源,是客戶端的某個集群管理操作 API引起的。
最終,找到了 Cluster State Api 統計命令引起的,客戶端應用程序每次做實際業務前,都會調用這個API命令獲取集群一些索引與Mapping信息,由于客戶端是采用多線程設計,且部署多個實例,只要并發數高,所有流量必然打到Master節點,造成整個集群響應慢。由于整個集群有近2w個分片,執行一次State 命令,需要統計匯總集群所有索引分片信息,并最終匯總到Master節點,造成實際Master節點網絡IO超過極限。
圖示:cluster state api返回內容,索引越多,返回內容越大。
二、排查過程&分析手段
以上我們快速講了一下問題現象與事故原因, 下面重點聊一下問題排查過程以及采用的工具方法思維等。
特別說明,由于是遠程協作分析排查以及客戶公司的行業特性,外部不能直接操作遠程任何節點,必須通過客戶公司運維人員間接指導操作排查,過程稍微有點曲折。
1、服務端集群排查
首先是ES集群問題排查,這是很正常直接的思維,在問題爆發點排查(ps:類似警察先趕到案發現場,采集證據)。由于集群版本是5.6.x,一些原因并未啟用官方的XPack功能,所以也就沒有自帶的Kibana監控可視化報表,國內早期多數用戶都是采用開源免費版本搭建集群,客戶公司基于Zabbix搭建有集群節點的基礎指標監控,總算是有一個,非常難得。
1)zabbix監控分析
很快基于Zabbix展開各個ES機器節點指標監控分析,按照常規套路,分析了CPU、內存、磁盤IO等一切正常,并不高。這就非常令人困惑,明明集群響應很慢,客戶端應用程序開發人員也如實反應,部署的實例非常少,所以初次分析下來,并未發現明顯定位到問題。
接著分析節點網絡IO,貌似發現了問題點,其中Master節點流量特別高,超出了網卡的極限;按照此套路,繼續查看了其它數據節點網絡IO,也比較高,然后觀察發現,數據節點的網絡IO流量累計起來剛好等于Master節點網絡IO流量,終于算是找到了一個突破口。
注意,基于Zabbix雖然能監控各個獨立節點的網絡流量,但并不能看到節點之間網絡流量,以及應用客戶端與服務端之間,這很不友好,若有一張全網絡流量圖,將會更容易定位分析問題。
圖示:Zabbix 網絡流量示意圖,僅僅能快速查看單獨節點
2)iftop監控分析
借助Zabbix算是找到了突破口,接下來就需要一張網絡流量關聯圖。此時第一個想到的是 Elastic Stack Packetbeat 網絡IO流量包可視化監控監控,瞬間與客戶公司討論,能否安裝配置,顯然這個過程太慢,需要申請更多資源等麻煩,時間預計來不及。后面客戶公司運維工程師臨時安裝 Linux 絡指令iftop,終于能夠分析ES所有節點網絡IO流量的流進流出方向,但是觀察分析相對來說比較痛苦,而且并不能繪制一個網絡圖譜,所以觀察起來還是不夠全面。
iftop僅僅在單機節點執行,所以只能看到單個節點的網絡流量進與出,不過這已經非常好了,只是時間長一點。
基于網絡IO流量進出初步分析觀察,很快做出了決策,先是重啟了現有Master節點,讓ES集群重新選舉新的Master,結果發現依然新選舉的Master節點流量依然巨大;接著也臨時申請增加2個新的ES節點,以為可以分散客戶端訪問的壓力,事實上并未從根本上排查解決。此時的判斷是認為某些業務索引查詢,造成流量比較大,剛好在Master節點中轉匯總,這里其實還沒有分析到客戶端的流量,所以做了一些無用的緊急服務端調整,但也證明了問題不在ES服務端。
圖示:iftop網絡流量示意圖,能分析到單節點的流量進出,也是不錯了
3)packetbeat監控分析
由于一些原因,并未部署Elastic Stack 監控分析產品,特別推薦Packetbeat網絡流量監控分析產品,官方默認提供的網絡流量圖,非常有用,可以更快速定位流量走向,相比ittop,更加全面一些,可以總結為iftop的網絡版本。Packetbeat內置官方一些可視化報表,如果覺得不夠,可以基于ES提供的分析能力自行設計。
圖示: packetbeta網絡IO流量監控分析圖,輸入與輸出
2、客戶端排查
其次是從客戶端應用排查。但實際上,客戶公司運維人員第一時間發現問題,聯系到我,我的第一個問題就是客戶端應用在做什么業務,業務類型是什么。運維人員也如實告知正在做的業務類型以及應用情況,其實只能概要說明一下,詳細的業務操作流程與影響的是不知道的,對于我來說,反正就知道了有個業務操作在影響著集群,具體怎么影響,還得繼續排查。必須說明一下,這個可能是國內IT運維界的通病,看起來運維屬于末端支持,本質更應該參與到業務系統的前沿陣地,從業務開始了解背后的運維問題。
然后通過ES服務端排查,掌握了一些信息,但遠遠不足以定位到問題,客戶端排查就任重道遠,必須要找出問題所在。ES集群響應慢有很多,但服務端只能發現問題,并不能從根本上解決,于是通過在服務端運行 thread_pool 與 task 命令,發現了集群的管理線程池特別多,任務一直爆滿,這不正常,這就更加肯定一定是客戶端的某些應用在惡意操作這些命令。
1)thread_pool 監控分析
集群響應慢,集群線程池是一個必須考慮的點,其中會查看到累計的任務量,經過打開指令觀察,其中的 management 線程池特別高,由此判斷客戶端正在做一些任務,且屬于management 線程池的,目前具體的依然不能確定,因為沒有看到客戶端應用具體的代碼調用方式。
圖示:thread_pool示意圖,可以監控ES節點任務數
2)task監控分析
借助thread_pool分析,可以定位到 management 線程池正在大規模做任務,同理借助task 查看分析 具體做的任務是什么。(ps:實際客戶環境中,發現是大量的state、stats任務,其中state任務數明顯要高,且非常不正常,這里不方便透漏,后面會詳細列出如何壓測出來此結果)
圖示:task示意圖,可以查看到具體的任務類型
3)stats監控分析
借助 task 監控分析,發現有大量的stats指令,接著在服務端執行一次,看看情況如何,實際發現響應也比較慢,但按理是正常的,產生的隊列次數并不高,只是執行慢,基于以上判斷應該是別的任務阻塞導致。
stats 負責集群監控檢查響應,常規的集群yellow,red,green就來自與此;另外也收集索引的統計信息,節點的統計信息,返回的數據量不多,常規下可以忽略不記,不過注意后面transport-client 訪問需要。
圖示:stats命令執行示意圖
4)state監控分析
借助 task 監控分析,發現有大量的state指令,接著在服務端執行一次,發現了問題點,執行一次時間很長,且響應返回的內容超過70mb,這是問題,可以回答為什么之前的master節點流量如此之高。終于問題越來越清晰了,也越來越確定了。
圖示:state命令執行示意圖
5)transport-client應用訪問
借助前面服務端現象分析,越來越確定問題出在客戶端應用代碼,大概率是操作不正確。
首先與客戶交流,詢問客戶端應用代碼訪問ES的方式與程序版本,客戶端開發團隊很好配合,很快了解到應用客戶端基于spring data elasticsearch框架,采用transport-client機制訪問操作ES,但此時是不能定位是客戶端造成的,也不能匆忙要求客戶端提供源碼。接下來很快在本地編寫相應的測試程序源碼。
Transport-client客戶端綁定代碼
/*模擬spring data elasticsearch配置transport-client,示例來自官方文檔*/ @Configuration public class TransportClientConfig extends ElasticsearchConfigurationSupport {@Beanpublic Client elasticsearchClient() throws UnknownHostException {Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build(); TransportClient client = new PreBuiltTransportClient(settings);client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300)); return client;}@Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" })public ElasticsearchTemplate elasticsearchTemplate() throws UnknownHostException {ElasticsearchTemplate template = new ElasticsearchTemplate(elasticsearchClient, elasticsearchConverter);template.setRefreshPolicy(refreshPolicy()); return template;} }6)jmeter壓測模擬
因為某些原因,我們只能提供間接性的服務方式,所以為了徹底解決上面的問題,需要在本地模擬測試,必須要模擬出生產的問題,才能要求客戶端給出到源碼。基于前面服務端與客戶端應用了解到的信息,接下來就是要做壓測,特別選擇了jmeter工具,很快配置好本地集群,附加客戶端應用訪問代碼。壓測進行時,同步觀察ES服務端threadpool與task,能夠復現生產的問題,很快就得到了想要的結果。
圖示:jmeter壓測示例,開啟更多線程數,超過ES測試服務器線程數
圖示:jmeter壓測示例,一次state命令執行需要消耗非常多的資源
既然在本地環境,借助jmeter壓測出來生產上同樣的問題,那么最后一步就是與客戶應用開發團隊一起review代碼,這一步非常快,很快就定位到 客戶應用端代碼在具體業務操作前,會調用Cluster State API,進行業務邏輯判斷,判斷索引是否存在,判斷索引字段是否存在等。
最終問題定位到了,產生原因也知道了,事情也算告一段落。
/* 客戶應用端的某個訪問代碼借助state來判斷索引的mapping信息 */public Map<String, Object> getMappingByField(String indexName, String type) throws IOException {ImmutableOpenMap<String, MappingMetaData> mappings = getClient().admin().cluster().prepareState().execute().actionGet().getState().getMetaData().getIndices().get(indexName).getMappings();if(mappings.isEmpty()) {return null;}Map<String, Object> mapping = mappings.get(type).getSourceAsMap();Map<String, Object> properties = (Map<String, Object>) mapping.get(ES_PROPERTIES);return properties;}3、問題分析過程回顧
服務端分析,尋找突破口
客戶端分析,縮小排查范圍
模擬測試,復現生產問題,確定問題產生原因
應用端代碼分析,找出問題代碼
修改觀察,確認問題已經解決
經驗總結,復查所有其它相關代碼
圖示:問題排查過程與流程
三、ES技術架構原理
本次ES問題排查涉及到的知識點以及技術性原理特別多,這里也來特別說明一下與此關聯的架構原理,供大家日后參考與分析。
1、ES架構原理
ES對外雖然宣稱是個分布式架構,可以橫向擴展,但那說的是數據節點或者其它非管理節點。實際上ES是典型主從架構模式,一個集群只有一個Active Master節點,Master節點負責管理集群所有元數據信息,其中包括節點信息、索引信息、分片信息、節點與索引路由信息、節點與分片路由信息等,集群執行一次管理型的命令都需要先在Master執行,然后分發到其它節點等。
了解這一點非常重要,可以很好的解釋,為什么在本次ES故障中,Master的網絡流量剛好等于其余節點網絡流量之和。客戶端應用發起一次State統計,首先都是Master節點接受指令,接著分發給其它節點執行State統計,最終匯總到Master節點,造成了Master節點網絡流量奇高,超過網卡極限,ES集群響應慢,但實際CPU與內存消耗又不高。
聯想到這里,集群架構是不是可以想象型的大膽設計一下,現在的ES集群只有一個大當家,隨著集群規模越來越大,大當家壓力越來越大,大當家如果出現故障,就重新選大當家,這聽起來好像不符合社會組織學。那能否下次修改一下,設計一個有大當家與二當家的模式,大當家與二大家職責再分離一下,大當家太忙,二當家分擔一些。
圖示:ES主從架構分布式示意圖,一個集群只有一個Active Master節點
2、ES線程池
ES是個數據庫產品,內部設計了多個任務線程池,不同的線程池任務與職責不一;線程池也分為多種類型,不同的線程池類型應對任務場景不一樣;ES不同版本,線程池數量與類型會有大的差異,尤其是5.x與7.x版本,這種跨大版本,差異相當大。
由于在某機構做ES老師,時常與Java學員交流,發現了一些嚴重的認知誤區:1.很多學員認為Java不能開發數據庫產品,因為GC機制;2.多數人學習掌握的Java線程池都只用來做簡單的多線程業務場景,從未想象過,類似ES這樣集成了幾十個線程池的玩法。所以必須承認,ES是一個非常好的Java開發高手學習參考的產品,特別是做后端開發,想要更加深入進階的同學。
了解ES線程池內部設計非常重要,可以很好的解釋,為什么本次ES故障中,只有Active Master節點的 management 線程池特別繁忙,其余線程池總體很閑,其余節點的線程池也非常閑。客戶端應用發起一次State統計,首先接收任務的是Master節點的management線程池,此線程池類型為 scaling,且最大的線程數是一個固定值,不超過實際CPU合數,也不能超過固定值5,而不是根據節點CPU核數來自動彈性設計的。
當客戶端應用采用多線程執行模式,且每次執行業務操作前,都先執行一次State 統計做業務邏輯判斷,這就無形中增加了集群的負載,增加了Master節點的任務數量,客戶端應用實例數量越多,并發線程數也越多,集群Master節點就幾乎無法消化,畢竟Master節點就一個;也正是由于負責執行State任務的線程池是個固定值,Master節點CPU也不會打滿,這就阻塞了所有的業務操作。
有時候官方文檔并沒有列出來,需要通過ES源碼去查看,這點我至今也沒有想明白,不光是過去歷史版本,包括當前最新版本也是一樣的,如當前 7.15.x,有的線程池就沒有在官方文檔列出來,但能在集群監控中查看到。
圖示:ES內部線程池劃分,(版本7.13.x,來自某機構ESVIP課程)
3、ES集群統計執行過程
Cluster State Api 執行一次指令,指令會傳輸給Active Master節點,Active Master分發指令給各個節點,各個節點收集好信息之后回傳給Master,然后由 Master響應給客戶端。
在開始排查問題中,初次判斷失誤,以為是客戶端在做大量的業務數據查詢任務,所有節點數據量都很高,其中大量依賴Master節點對外輸出,實際不是。
圖示:Cluster State Api執行過程示意圖
4、ES動態創建索引
ES是典型的Free Schema數據產品,索引是可以動態創建的,索引的字段也是可以動態創建的,無需優先聲明,更無需在應用代碼中邏輯判斷是否存在,是否需要創建,這是ES非常好的動態擴展能力之一,基于此給應用開發帶來了相當多的便利,比如著名的“大寬表模式”查詢場景,解決了海量數據關聯實時查詢的問題。
ES可以提前創建索引,也可以不創建,寫入第一條數據,即可動態創建索引,并同時創建索引自動的mapping索引內部結構。若第二條數據寫入,增加了很多新的數據內容結構,則會自動更新當前索引的mapping,自動刷新mapping。若新增加的數據字段缺失,也不會出錯。ES默認內部會根據字段進行推測其字段對應的類型。
#動態創建空索引 PUT my-index-000001 { } #新增數據,動態創建索引,自動推測字段類型 PUT my-index-000001/_doc/1 {"create_date": "2015/09/02" } #更新數據,動態增加新字段類型 PUT my-index-000001/_doc/1 {"my_float": "1.0", "my_integer": "1" ,"create_date": "2015/09/02" }5、transport-client
Transport client 是官方早期推出的應用接入訪問機制,自Rest Api 推出之后,官方就竭力要求切換過來,其中緣由部分并沒有特別說明。Transport是一種直連方式,直接連接到ES集群中,連接之后保持長連接,并且需要定時執行內部的一些stats命令,來檢查集群監控狀況,這個其實非常多余,在極端情況下也非常消耗集群資源。
ES集群內部通信或者執行其它指令,都是通過transport機制,即使是rest api執行,內部也是轉換為transport機制來執行。
Rest 接入相比 Transport 更加解耦,也可以盡力避免惡意干擾 transport 通信,更多的此處不展開,后續會有另外的文章來寫。
圖示:transport-client與rest api連接示意圖
四、專家建議
此次從問題發現、問題定位、問題解決,花費了幾天時間,有一些經驗建議有必要特別說明一下。
1、全面的監控體系
監控體系是運維的眼睛,集群的各種運行信息,都需要借助強大的監控體系來保障,提供實時的分析等。本次案例中,客戶公司監控體系相對來說比較傳統落后,雖然有zabbix,但在一些新的分析問題方式上表現并不行,而且非常欠缺,如分析集群各個節點網絡流量進出走向,包括服務端與客戶端的關系,都是沒有的。
選擇一款全面性且非常有獨立視角的監控產品非常重要,Elastic Stack 是新時代的產物,新事物可以幫助我們提升優化問題排查思維。
2、權限安全隔離
絕大多數數據庫產品都提供了一些基本的安全策略與防護,可以通過設置一些安全用戶群組與角色權限來限制避免此種問題。
比如傳統的關系型數據庫MySQL,可以通過給客戶端應用分配更小的權限來限制。早期ES版本由于ES并未提供安全防護機制,很多應用團隊都是直接使用,也沒有做到基于用戶群組的權限隔離。最新版本的ES提供了開源免費的基本安全策略,可以通過用戶群組權限來避免客戶端應用的無意識操作。
3、全面的知識體系
本次案例中,先從集群后端運行分析,到應用程序端源碼分析,再到本地環境模擬測試,涉及到的技術點非常的寬泛,并不能從單一維度發現解決,也不能僅僅從ES知識層面排查解決;任何人都不能只從ES集群運行表象定位問題,很多問題爆發是屬于末端,但引起的其實在另外一端,這就需要跨界的能力與思維,當然最重要的是構建自己的知識體系,有自己獨立的解決問題排查思路,也得掌握必要的各種工具軟件,不能僅僅局限在ES范圍之內。
為了用好ES,我們需要掌握開發技能,熟練使用ES提供的開發特性,了解ES各種特性的邊界,防止濫用。我們需要掌握ES集群架構基本的原理,基本的運行機制,避免認知上的誤區,如ES是典型的主從架構分布式,并不是無中心的分布式。我們需要掌握常規的運維技能,從操作系統基礎環境,到ES運行各種指標信息等。
4、全棧工程師理念
隨著業務需求與社會發展,我們更多的是需要全棧式的工程師,當然必須聲明,不是要求一個工程師同時兼任多種工作,不是按照國內某些企業“壓榨式的全棧”。而是特別強調工程師的專業水平,工程師可以依據工作崗位比較容易切換角色,不僅僅局限某一個固定職位。很多優秀的IT產品都不是本職工作的人做出來的,而是一些跨界的人士創作出來的。
本次案例中,看似集群的問題是服務端,但實際上是由于開發知識面局限造成的,最后解決也是在應用端修改代碼解決,這是一個典型的跨界問題,由服務端逐步往前發現是應用端的問題。為了模擬生產環境問題,需要用壓測工具,這貌似又屬于測試職責,但為了解決問題,從后往前。為了確定線程池設置問題,下載ES對應版本源碼,去查看閱讀對應線程池的設置,因為官方文檔沒有。為了確定客戶端應用代碼問題,基于客戶開發人員提供的信息,編寫模擬客戶端應用代碼行為。
目前國內的大多數公司工程師都是單一職責職位與技能,尤其是注重前后端分離之后,前端與后端技能分裂的更嚴重了,前端很多薪資很高,漲幅快,看不起后端,后端也逐步遠離前端應用,更加不關心前端運行方式;后端應用與大數據開發也是,將大數據開發與應用開發分離,導致工程師的專業素養下降很快,不少大數據工程師都不具備很好的編程能力,這是值得大家思考的問題。
>>>>
參考資料
State 參考文檔
https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-state.html
threadpool參考文檔
https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html
elasticsearch transport client 參考文檔
https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/index.html
spring data elasticsearch 參考文檔
https://docs.spring.io/spring-data/elasticsearch/docs/4.2.6/reference/html/#reference
jmeter http request 參考文檔
http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Request
dbaplus社群歡迎廣大技術人員投稿,投稿郵箱:editor@dbaplus.cn
總結
以上是生活随笔為你收集整理的由Elasticsearch的API命令,引发的金融业生产故障的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果CMSv10首款原创支持百度mip技
- 下一篇: 那些喜欢的句子