[장치] Elasticsearch CCR 소스 코드 분석 (2 개)

한쪽 : [] CCR Elasticsearch 원본 소스 코드 분석 (a) .

sendShardChangesRequest있어서 결국 TRANSLOG에서 샤드 필요 복귀 동작 최신 샤드의 범위 내에서 모든 seq_no 동작을, 상기 판독 요청에 따라 함께 ShardChangesAction.TransportAction # shardOperation 체결 구.

        protected Response shardOperation(Request request, ShardId shardId) throws IOException {
            .......
            // 获取Operation
            final Translog.Operation[] operations = getOperations(
                    indexShard,
                    seqNoStats.getGlobalCheckpoint(),
                    request.getFromSeqNo(),
                    request.getMaxOperationCount(),
                    request.getExpectedHistoryUUID(),
                    request.getMaxBatchSize());
            // 在快照操作完成之后,确保maxSeqNoOfUpdatesOrDeletes,索引元数据,mapping和setting是最新的
            final long maxSeqNoOfUpdatesOrDeletes = indexShard.getMaxSeqNoOfUpdatesOrDeletes();
            final IndexMetaData indexMetaData = indexService.getMetaData();
            final long mappingVersion = indexMetaData.getMappingVersion();
            final long settingsVersion = indexMetaData.getSettingsVersion();
            return getResponse(......);
        }

첫 번째 테스트 매개 변수를 다음 조작 내부 스냅 샷을 통과, 스냅 샷 TRANSLOG를 작성하고 배치의 최대 한도를 초과까지 추가 : 다음과 같이 인수 작업.

    static Translog.Operation[] getOperations(....) throws IOException {
        .....// 参数检验
        int seenBytes = 0;
        long toSeqNo = Math.min(globalCheckpoint, (fromSeqNo + maxOperationCount) - 1);
        final List<Translog.Operation> operations = new ArrayList<>();
        // 创建Translog快照,根据translog快照读取Operation
        try (Translog.Snapshot snapshot = indexShard.newChangesSnapshot("ccr", fromSeqNo, toSeqNo, true)) {
            Translog.Operation op;
            while ((op = snapshot.next()) != null) {
                operations.add(op);
                seenBytes += op.estimateSize();
                if (seenBytes > maxBatchSize.getBytes()) {
                    break;
                }
            }
        } catch (MissingHistoryOperationsException e) {
            ......
        }
        return operations.toArray(EMPTY_OPERATIONS_ARRAY);
    }

sendShardChangesRequest handleReadResponse은 응답 방식에 의한 처리 방법을 스누핑.

void handleReadResponse(long from, long maxRequiredSeqNo, ShardChangesAction.Response response) {
    	// 处理read response
        Runnable handleResponseTask = () -> innerHandleReadResponse(from, maxRequiredSeqNo, response);
        // 更新follow index mapping
        Runnable updateMappingsTask = () -> maybeUpdateMapping(response.getMappingVersion(),handleResponseTask);
        // 更新follow index settings
        maybeUpdateSettings(response.getSettingsVersion(), updateMappingsTask);
    }

응답 동작이 sendShardChangesRequest 요구를 재전송하지 않을 경우, 판독 응답을 처리하는 통화 innerHandleReadResponse있어서, 내부에 첨가 버퍼 내부의 모든 작업 달리 응답하고, 기록 처리를 입력한다.

    synchronized void innerHandleReadResponse(long from, long maxRequiredSeqNo, ShardChangesAction.Response response) {
        .......
        if (response.getOperations().length == 0) { 
            newFromSeqNo = from;
        } else {
            List<Translog.Operation> operations = Arrays.asList(response.getOperations());
            long operationsSize = operations.stream().mapToLong(Translog.Operation::estimateSize).sum();
            buffer.addAll(operations);
            bufferSizeInBytes += operationsSize;
            final long maxSeqNo = response.getOperations()[response.getOperations().length - 1].seqNo();
            newFromSeqNo = maxSeqNo + 1;
            lastRequestedSeqNo = Math.max(lastRequestedSeqNo, maxSeqNo);
            coordinateWrites();//进入write
        }
        if (newFromSeqNo <= maxRequiredSeqNo && isStopped() == false) {
            int newSize = Math.toIntExact(maxRequiredSeqNo - newFromSeqNo + 1);
            sendShardChangesRequest(newFromSeqNo, newSize, maxRequiredSeqNo); //重新发送请求
        } else {
            numOutstandingReads--;
            coordinateReads(); //重新进入read
        }
    }

또한, 기록 프로세스가 먼저 기록 용량의 전체 후 내부로부터의 ArrayList 내부 버퍼 큐에 추가 된 모든 조작 OPS를 통과 여부를 결정하고, 요청 sendBulkShardOperationsRequest 통해 일어난다.

    private synchronized void coordinateWrites() {
        ......
        while (hasWriteBudget() && buffer.isEmpty() == false) {
            long sumEstimatedSize = 0L;
            int length = Math.min(params.getMaxWriteRequestOperationCount(), buffer.size());
            List<Translog.Operation> ops = new ArrayList<>(length);
            for (int i = 0; i < length; i++) {
                Translog.Operation op = buffer.remove();
                ops.add(op);
                sumEstimatedSize += op.estimateSize();
                if (sumEstimatedSize > params.getMaxWriteRequestSize().getBytes()) {
                    break;
                }
            }
            bufferSizeInBytes -= sumEstimatedSize;
            numOutstandingWrites++;
            // 发送bulk写请求
            sendBulkShardOperationsRequest(ops, leaderMaxSeqNoOfUpdatesOrDeletes, new AtomicInteger(0));
        }
    }

