ES做爲線上服務的重要組件,索引重建時通常要求零停機。經過藍綠部署,咱們能實現安全的在ES集羣中進行流量瞬間無縫切換,實現零停機部署。php
每次生產部署進行以下操做:安全
別名指向
至以下兩個實際索引
部署開始: PUT /my_index_blue # 實際索引_藍 建立 | V 1. 別名切換進行藍綠部署 2. DELETE /my_index_green #刪除舊索引 | V GET /my_index/_search #生產環境使用部署更新後的索引 | V 新一輪部署: PUT /my_index_green # 實際索引_綠 建立 | V 1. 別名切換進行藍綠部署 2. DELETE /my_index_blue #刪除舊索引 | V GET /my_index/_search #生產環境使用部署更新後的索引 | V 循環以上流程。。。
一個別名能夠指向多個索引,因此別名切換進行藍綠部署時,咱們要原子化操做「增長新別名 & 刪除舊別名」app
# 在一個原子操做中完成別名切換 POST /_aliases { "actions": [ { "remove": { "index": "my_index_blue", "alias": "my_index" }}, { "add": { "index": "my_index_green", "alias": "my_index" }} ] }
咱們約定每一個模型表獨佔一個INDEX空間設計
<?php trait EsSearchable { use Elasticquent\ElasticquentTrait; public static function getIndex(){ return static::index; } public static function setIndex($index){ return static::index = $index; } public static function getType(){ return static::type; } public static function setType($type){ return static::type = $type; } } class Foo extends \App\Models\Model { use EsSearchable; protected static $index = 'foo_index'; protected static $type = 'foo_type'; // protected $indexSettings = []; // protected $mappingProperties = []; } ########################################################################## $aliasIndex = Foo::getIndex(); $actualIndexes = [ $aliasIndex . '_blue', $aliasIndex . '_green', ]; $fromIndex = \ES::indices()->existsAlias(['name'=>$aliasIndex, 'index'=>$actualIndexes[0]]) ? array_shift($actualIndexes) : array_pop($actualIndexes); $toIndex = current($actualIndexes); createIndexByModel($toIndex, Foo::class); ModelDocsToIndex($toIndex, Foo::class); switchIndexAlias($aliasIndex, $fromIndex, $toIndex); deleteIndexByModel($fromIndex, Foo::class); /** * 索引文檔至指定索引空間 */ function ModelDocsToIndex($index, $modelCls){ $originIndex = $modelCls::getIndex(); $modelCls::setIndex($index); $modelCls::chunk(1000, function(Collection $collection){ $collection->->addToIndex(); }); $modelCls::setIndex($originIndex); } /** * 藍綠部署切換:改變索引別名的指向 */ function switchIndexAlias($aliasIndex, $fromIndex, $toIndex){ $params = [ 'body' => [ 'actions' => [ 'remove' => ['index' => $fromIndex, 'alias' => $aliasIndex], 'add' => ['index' => $toIndex, 'alias' => $aliasIndex], ] ] ]; \ES::indices()->updateAliases($params); } /** * 新建索引(配置同指定模型) */ function createIndexByModel($index, $modelCls){ $originIndex = $modelCls::getIndex(); $modelCls::setIndex($index); $modelCls::createIndex(); $modelCls::setIndex($originIndex); } /** * 刪除索引(配置同指定模型) */ function deleteIndexByModel($index, $modelCls){ $originIndex = $modelCls::getIndex(); $modelCls::setIndex($index); $modelCls::deleteIndex(); $modelCls::setIndex($originIndex); }