😊你好,我是小航,一個正在變禿、變強的文藝傾年。
🔔本專欄《八股消消樂》旨在記錄個人所背的八股文,包括Java/Go開發、Vue開發、系統架構、大模型開發、具身智能、機器學習、深度學習、力扣算法
等相關知識點,期待與你一同探索、學習、進步,一起卷起來叭!
目錄
- 題目
- 答案
- Elasticsearch 節點角色
- 寫入數據
- Translog
- Elasticsearch 索引與分片
- 簡歷準備
- 限流保護節點
- 利用消息隊列削峰
- 保護協調節點
- 雙集群
題目
💬技術棧:Elasticsearch
🔍簡歷內容:熟悉Elasticsearch節點角色、索引與分片基本原理。
根據業務定制Elasticsearch插件,實現基于內存使用率和CPU 使用率限流;針對xx業務實時性不高,引入消息隊列Kafka,通過監聽binlog并將生成消息丟到Kafka中,實現削峰和限流;針對高并發業務設計策略保護協調節點;設計簡易雙集群方案來替換CCR方案,成本節約了近80%。
🚩面試問:主分片是由主節點選出來的,那么主節點自己又是怎么選出來的呢?
💡建議暫停思考10s,你有答案了嘛?如果你有不同題解,歡迎評論區留言、打卡。
答案
對于中間件,常見的兩個問題:
- 中間件是如何做到高可用/高性能的?
- 你在實踐中怎么做到高可用/高性能?
Elasticsearch 節點角色
Elasticsearch 的節點可以分成很多種角色,并且一個節點可以扮演多種角色。常見的有:
候選主節點(Master-eligible Node)
:可以被選舉為主節點的節點。主節點主要負責集群本身的管理,比如說創建索引
。類似的還有僅投票節點(Voting-only Node)
,這類節點只參與主從選舉,但是自身并不會被選舉為主節點。協調節點(Coordinating Node)
:協調節點負責協調請求的處理過程。一個查詢請求會被發送到協調節點上,協調節點確定數據節點,然后讓數據節點執行查詢,最后協調節點合并數據節點返回的結果集。大多數節點都會兼任這個角色。數據節點(Data Node)
:存儲數據的節點。當協調節點發來查詢請求的時候,也會執行查詢并且把結果返回給協調節點。類似的還有熱數據節點(Hot Data Node)、暖數據節點(Warm Data Node)、冷數據節點(Cold Data Node)
,你從名字就可以看出來,它們只是用于存儲不同熱度的數據。
寫入數據
寫入數據的整體流程如下:
- 文檔首先被寫入到 Buffer 里面,這個是 Elasticsearch 自己的 Buffer。
定時刷新到 Page Cache 里面
。這個過程叫做 refresh,默認是 1 秒鐘執行一次
。- 刷新到磁盤中,這時候還會
同步記錄一個 Commit Point
。
數據遷移存在的問題:
- 在寫入到 Page Cache 之后會產生很多段(Segment),
一個段里面包含了多個文檔
。文檔只有寫到了這里之后才可以被搜索到。 不斷寫入會不斷產生段,而每一個段都要消耗 CPU、內存和文件句柄
,所以需要考慮合并。
整個過程:
已有的段不動
。創建一個新的段,把已有段的數據寫過去
,標記為刪除的文檔就不會寫到段里面。告知查詢使用新的段
。- 等使用老的段的查詢都結束了,直接刪掉老的段。
查詢怎么知道應該使用合并段了呢?
這都依賴于一個統一的機制,就是 Commit Point
。你可以理解成,它里面記錄了哪些段是可用的
。所以當合并段之后,產生一個新的 Commit Point,里面有合并后的段,但是沒有被合并的段,就相當于告知了查詢使用新的段
。
Translog
Elasticsearch 在寫入的時候,還要寫入一個東西,也就是 Translog。如果宕機了,Elasticsearch 可以用 Translog 來恢復數據
。
對比一下 MySQL 的寫入過程:
- MySQL 寫入的時候,其實
只是修改了內存里的值,然后記錄了日志,也就是 binlog、redo log 和 undo log
。 - Elasticsearch寫入的時候,也是
寫到了 Buffer 里,然后記錄了 Translog
。
不同的是,Translog 是固定間隔刷新到磁盤上的,默認情況下是 5 秒
。
Elasticsearch 索引與分片
一個 Elasticsearch 的索引并不僅僅指倒排索引,還包括了對應的文檔
。這個和關系型數據庫下的語義是不同的。Elasticsearch 的一個索引有多個分片,每個分片又有主從結構。
一個索引就是一個邏輯表
。分片就是分庫分表
。每個分片都有主從結構
,在分庫分表里面,一般也是用主從集群來存儲數據。
簡歷準備
問題收集:
- 你們公司有沒有使用 Elasitcsearch?用來解決什么問題?
- 你用的 Elasticsearch 的性能怎么樣?讀寫流量多大?存儲的數據量又有多大?
- 你創建的索引有多大?多少個分片?你是怎么確定分片數量的?
- 你們公司有沒有使用一些措施來保證 Elasticsearch 的可用性?有沒有用過 Elasticsearch 的網關?
- 你們公司的 Elasticsearch 有沒有出過問題?出了什么問題?最終又是怎么解決的?
Elasitcsearch 高可用的核心:
分片
,并且每個分片都有主從之分。萬一主分片崩潰了,還可以使用從分片,從而保證了最基本的可用性。Translog
,類似于 MySQL 里的 redo log。后面 Elasticsearch 崩潰之后,可以利用 Translog 來恢復數據。Elasticsearch 在寫入數據的過程中,為了保證高性能,都是寫到自己的 Buffer 里面,后面再刷新到磁盤上。所以為了降低數據丟失的風險,Elasticsearch 還額外寫了一個 Translog。
在 Elasticsearch 的基礎上,還可以做一些額外的優化,來保證 Elasticsearch 的高可用。
限流保護節點
通過 Elasticsearch 的插件機制來實現自定義的限流策略,例如設計一個限流插件,根據 Elasticsearch 當前的內存使用率和 CPU 使用率來判斷是否需要執行限流
。不管是內存使用率還是 CPU 使用率,只要超過閾值一段時間,就觸發限流。
也可以考慮其他兩種策略,一種是在 Elasticsearch 之前加一個網關,查詢經過網關的時候會被限流、熔斷或者降級
。當然,引代理也可以
。
這里客戶端也可以進行限流,各個業務方需要限制住自己的查詢頻率,防止把整個 Elasticsearch 打崩,這種方式是最好落地的。
利用消息隊列削峰
場景:數據實時性要求不高。
方案:在業務方和 Elasticsearch 中間加入一個消息隊列。削峰和限流。
優化前:雙寫,一方面寫數據庫,一方面寫 Elasticsearch。那么在業務高峰期,Elasticsearch 就會有性能瓶頸。
優化后:引入了消息隊列。業務方只是寫入數據庫就返回。然后我們監聽 binlog,并且生成消息丟到 Kafka 上。在這種情況下,Elasticsearch 空閑的話,消費速率就高;如果 Elasticsearch 性能比較差,那么消費就比較慢。這樣就起到了削峰和限流的效果。
在這個架構的基礎上,還可以考慮引入降級
,也就是在 Elasticsearch 真的有性能問題的時候,關閉一部分消費者。
我有兩類消費者寫入數據到 Elasticsearch。一類是核心數據消費者,一類是非核心數據消費者
。如果我在監控到 Elasticsearch 性能已經比較差了,比如說寫入的時候會遇到超時問題,那么我就把非核心數據消費者停下來
。等 Elasticsearch 恢復過來再啟動。
對于大促或者秒殺這種活動中,你可以把整個數據同步都停掉
,讓 Elasticsearch 只支持查詢操作。如果你所在的業務是電商類的,那么你可以考慮使用這個策略。
保護協調節點
問題:突發大請求打崩協調節點。
場景:你有一個查詢命中了十個分片,并且每個分片都返回了幾萬條數據
,那么協調節點本身的資源使用量一下就會上去
,甚至出現 CPU 100% 或者 OOM 等問題。
解決方案:如果公司內部資源比較多,那么可以考慮 部署純粹的協調節點。比如說專門部署一批節點,只扮演協調節點的角色。
如果客戶端能夠判定自己是大請求,就將請求發送到純粹的協調節點上
,否則發送到其他兼任的協調節點上。
好處:大請求即便把協調節點打崩了,也只會影響到其他大請求。但是占據絕大多數的普通請求,并不會受到影響。
對 Elasticsearch 進行二次開發,可以修改協調節點的邏輯,讓協調節點在資源快不足的時候,直接拒絕這種大請求。
雙集群
鈔能力方案:直接使用付費的 CCR 跨集群復制。
簡單方案:假設有A、B兩個集群。
- 使用消息隊列來保持雙寫。
寫入的時候并不是直接寫入到 Elasticsearch,而是寫入到消息隊列
,而后啟動兩個消費者,分別消費消息
,然后寫到兩個集群 AB 里面。 - 在查詢的時候,優先使用 A 集群,當確認 A 集群出了問題的時候,切換到 B 集群。
如何實現自動切換:對 Elasticsearch 的客戶端進行了二次封裝
。在封裝之后,正常情況下,會訪問集群 A。同時客戶端監控集群 A 的響應時間。如果響應時間超出預期,又或者返回了比較多超時響應,客戶端就會自動切換到集群 B 上。
往期精彩專欄內容,歡迎訂閱:
🔗【八股消消樂】20250619:構建微服務架構體系—保證服務高可用
🔗【八股消消樂】20250615:構建微服務架構體系—鏈路超時控制
🔗【八股消消樂】20250614:構建微服務架構體系—實現制作庫與線上庫分離
🔗【八股消消樂】20250612:構建微服務架構體系—限流算法優化
🔗【八股消消樂】20250611:構建微服務架構體系—降級策略全總結
🔗【八股消消樂】20250610:構建微服務架構體系—熔斷恢復抖動優化
🔗【八股消消樂】20250609:構建微服務架構體系—負載均衡算法如何優化
🔗【八股消消樂】20250608:構建微服務架構體系—服務注冊與發現
🔗【八股消消樂】20250607:MySQL存儲引擎InnoDB知識點匯總
🔗【八股消消樂】20250606:MySQL參數優化大匯總
🔗【八股消消樂】20250605:端午節產生的消費數據,如何分表分庫?
🔗【八股消消樂】20250604:如何解決SQL線上死鎖事故
🔗【八股消消樂】20250603:索引失效與優化方法總結
🔗【八股消消樂】20250512:慢SQL優化手段總結
🔗【八股消消樂】20250511:項目中如何排查內存持續上升問題
🔗【八股消消樂】20250510:項目中如何優化JVM內存分配?
🔗【八股消消樂】20250509:你在項目中如何優化垃圾回收機制?
🔗【八股消消樂】20250508:Java編譯優化技術在項目中的應用
🔗【八股消消樂】20250507:你了解JVM內存模型嗎?
🔗【八股消消樂】20250506:你是如何設置線程池大小?
🔗【八股消消樂】20250430:十分鐘帶背Duubo中大廠經典面試題
🔗【八股消消樂】20250429:你是如何在項目場景中選取最優并發容器?
🔗【八股消消樂】20250428:你是項目中如何優化多線程上下文切換?
🔗【八股消消樂】20250427:發送請求有遇到服務不可用嗎?如何解決?
📌 [ 筆者 ] 文藝傾年
📃 [ 更新 ] 2025.6.20
? [ 勘誤 ] /* 暫無 */
📜 [ 聲明 ] 由于作者水平有限,本文有錯誤和不準確之處在所難免,本人也很想知道這些錯誤,懇望讀者批評指正!