面試官常考的MySQL索引(MySQL進階)
1288
2025-04-02
elasticsearch是一個實時的分布式搜索和分析引擎,它可以幫助我們用很快的速度去處理大規模數據,可以用于全文檢索、結構化檢索、推薦、分析以及統計聚合等多種場景。elasticsearch的數據存儲在本地lucene文件,采用json的數據格式,同時提供了簡單易用的restful接口。在實際應用場景下的實踐和探索結果,從業務場景,數據規劃,如何進行寫入和查詢調優,包括常見的問題出發。總結和梳理Elasticsearch的最佳實踐。
1 業務場景
1.1 數據特點
數據體量大,如大量的日志型數據,軌跡型數據等。
1.?從大量的日志型數據中,根據關鍵字搜索出相關的信息。需要把所有搜索結果過濾出來,便于進行二次分析(需要返回大量的查詢結果,一般萬級別以上)
2.?從軌跡型數據中,根據關鍵信息搜索出相關的軌跡變化。需要對搜索過程中按照一定的字段進行聚合(需要返回的查詢結果相對較小,對查詢響應時間要求高)。
從數據存儲周期來看:大部分數據保存周期為3-6個月,部分數據保存1年以上,甚至永久保存。
從業務場景來看:基本都屬于寫多查少的場景,或者寫入和查詢都多的場景。這就對ES集群的存儲和查詢能力有較高的要求。
1.2?ES在業務場景下的特點
一次寫入多次查詢:ES適合一次寫入多次查詢的場景,支持update更新操作,但是如果需要進行索引mapping的更改,需要reindex重建或者新建索引,更改成本較大,所以在大部分場景下,數據寫入之后不再更新。
全文檢索:ES的優勢在于全文檢索,模糊查詢,適合需要從大量的數據中根據某些關鍵信息挖掘有價值的數據的場景。
2 數據規劃
2.1 為什么數據規劃很重要
任何系統都有一套更為適用的規則或者其系統規格,前期的詳細設計能為我們后期維護優化節約大量的精力。在我們實際的經驗中,發現大部分問題(分片嚴重超規格,單個分片超大,索引mapping設置不合理等問題)都是由于數據的前期規劃不夠,大大增加了后期整改和優化的難度和成本。
在進行數據規劃之前,首先要對數據有充分的了解,包括不限于:
數據量有多大,包括總量,增量,以及未來的趨勢?
數據的生命之旅是怎么樣的,即從寫入到刪除的過程?
我們期望從數據里面挖掘出什么,即數據是用來做什么的?
2.2 合理的規格
常見的系統規格如下所示:
2.3?分片如何規劃
每個分片都可以處理索引和查詢請求,在設定分片數目時,可從以下幾個方面考慮:
1. 建議單個分片保存的數據量在20GB左右,最大不超過30GB,過大的分片會降低查詢以及索引恢復的性能。
2. 根據索引預計承載的最大數據容量和單個分片容量確定主分片個數。
3. 為了提升數據可靠性,合理設置副本分片個數,至少設置為1,如果集群的存儲空間足夠,推薦設置為2。
4. 每個node可以支撐的shards個數是有限的,node是物理資源分配的對象,隨著shards中數據的增大,shards中的數據在查詢時被不斷加載到內存,達到一定量時,將會把HeapSize耗盡,導致頻繁GC,系統將不能正常工作。推薦1GB內存管理15個shard,以一個Elasticsearch實例內存最大31G為例,單實例管理的shard數保持在500以內。
5. 配置total_shards_per_node參數,讓分片更加均勻的分布在各個實例上。表示限制每個實例上分布該該索引的分片最大個數,如2,即表示每個實例上最多分布2個該索引的分片。
說明:total_shards_per_node參數值=索引總分片數/數據實例數(向上取整)。
2.4?數據結構如何規劃
通常的使用場景中,一個集群內的業務數據一般分為幾類,為了更加方便數據管理,通常會將相近的數據結構的數據歸為一類。這時候建議使用索引模板規范索引的建立,不同類別的數據創建不同的索引模板。
2.4.1 索引模板
Elasticsearch提供一種叫“索引模板”方式,幫助用戶在新創建索引時采用提前設定好的參數,簡化創建過程。索引模板可以設置包括order、template、settings和mappings等部分設置靈活。索引模板僅在新創建索引時起作用,修改索引模板不對會現有已經創建的索引產生影響。索引模板設定后,會根據模板設定規則,在滿足設定條件的時候起作用,如果創建的索引中已經指定索引模板設置的參數則索引模板不會起作用。
索引模板設置內容如下:
order:模板優先級,最大值2147483647(JAVA Integer.MAX_VALUE - 1),Order值越大優先級越高,如果不設置則為0;
template:模板匹配的名稱方式,比如:“te*”表示匹配名稱以“te”開頭的索引,如果為“*”表示匹配所有的索引;
settings:索引設置,一般定義的是索引的主分片、拷貝分片、刷新時間、自定義分析器等;
mappings:索引中各個字段的映射定義,可以設置動態映射和自定義字段映射;
aliases:設置索引別名。
注意:如果匹配到多個模板(和匹配規則無關,只要匹配到了就行,即匹配規則不影響模板的優先級),會將這些模板的設置進行合并,不同的優先級相同的設置屬性優先使用優先級高的配置,如果相同的優先級相同的屬性設置則優先使用最先創建的那個模板,其他的不相同的屬性會合并到一起。
{ ????"order":?0, ????"template":?"*", ????"settings":?{ ????????"index":?{ ????????????"indexing.slowlog.source":?"500", ????????????"indexing.slowlog.threshold.index.debug":?"2s", ????????????"indexing.slowlog.threshold.index.info":?"5s", ????????????"indexing.slowlog.threshold.index.warn":?"10s", ????????????"number_of_replicas":?"1", ????????????"search.slowlog.threshold.query.debug":?"2s", ????????????"search.slowlog.threshold.query.info":?"5s", ????????????"search.slowlog.threshold.query.warn":?"10s", ????????????"store.type":?"niofs", ????????????"translog.durability":?"async", ????????????"translog.flush_threshold_size":?"3gb" ????????} ????} }
2.4.2 索引的創建
1. 為了減少索引數量并避免非常龐大的映射,請考慮將相同索引結構的數據存儲在相同的索引中;
2. 避免將不相關的數據放在同一個索引中,以避免稀疏,將這些文件放在不同的索引中通常會更好;
3. 針對數據量比較大的索引,建議按周期進行分表,比如按天進行索引劃分;
4. 建議提前創建好索引,不要自動創建索引,可以避免集群內出現一些雜亂的數據。可通過設置參數auto_create_index:true關閉自動創建索引。
2.4.3 索引mapping的設置
寫入數據前進行合理的mapping設置是必須的,而且一旦索引已經創建好,已經存在的字段無法更新:
1. Elasticsearch可以對數據做動態mapping,但請不要這么做,盡量在創建index時便賦予index固定的mapping配置。設置動態mapping,當大量數據寫入的同時伴隨著新的字段的增加,會造成大量的put_mapping操作,從而造成EsMaster阻塞,影響整個ES集群的運行。不建議使用動態mapping,如果需要使用動態mapping,建議盡量使用較為精準的匹配規則,杜絕*通配符等暴力操作。
{ ????"mappings":?{ ????????"mytype":?{ ????????????"dynamic":?false ????????} ????} }
2. 如果數據量巨大,可以分的字段個數太多,如超過1000個字段,最好給字段賦予不同的級別索引到不同的index中。例如,常用的查詢字段可以寫入到一個index中,字段長度較長且不常用的索引到另一個index中。
3. 合理的設計Mapping,根據實際的業務數據去設置優化Mapping,根據具體的字段和需求去選擇對應的類型設置,可參考如下幾點:
a. string類型默認分成:text和keyword兩種類型。需要分詞:text,否則keyword;
b. 枚舉類型,基于性能keyword,即便是整形;
c. 數值類型,盡量選擇貼近大小的類型;
d. 日期類型,如果需要基于時間軸做分析,必須date類型,如果僅需秒級返回,建議使用keyword;
e. 其他類型,布爾、日期、地理位置,使用對應的類型即可;
f. 如果某個字段不需要被檢索,則不需要建立索引,可以減少很多的CPU計算操作,將“index”參數設置為“false”;
{ { "content":?{? "index":?false? }? } }
g. 如果字段完全不需要檢索,排序,聚合分析,將“enable”參數設置為“false”;
{? {? "content":?{? ?? "enabled":?false? }? }? }
4. “_all”字段,默認將寫入的字段拼接成一個大的字符串,并對該字段進行分詞,用于支持整個doc的全文檢索,“_all”字段在查詢時占用更多的CPU,同時占用更多的磁盤存儲空間,默認為“false”,不建議開啟該字段;
{ ????"_all":?{ ????????"enable":?false ????} }
5. norms字段,norm是索引評分因子,如果不用按評分對文檔進行排序,設置為“false”,默認是“true”;
6. _source字段,默認是開啟的,如果不需要update、reindex和高亮操作,可以禁止“_source”,節省更多的磁盤空間;
a. doc_value字段,默認是開啟的,存儲的是正排索引,如果不需要對字段進行排序和聚合,可以禁用該字段的doc_value,能節約大量的磁盤空間。
{ ????"mappings":?{ ????????"my_type":?{ ????????????"properties":?{ ????????????????"filed":?{ ????????????????????"doc_values":?false, ????????????????????"type":?"keyword" ????????????????} ????????????} ????????} ????} }
2.4.4?索引setting的設置
1. 修改索引刷新時間:默認為1s,即每1s都會將寫入到內存里面的數據刷新到磁盤里面,可修改為60s或者120s,減輕磁盤的IO壓力;
"refresh_interval"?:?"60s"
2. 修改Translog策略參數,默認translog的持久化策略默認為request,即每個請求都進行flush,影響ES寫入速度。將持久化策略改成async,表示按設置的sync_interval周期性進行刷新,同時調大translog刷盤間隔時間,默認為5s,調大至120s或者180s。調大translog flush的大小為3G,即大小超過3GB進行刷新操作;
"translog.?durability?":"async"? "sync_interval":?"180s"? "translog.flush_threshold_size":"3gb"
3. 設置index.type.store為niofs模式,可以減輕集群的IO負載;
"index.type.store"?:?"niofs"
4. 針對于5機器節點以上,為了讓各個實例上的分片均勻分布,添加如下參數,設置每個索引在單個實例上的分片個數,如下所示為每個索引在每個實例上的分片為2個。
"index.routing.allocation.total_shards_per_node":"2"
2.5?數據生命周期如何規劃
Elasticsearch中的open狀態的索引都會占用堆內存來存儲倒排索引,過多的索引會導致集群整體內存使用率多大,甚至引起內存溢出。所以需要根據自身業務管理歷史數據的生命周期,如近3個月的數據open用于快速查詢;過去3-6月的數據索引close以釋放內存,需要時再開啟;超過6個月的可以刪除索引。
可以使用索引模板的方式按照一定時間創建新的索引,例如按天創建索引,索引的命名可能是index-yyyy-mm-dd,每天生成不同的索引,清除歷史數據時可直接關閉或刪除。
2.5.1 滾動索引
當一個索引過大或者過于陳舊時,滾動索引可以將索引的別名滾動到一個新的索引上,這個新的索引結構與舊索引結構相同。
滾動索引API需要指定一個索引別名和條件。發送請求時這個索引別名需要指向一個可以寫入的索引,否則請求將無效。
索引別名:
指定的索引別名有以下兩種情況:
(1)如果別名指向一個索引,is_write_index未配置,此時舊索引別名將滾動到新索引上,同時舊索引別名將被刪除;
(2)如果索引別名指向一個或者多個索引,同時有一個或者多個索引的is_write_index設置為true,此時,這些可寫入的索引將滾動別名同時將is_write_index設置為false,將別名滾動到新的索引同時將新索引的is_write_index設置為true。
滾動條件:
滾動索引的API支持三個條件,如下所示。
當發出滾動請求的時候指定索引滿足設定條件中的任意一個或者多個索引將會被滾動,如果不滿足則不會滾動,elasticsearch暫不提供監聽功能,需要滾動時需要手動觸發。
索引命名規則:
滾動索引的命名必須滿足一定規則否則無法正常滾動索引或者需要手動指定新的索引名稱。
1. 以-和數字結尾:如果現有索引名稱以-和數字結尾例如log-1,新的索引名稱將會根據現有數字大小加1,無論就得索引名稱如何,新的索引的編號數字都會填充為6位,log-1索引滾動后新的索引名稱為log-000002。
2. 使用日期計算:新索引的命名也支持用滾動日期來命名,要求索引名稱同樣以-加數字結尾,比如log-2019.08.28-1,如果當天滾動索引的話新的索引名稱為log-2019.08.28-000002,如果一天后滾動新的索引名稱為log-2019.08.29-000002。
也可以用日期計算進行創建索引并設定別名,如以下操作將會創建logs-2019.08.28-1索引,別名為logs_write:
#?PUT?/
3. 日期計算:
日期計算的格式為:
參數說明為:
日期計算表達式只支持公歷。
必須將 date math 索引名稱表達式包含在尖括號中,并且所有的特殊字符都應進行 URI 編碼。例如 :
GET?/%3Clogstash?-?%7Bnow?%2Fd?%7D?%3E?/?_search? ?{ ????"query":?{ ????????"match":?{ ????????????"test":?"data" ????????} ????} }
用于日期計算的特殊字符必須按照如下 URI 編碼 :
以下示例顯示了不同形式索引表達式和它們解析的最終索引名稱,給定的當前時間是 2024 年 3 月 22 日 utc。
如果索引中要使用{},需要使用反斜杠“\”進行轉義處理,例如:
4. 自定義的索引名稱:如果索引名稱不滿足以-加數字結尾,比如log,此時如果不指定新的索引名稱請求會報錯,自定義新的索引名稱請求如下:
POST?/test/_rollover/log_new? { ????"conditions":?{ ????????"max_age":?"1m", ????????"max_docs":?"1000", ????????"max_size":?"5gb" ????} }
如果滾動成功的話會生成log_new索引。
設置新的索引:
索引滾動時新的索引會根據匹配到的索引模板自動設置,也支持自定義的settings、mappings和aliases設定。請求中的設定值將會覆蓋索引模版中相同的設定,比如可以進行以下設定:
POST?/test/_rollover? ?{? ?"conditions":?{? ?"max_age":?"1m", ?"max_docs":"1000", ?"max_size":"5gb" ?}, ?"settings"?:{ ? "index.number_of_shards":2? ?} ?}
新的索引的index.number_of_shards將會被設置為2。
Dry運行:
滾動索引支持dry_run模式,可以在不執行實際滾動的情況下檢查請求條件:
POST?/test/_rollover?dry_run? ?{? ?"conditions":?{? ?"max_age":?"1m", ?"max_docs":"1000", ?"max_size":"5gb" ?}, ?"settings"?:{ ? "index.number_of_shards":2? ?} ?}
FusionInsight Elasticsearch EI企業智能
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。