TransportBulkShardOperationsAction 클래스가되는 기본 슬라이스와 슬라이스의 사본을 쓰기 시작, TransportBulkShardOperationsAction TransportWriteAction 클래스를 상속.
그림 삽입 설명 여기
서면 절차 및 일반 일괄 계약을 작성하지만, shardOperationOnPrimary 및 shardOperationOnReplica 방법을 다시 썼다. 성공적인 업데이트 동기화 TRANSLOG 위치를 작성 후,를 통해 차 TRANSLOG 파일 재생을 작성하고 replicaRequest을 구축 할 수 있습니다. 기록 프로세스의 사본은 상기 직접 기록 좋은 replicaRequest에 따라 구축 하였다.

    public static CcrWritePrimaryResult shardOperationOnPrimary(....) throws IOException {
        ......
        final List<Translog.Operation> appliedOperations = new ArrayList<>(sourceOperations.size());
        Translog.Location location = null;
        for (Translog.Operation sourceOp : sourceOperations) {
            final Translog.Operation targetOp = rewriteOperationWithPrimaryTerm(sourceOp, primary.getOperationPrimaryTerm()); //包含操作类型,和相关的信息以及source
            final Engine.Result result = primary.applyTranslogOperation(targetOp, Engine.Operation.Origin.PRIMARY);  // 通过重放translog文件,最终进入到了写primary的逻辑
            if (result.getResultType() == Engine.Result.Type.SUCCESS) {
                appliedOperations.add(targetOp);
                location = locationToSync(location, result.getTranslogLocation());  // 写入成功的话更新同步translog location
            } else {
                ......
            }
        }
        // 写入主分片成功之后,构建replicaRequest
        final BulkShardOperationsRequest replicaRequest = new BulkShardOperationsRequest(
            shardId, historyUUID, appliedOperations, maxSeqNoOfUpdatesOrDeletes);
        return new CcrWritePrimaryResult(replicaRequest, location, primary, logger);  //更新Checkpoint,SeqNo
    }

    public static WriteReplicaResult<BulkShardOperationsRequest> shardOperationOnReplica(.....) throws IOException {
        Translog.Location location = null;
        for (final Translog.Operation operation : request.getOperations()) {
            final Engine.Result result = replica.applyTranslogOperation(operation, Engine.Operation.Origin.REPLICA);  //进入到写数据流程
            if (result.getResultType() != Engine.Result.Type.SUCCESS) {
              .....
            }
            location = locationToSync(location, result.getTranslogLocation());// 写入成功的话更新同步translog location
        }
        return new WriteReplicaResult<>(request, location, null, replica, logger);
    }

버퍼가 미리 측정 된 경우 handleWriteResponse 리스너 방법 및 numOutstandingWrites까지 처리 영하 1 numOutstandingWrites 성공적인 당 처리 결과 sendBulkShardOperationsRequest가 0 인, 지속적인 판독된다.

private synchronized void handleWriteResponse(final BulkShardOperationsResponse response) {
        this.followerGlobalCheckpoint = Math.max(this.followerGlobalCheckpoint, response.getGlobalCheckpoint());
        this.followerMaxSeqNo = Math.max(this.followerMaxSeqNo, response.getMaxSeqNo());
        numOutstandingWrites--;
        assert numOutstandingWrites >= 0;
        coordinateWrites();
        // 缓冲区有预量时开始读取
        coordinateReads();
    }

일반적으로, 종동 샤드 seq_no의 범위 내에서, 판독 요청을 전송 : 작업이 가능 새로운 리더 샤드 있으면, 프레스 구성 파라미터는, 다음 기록 데이터를 상기 응답을 제한하기 위해, 새로운 리더 샤드 동작하는 경우 사용할 수없는, 그 타임 아웃 될 때까지 기다린 새로운 운영 즉시 다음, 제한 시간 내에 새로운 동작에 반응 발생했을 경우, 그렇지 않으면 타임 아웃이 새로운 동작을 샤딩하지 추종자 응답 할 것이다 경우.

프로세스는 버퍼에 의해 캐시 버퍼에 읽기 및 쓰기합니다 : 버퍼가 SEQNO으로 분류 우선 순위 큐이다.

private final Queue<Translog.Operation> buffer = new PriorityQueue<>(Comparator.comparing(Translog.Operation::seqNo));

4 요약

  1. CCR 방식으로 위젯 커널 침입을 수정하지 않습니다,로드 및 사용;
  2. 복제의 전액을 복원 스냅 샷을 방법을 사용;
  3. 증분 복제 프로세스의 사용은 모든 운영을 얻고 TRANSLOG 트랜잭션 내부 로그 로컬 클러스터에서 원격 클러스터에 데이터를 기록하는;
  4. 복제 샤드 수준이기 때문에 각 샤드는 자신의 추종자 파편 작업이 있습니다;
  5. 클러스터 간의 데이터 일관성 seq_no GlobalCheckpoint에 의해 확인하는 단계;
  6. ES 세그먼트 파일은 모든 soft_deletes 사용 seq_no의 변화, 12 시간 동안 기본 보존으로 이어질 것입니다, 삭제 또는 일부의 문서 병합 프로세스 관련 작업에 업데이트 될 수 있습니다.
게시 31 개 원래 기사 · 원 찬양 65 ·은 50000 +를 볼

추천

출처blog.csdn.net/wudingmei1023/article/details/104064469