ES的delete api使用很是簡單。node
curl -XDELETE 'http://localhost:9200/index/type/doc_id'
前面學習了get api
的主要流程,這裏探索一下delete api
的實現原理。 優先選擇delete api
而非index api
, 主要是以爲刪除貌似更容易, 選擇delete api
學習曲線應該比較平緩。api
ES相關功能Action的命名很統一, 好比get api
, 對應實現類的名稱爲TransportGetAction
, delete api
對應實現類的名稱也是依樣畫葫蘆: TransportDeleteAction
。 curl
可是學習TransportDeleteAction, 其核心流程在其父類: TransportReplicationAction
。 我的以爲這個名字起得很差,讓人覺得是隻會在副本上執行相關功能的意思。ide
瞭解TransportReplicationAction
以前,先說一下delete api
的執行流程,就是劇透結果,再解析劇情。學習
從ES中刪除一個文檔的過程以下: 先從主分片中執行刪除操做,再在全部的副本分片上執行刪除操做。 因此核心流程分三步: s1: 從請求節點路由到主分片節點。 s2: 在主分片節點執行刪除操做。 s3: 在全部的副本分片上執行刪除操做。
按如上所述, 在TransportReplicationAction
類中,對應着三個子類:this
class name | 功能 |
---|---|
ReroutePhase | 將請求路由到primary 分片所在的節點 |
PrimaryPhase | 在主分片執行任務 |
ReplicationPhase | 在全部的replica分片上執行任務 |
這個結構是通用的,就像模板同樣。 這個類有個註釋,解釋了類的運行流程:url
/** * Base class for requests that should be executed on a primary copy followed by replica copies. * Subclasses can resolve the target shard and provide implementation for primary and replica operations. * * The action samples cluster state on the receiving node to reroute to node with primary copy and on the * primary node to validate request before primary operation followed by sampling state again for resolving * nodes with replica copies to perform replication. */
解釋起來有以下的關鍵幾點:插件
1. 基於該類的請求先會在primary shard執行,而後在replica shard執行。 2. 具體執行的操做由子類實現,好比`TransportDeleteAction`就實現了刪除的操做。 3. 每一個節點在執行相關的操做前須要基於cluster state對請求參數進行驗證。這個驗證對應的方法就是`resolveRequest`
基於這個流程,能夠看出,刪除操做仍是比較重量級的, 副本越多,刪除的代價就越大。 code
因爲ES每一個節點代碼都是同樣的,因此默認狀況下每一個節點的可扮演的角色是自由切換的。 這裏主要是在研讀transportService.sendRequest()
方法時的一個小竅門。 好比代碼:orm
void performOnReplica(final ShardRouting shard) { // if we don't have that node, it means that it might have failed and will be created again, in // this case, we don't have to do the operation, and just let it failover final String nodeId = shard.currentNodeId(); ... final DiscoveryNode node = nodes.get(nodeId); transportService.sendRequest(node, transportReplicaAction, ... ){ ... } }
這裏transportService.sendRequest()
後,接受的邏輯在哪裏呢?
transportService.registerRequestHandler(actionName, request, ThreadPool.Names.SAME, new OperationTransportHandler()); transportService.registerRequestHandler(transportPrimaryAction, request, executor, new PrimaryOperationTransportHandler()); // we must never reject on because of thread pool capacity on replicas transportService.registerRequestHandler(transportReplicaAction, replicaRequest, executor, true, true, new ReplicaOperationTransportHandler());
也就是說transportService.sendRequest()
的第二個參數action
和transportService.registerRequestHandler()
的第一個參數action
是一一對應的。
遇到transportService.sendRequest()
直接經過action
參數找到對應的Handler便可。好比PrimaryOperationTransportHandler
就是用於接收ReroutePhase().run()
方法中發送出去的請求。
回到TransportDeleteAction
, 來理解ES刪除的邏輯,整個類就只須要理解2個方法:
# 在primary shard執行的刪除邏輯 shardOperationOnPrimary() # 在replica shard執行的刪除邏輯 executeDeleteRequestOnReplica()
這裏面就是刪除的具體邏輯,Engine相關的內容後續再深刻。
關於刪除,ES提供的是delete by id
的思路。 早期ES是支持經過query批量刪除的,後來以爲這個功能太過危險,就將delete by query
作成了Plugin, 由用戶自行安裝插件後才能使用。 關於ES批量刪除的思路,能夠參考delete by query
插件的源碼,大致思路是經過scroll query
按條件查詢出doc id, 而後使用client.bulk()
進行刪除。
最後,因爲TransportReplicationAction
是個比較通用的模式,因此ES其餘的功能也是基於這個模式的, 好比: TransportIndexAction
。