021.Elasticsearch索引管理高級篇

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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市庭瑰,隨后出現(xiàn)的幾起案子星持,更是在濱河造成了極大的恐慌,老刑警劉巖弹灭,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件督暂,死亡現(xiàn)場離奇詭異,居然都是意外死亡穷吮,警方通過查閱死者的電腦和手機(jī)逻翁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捡鱼,“玉大人八回,你說我怎么就攤上這事。” “怎么了缠诅?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵溶浴,是天一觀的道長。 經(jīng)常有香客問我管引,道長士败,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任褥伴,我火速辦了婚禮谅将,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘重慢。我一直安慰自己饥臂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布似踱。 她就那樣靜靜地躺著隅熙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪屯援。 梳的紋絲不亂的頭發(fā)上猛们,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機(jī)與錄音狞洋,去河邊找鬼弯淘。 笑死,一個胖子當(dāng)著我的面吹牛吉懊,可吹牛的內(nèi)容都是我干的庐橙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼借嗽,長吁一口氣:“原來是場噩夢啊……” “哼态鳖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起恶导,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤浆竭,失蹤者是張志新(化名)和其女友劉穎羹蚣,沒想到半個月后爆存,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苔咪,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡忧设,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了恢恼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姻乓。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡砂碉,死狀恐怖蕉拢,靈堂內(nèi)的尸體忽然破棺而出特碳,到底是詐尸還是另有隱情诚亚,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布午乓,位于F島的核電站站宗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏益愈。R本人自食惡果不足惜份乒,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腕唧。 院中可真熱鬧,春花似錦瘾英、人聲如沸枣接。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽但惶。三九已至,卻和暖如春湿蛔,著一層夾襖步出監(jiān)牢的瞬間膀曾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工阳啥, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留添谊,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓察迟,卻偏偏與公主長得像斩狱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子扎瓶,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,647評論 2 354