文章目录
前言
新建、索引和删除请求都是写操作,写单个文档的流程如下:
- 客户端向协调节点发送写请求,ES的任意节点都可以作为协调节点(coordinating node)接受请求。
- 协调节点使用_routing(默认是文档ID)字段来确定文档属于的分片,通过集群状态中的内容路由表信息获知数据对应分片的主分片的节点,因此请求被转发到主分片节点上。
- 主分片执行写操作。如果写入成功,则它将请求并行转发到副分片上,等待返回结果。当所有的副分片都报告成功,主分片将向协调节点报告成功,协调节点再向客户端报告成功。
- 在客户端收到成功响应时,意味着写操作已经在主分片和所有副分片都执行完成。
下面以不同角色节点执行的任务整体流程进行分析。
协调节点流程
ES中接收并转发请求的节点称为coordinating节点,协调节点负责创建索引、转发请求到主分片节点、等待响应、回复客户端。实现位于TransportBulkAction,其入口是doExecute方法。
数据预处理pipeline请求
数据预处理(ingest)工作通过定义pipeline和processors实现。如果当前节点没有ingest角色,则需要将请求转发给有ingest角色的节点执行。
如果请求中指定了pipeline参数,则先使用相应的pipeline进行处理。否则查看该请求是否符合某个ingest pipeline的pattern,如果符合则执行pipeline中的逻辑。
// TransportBulkAction#doExecute
protected void doExecute(Task task, BulkRequest bulkRequest, ActionListener<BulkResponse> listener) {
...
for (DocWriteRequest<?> actionRequest : bulkRequest.requests) {
// 将IndexRequest和UpdateRequest都封装为IndexRequest,忽略DeleteRequest
IndexRequest indexRequest = getIndexWriteRequest(actionRequest);
if (indexRequest != null) {
// 如果请求中指定了pipeline,则返回pipeline,否则返回null
String pipeline = indexRequest.getPipeline();
// 如果请求中没有指定pipeline
if (pipeline == null) {
IndexMetaData indexMetaData = indicesMetaData.get(actionRequest.index());
if (indexMetaData != null) {
// 如果index已存在则查询默认定义的pipeline(如果有的话)
String defaultPipeline = IndexSettings.DEFAULT_PIPELINE.get(indexMetaData.getSettings());
indexRequest.setPipeline(defaultPipeline);
if (IngestService.NOOP_PIPELINE_NAME.equals(defaultPipeline) == false) {
hasIndexRequestsWithPipelines = true;
}
} else if (indexRequest.index() != null) {
// 如果index不存在(并且这是一个合法的请求),则匹配index模板以寻找默认的pipeline
List<IndexTemplateMetaData> templates = MetaDataIndexTemplateService.findTemplates(metaData, indexRequest.index());
assert (templates != null);
String defaultPipeline = IngestService.NOOP_PIPELINE_NAME;
// 模板的顺序是按模板IndexTemplateMetaData#order序号倒排,如果找到了defalut_pipeline则终止
for (IndexTemplateMetaData template : templates) {
final Settings settings = template.settings();
if (IndexSettings.DEFAULT_PIPELINE.exists(settings)) {
defaultPipeline = IndexSettings.DEFAULT_PIPELINE.get(settings);
break;
}
}
indexRequest.setPipeline(defaultPipeline);
if (IngestService.NOOP_PIPELINE_NAME.equals(defaultPipeline) == false) {
hasIndexRequestsWithPipelines = true;
}
}
} else if (IngestService.NOOP_PIPELINE_NAME.equals(pipeline) == false) {
hasIndexRequestsWithPipelines = true;
}
}
}
// 检查是否指定了 Pipeline 操作
if (hasIndexRequestsWithPipelines) {
// 该方法(doExecute)将会被再次调用,除了来自协调节点更新过的bulk请求,
// 以及除了每个带有IngestService.NOOP_PIPELINE_NAME的请求。
// 这确保了当第二次通过此方法时,该代码路径将不会生效。
try {
if (clusterService.localNode().isIngestNode()) {
// 如果本节点就是协调节点,则使用相应的pipeline进行处理
processBulkIndexIngestRequest(task, bulkRequest, listener);
} else {
// 如果本节点不是协调节点,则随机地转发给任一协调节点进行处理
ingestForwarder.forwardIngestRequest(BulkAction.INSTANCE, bulkRequest, listener);
}
} catch (Exception e) {
listener.on