1. 索引別名
在開發(fā)中磅甩,隨著業(yè)務(wù)需求的迭代糊识,較老的業(yè)務(wù)邏輯就要面臨更新甚至是重構(gòu),而對于ES來說堵未,為了適應(yīng)新的業(yè)務(wù)邏輯腋舌,可能就要對原有的索引做一些修改,比如對某些字段做調(diào)整渗蟹,甚至是重建索引侦厚,而做這些操作的時候,可能會對業(yè)務(wù)造成影響拙徽,甚至需要停機(jī)調(diào)整,由此诗宣,ES引入了索引別名來解決這些問題膘怕,索引別名就像一個快捷方式或是軟鏈接,可以指向一個或多個索引召庞,也可以給任意一個需要索引別名的API來使用岛心,別名的應(yīng)用為程序提供了極大的靈活性来破。
-
查詢別名
# 查詢所有索引的別名 GET _alias # 查詢某個索引的別名 GET /index_name/_alias
-
新增別名
# 方法一 POST /_aliases { "actions": [ { "add": { "index": "index_name", "alias": "index_name_v1.0" } } ] } # 方法二 PUT /index_name/_alias/index_name_v1.0
-
刪除別名
# 方法一 POST /_aliases { "actions": [ { "remove": { "index": "index_name", "alias": "index_name_v1.0" } } ] } # 方法二 DELETE /index_name/_alias/index_name_v1.0
-
重命名
POST /_aliases { "actions": [ { "remove": { "index": "index_name", "alias": "index_name_v1.0" } }, { "add": { "index": "index_name", "alias": "index_name_v2.0" } } ] }
-
多個索引指定一個別名
POST /_aliases { "actions": [ { "add": { "index": "index_name1", "alias": "alias_name" } }, { "add": { "index": "index_name2", "alias": "alias_name" } } ] }
-
一個索引指定多個別名
POST /_aliases { "actions": [ { "add": { "index": "index_name", "alias": "alias_name_1" } }, { "add": { "index": "index_name", "alias": "alias_name_2" } } ] }
-
通過別名查詢索引,如果多個索引都是這個別名忘古,那么就是查詢多個索引
GET /alias_name/_search { "query": {...} }
-
通過別名寫數(shù)據(jù)到索引
PUT /alias_name/type_name[/id] { data... } # 如果多個索引都是這個別名徘禁,那么可以指定具體寫入哪個索引 # is_write_index設(shè)置了此索引是可以通過此別名被寫入的索引 POST /_aliases { "actions": [ { "add": { "index": "index_name1", "alias": "alias_name", "is_write_index": true } }, { "add": { "index": "index_name2", "alias": "alias_name" } } ] }
2. 索引重建
Elasticsearch的索引在創(chuàng)建好之后其數(shù)據(jù)結(jié)構(gòu)和一些固有設(shè)置是不能修改的,如果一定要修改其數(shù)據(jù)結(jié)構(gòu)和某些設(shè)置例如主分片的個數(shù)髓堪,那么就必須重建索引送朱,ES提供了一些輔助工具來支持索引重建。
索引重建步驟:
- index_old取一個別名index_service干旁,index_service對外提供服務(wù)
- 新創(chuàng)建一個索引index_new驶沼,數(shù)據(jù)結(jié)構(gòu)與index_old一樣,但是根據(jù)需求修改了某些字段或者修改了某些設(shè)置
- 將index_old的數(shù)據(jù)同步到index_new
- 給index_new取別名index_service争群,刪除index_old的別名
- 刪除index_old
案例:
# 創(chuàng)建index_old
PUT index_old
{
"mappings": {
"_doc": {
"properties": {
"id": {"type": "long"},
"name": {"type": "text"}
}
}
}
}
POST /_bulk
{"index":{"_index":"index_old","_type":"_doc","_id":"1"}}
{"id": 1001, "name": "張三豐"}
{"index":{"_index":"index_old","_type":"_doc","_id":"2"}}
{"id": 1002, "name": "張無忌"}
{"index":{"_index":"index_old","_type":"_doc","_id":"3"}}
{"id": 1003, "name": "虛竹"}
{"index":{"_index":"index_old","_type":"_doc","_id":"4"}}
{"id": 1004, "name": "云中鶴"}
{"index":{"_index":"index_old","_type":"_doc","_id":"5"}}
{"id": 1005, "name": "楊過"}
# 此時我們要把name字段的類型由text修改為keyword回怜,就必須重建索引
# 1.index_old取一個別名index_service,index_service對外提供服務(wù)
POST /_aliases
{
"actions": [
{
"add": {
"index": "index_old",
"alias": "index_service"
}
}
]
}
# 2.新創(chuàng)建一個索引index_new换薄,數(shù)據(jù)結(jié)構(gòu)與index_old一樣玉雾,但是name字段的類型為keyword
PUT index_new
{
"mappings": {
"_doc": {
"properties": {
"id": {"type": "long"},
"name": {"type": "keyword"}
}
}
}
}
# 3.將index_old的數(shù)據(jù)同步到index_new
# ES6.X需要指定舊索引的type和新索引的type
POST /_reindex?wait_for_completion=false
{
"source": {
"index": "index_old",
"type": "_doc"
},
"dest": {
"index": "index_new",
"type": "_doc"
}
}
# ES7.X不需要指定type
POST /_reindex?wait_for_completion=false
{
"source": {
"index": "index_old"
},
"dest": {
"index": "index_new"
}
}
# wait_for_completion=true,同步執(zhí)行轻要,會一直等待直到同步完成或者報錯复旬,默認(rèn)
# wait_for_completion=false,異步執(zhí)行伦腐,返回taskId赢底,然后后臺進(jìn)行同步,數(shù)據(jù)量大的情況下建議使用
# 4.將index_old的別名刪除柏蘑,index_new的別名設(shè)置為index_service
POST /_aliases
{
"actions": [
{
"remove": {
"index": "index_old",
"alias": "index_service"
}
},
{
"add": {
"index": "index_new",
"alias": "index_service"
}
}
]
}
# 5.刪除index_old
DELETE /index_old
3. refresh幸冻、flush和merge
3.1 document寫入原理一
- 一個document先被寫入一個內(nèi)存buffer中
- 當(dāng)Buffer被寫滿或者到達(dá)一定時間后,執(zhí)行commit操作咳焚,將buffer中的所有數(shù)據(jù)寫入到segment中洽损,一個index在物理上就是由多個segment文件組成的,但此時將buffer中的數(shù)據(jù)寫到segment中革半,并非是寫入磁盤碑定,而是先寫到頁面緩存中,也就是OS Cache中
- 如果是刪除操作又官,那么在commit的時候延刘,會往.del文件中將此document標(biāo)記為"delete",搜索的時候六敬,比如搜索到id=1的文檔碘赖,發(fā)現(xiàn)在.del文件中已經(jīng)被標(biāo)記為"delete"了,就不會返回這條數(shù)據(jù)
- 如果是更新操作,那么commit的時候普泡,那么在.del文件中將舊數(shù)據(jù)標(biāo)記為"delete"(document是有版本的)播掷,然后將新數(shù)據(jù)寫入到新的segment中,查詢的時候返回最新版本的document
- 然后OS cache將segment刷寫到磁盤上撼班,形成segment文件歧匈,然后對這個segment文件執(zhí)行一個"open"操作,這個這個segment文件就可以用于搜索了砰嘁,同時刷寫到磁盤之后件炉,還會清空內(nèi)存buffer
3.2 document寫入原理二:refresh
上述流程是有問題的,從寫入一條document到OS Cache將segment刷寫到磁盤般码,并且該segment被打開允許搜索這個過程是有延遲的妻率,可能達(dá)到min級別,這就不是近實時的搜索了板祝,上述流程的主要瓶頸在于OS Cache將segment刷寫到磁盤的過程宫静,于是,我們想券时,只要數(shù)據(jù)被寫入OS Cache中了孤里,就可以被搜索,而不用刷寫到磁盤后才能搜索橘洞,這樣就可以提高搜索效率捌袜,索引刷新(refresh)功能就是讓某條數(shù)據(jù)在寫入OS Cache后就可以被搜索。
refresh默認(rèn)時間間隔是1s炸枣,也就是說每隔一秒虏等,將buffer中的數(shù)據(jù)寫入到OS Cache中,并且允許該數(shù)據(jù)被搜索适肠。
# 數(shù)據(jù)寫入就強(qiáng)制刷新
PUT /index_name/type_name/id?refresh
{
"data": "..."
}
# 設(shè)置index的刷新時間
PUT /index_name/_settings
{
"index": {
"refresh_interval": "5s"
}
}
3.3 document寫入原理三:translog和flush
在原理二的優(yōu)化之后霍衫,ES就可以滿足近實時的查詢效率,但是還有一個問題是可靠性侯养,因為document在真正的寫入磁盤之前都是在內(nèi)存中的敦跌,那么ES宕機(jī)就可能會丟失數(shù)據(jù),Translog文件可以解決這個問題:
改進(jìn)后得流程如下:
(1) document寫入buffer緩沖逛揩,同時寫入Translog日志文件
(2) 每隔1s柠傍,buffer中的數(shù)據(jù)被寫入新的segment,并進(jìn)入OS Cache辩稽,此時segment被打開并可以用于搜索
(3) buffer被清空
(4) 重復(fù)(1)-(3)惧笛,新的segment不斷添加,buffer不斷被清空逞泄,而translog中的數(shù)據(jù)不斷累加
(5) 當(dāng)translog的大小達(dá)到一定程度徐紧,觸發(fā)flush操作:
? (5-1) buffer中的所有數(shù)據(jù)寫入一個新的segment静檬,并寫入OS Cache,segment被打開并可以用于搜索
? (5-2) buffer被清空
? (5-3) 一個commit ponit文件被寫入磁盤并级,其中標(biāo)明了index當(dāng)前所有的segment有哪些
? (5-4) OS Cache中的所有segment緩存數(shù)據(jù),被強(qiáng)行刷寫到磁盤上
? (5-5) 現(xiàn)有的translog被清空侮腹,創(chuàng)建一個新的translog
基于Translog如何進(jìn)行數(shù)據(jù)恢復(fù)嘲碧?
ES宕機(jī)之后,內(nèi)存中的數(shù)據(jù)全部丟失父阻,重啟之后愈涩,上一次flush之后的全部數(shù)據(jù)都在Translog中保存著,將這些數(shù)據(jù)重新加載到內(nèi)存buffer中并形成一個個segment然后寫入OS Cache中即可加矛。
相關(guān)設(shè)置參數(shù)如下:
index.translog.durability:新增履婉、刪除,更新或批量操作之后是否寫入Translog并觸發(fā)flush操作
- request(默認(rèn)):每次請求都寫入Translog并觸發(fā)flush操作
- async:按照時間間隔來寫入Translog并觸發(fā)flush操作
index.translog.sync_interval:寫數(shù)據(jù)請求提交到Translog并觸發(fā)flush操作的時間間隔斟览,默認(rèn)5s毁腿,最小不能低于100ms
index.translog.flush_threshold_size:Translog觸發(fā)flush操作的文件大小閾值,默認(rèn)512mb
PUT /index_name/_settings
{
"index.translog.durability": "async",
"index.translog.sync_interval": "5s"
}
# 手動觸發(fā)flush操作
POST /index_name/_flush
3.4 document寫入原理四:segment merge
在上述寫入流程中苛茂,每秒生成一個segment已烤,segment數(shù)量太多,每次search都要搜索所有的segment妓羊,性能不好胯究,ES默認(rèn)會在后臺執(zhí)行segment merge操作,在merge的時候躁绸,被標(biāo)記為deleted的document也會被徹底物理刪除裕循,每次merge操作的執(zhí)行流程:
選擇一些有相似大小的segment,merge成一個大的segment
將新的segment flush到磁盤上去
寫一個新的commit point净刮,其中記錄著新的segment的元數(shù)據(jù)剥哑,刪除那些舊的segment的元數(shù)據(jù)
將新的segment打開用于搜索
將舊的segment刪除
手動執(zhí)行merge的API:
# max_num_segments指定了合并之后的segments個數(shù)
POST /index_name/_optimize?max_num_segments=1