혼란이 코드 공간을 덮쳤을 때 Alluxio가 어떤 블록 할당 전략을 채택할 것인지 알아보십시오.

여기에 이미지 설명 삽입

이번 호에서 공유된 주제: "Alluxio 블록 할당 전략에 대한 자세한 설명"
은 주로 [전략 세부 개요], [블록 할당 전략 소개], [코드 수준 해석]의 세 부분으로 소개
됩니다. 건조물↓

전략 상세 개요

Alluxio의 Worker는 사용자의 데이터 자원을 저장하는 역할을 하며, 데이터는 Worker의 스토리지 디렉토리(tiered storage)에 블록 형태로 저장됩니다. 레벨은 여러 디렉토리로 구성되어 있으므로 사용자가 Alluxio를 통해 데이터를 읽고 쓸 때 Alluxio는 블록을 넣을 디렉토리를 어떻게 결정합니까? 이 기사는 코드의 관점에서 블록 스토리지 디렉토리의 선택 프로세스를 분석합니다.

블록 할당 전략 소개

Alluxio는 블록 할당 정책을 사용하여 블록이 여러 스토리지 디렉토리(동일한 계층 또는 다른 계층)에 할당되는 방식을 정의합니다.

현재 알룩시오의 블록 할당 전략은 크게 3가지 유형이 있습니다.

  1. alluxio.worker.block.allocator.GreedyAllocator
    는 위에서 아래로 블록을 수용할 수 있는 첫 번째 저장소 디렉토리에 블록을 할당합니다.
  2. alluxio.worker.block.allocator.MaxFreeAllocator
    는 남은 여유 공간이 가장 큰 스토리지 디렉토리에 블록을 할당합니다.
  3. alluxio.worker.block.allocator.RoundRobinAllocator
    는 블록을 위에서 아래로 각 저장소 디렉토리로 반복합니다.
    사용되는 기본 정책은 MaxFreeAllocator이며 속성 alluxio.worker.allocator.class를 통해 변경할 수 있습니다.

코드 수준에서의 해석


블록에 스토리지 디렉토리 할당을 담당하는 코드 레벨의 assignSpace 함수는 assignSpace입니다 .
데이터를 읽고 쓸 때 작업자에 데이터를 저장해야 하는 경우 블록 할당 정책에 따라 데이터를 저장하기 위해 블록에 대한 저장소 디렉토리를 요청합니다.AllocateSpace는 먼저 수신 매개변수에 지정된 위치에서 데이터를 찾으려고 시도합니다. options(기본값은 level0). , 지정된 위치에 적절한 공간이 없으면 모든 저장소 디렉터리에서 찾으려고 시도합니다.

private StorageDirView allocateSpace(long sessionId, AllocateOptions options)
      throws WorkerOutOfSpaceException, IOException {
      while (true) {
        if (options.isForceLocation()) {
            //...
        } else {
            //...
            dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(),
                options.getLocation(), allocatorView, false);
            if (dirView != null) {
              return dirView;
            }
            dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(),
                BlockStoreLocation.anyTier(), allocatorView, false);
            if (dirView != null) {
              return dirView;
            }
      }
        //...
}

위에서 설명한 assignSpace 에 의해 선택된 저장소 디렉토리는 동적 계산에 의해 얻어지는 것을 알 수 있지만, 어느 시점에서 데이터는 또한 지정된 저장소 디렉토리 또는 레벨에 기록될 수 있으므로, assignSpace 도 evict Block을 지원하여 저장소 디렉토리가 여유 공간을 확보할 수 있도록 합니다. 새 데이터를 수용할 수 있는 충분한 공간(나중에 자세히 설명).

private StorageDirView allocateSpace(long sessionId, AllocateOptions options) {
    StorageDirView dirView;
//...
    while (true) {
      if (options.isForceLocation()) {
        dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(),
            options.getLocation(), allocatorView, true);
        if (dirView != null) {
          return dirView;
        }
        freeSpace(sessionId, options.getSize(), options.getSize(), options.getLocation());
        dirView = mAllocator.allocateBlockWithView(sessionId, options.getSize(),
                      options.getLocation(), allocatorView.refreshView(), true);        
        //...
        }
      }
      //...
      } else {
        //...
      }
      return dirView;
    }
  }

특별히 assignSpace에서 적절한 저장소 디렉토리를 찾는 클래스는 Allocator 인터페이스의 여러 구현 클래스이며, 이는 이전 장에서 제안된 여러 블록 할당 전략입니다. GreedyAllocator/MaxFreeAllocator/RoundRobinAllocator

할당자

public interface Allocator {

  //...
  StorageDirView allocateBlockWithView(long sessionId, long blockSize, BlockStoreLocation location,
        BlockMetadataView view, boolean skipReview);
}

Allocator 인터페이스의 assignBlockWithView는 주로 적절한 저장소 디렉토리를 찾는 역할을 합니다. 주의해야 할 매개변수는 주로 세 가지입니다:
✓ blockSize: 할당하려는 공간
✓ 위치: 공간을 할당할 위치
✓ skipReview: 검토를 건너뛰고
기본 alluxio.worker.block.allocator.MaxFreeAllocator#MaxFreeAllocator를 예로 사용하면 모든 위치에서 저장소 디렉터리를 찾고자 하면 모든 저장소 디렉터리를 하나씩 검사하고 가장 큰 값을 반환하는 것을 알 수 있습니다. 하나:

private StorageDirView allocateBlock(long sessionId, long blockSize,
      BlockStoreLocation location, boolean skipReview) {

    if (location.equals(BlockStoreLocation.anyTier())) {
      for (StorageTierView tierView : mMetadataView.getTierViews()) {
        candidateDirView = getCandidateDirInTier(tierView, blockSize, BlockStoreLocation.ANY_MEDIUM);
        if (candidateDirView != null) { // Review
          if (skipReview || mReviewer.acceptAllocation(candidateDirView)) {
            break;
          }
        }
      }
    } 
    //...
    return candidateDirView;
  }

private StorageDirView getCandidateDirInTier(StorageTierView tierView,
      long blockSize, String mediumType) {
    StorageDirView candidateDirView = null;
    long maxFreeBytes = blockSize - 1;
    for (StorageDirView dirView : tierView.getDirViews()) {
      if ((mediumType.equals(BlockStoreLocation.ANY_MEDIUM)
          || dirView.getMediumType().equals(mediumType))
          && dirView.getAvailableBytes() > maxFreeBytes) {
        maxFreeBytes = dirView.getAvailableBytes();
        candidateDirView = dirView;
      }
    }
    return candidateDirView;
  }

코드를 보면 알 수 있듯 CandidateDirView가 발견되면 최종적으로 어떤 저장소 디렉토리를 반환할지 결정하기 위해 Review 과정을 거쳐야 하는데, Review 과정은 어떤 용도로 사용되는 것일까요?

블록 할당 검토 정책
검토는 블록 할당 전략에 대한 보완으로, 블록 할당 전략에 몇 가지 추가 제한(예: SoftLimit/HardLimit)과 임의성을 부여합니다. 현재 Alluxio에는 두 가지 검토 전략이 있습니다.

  1. alluxio.worker.block.reviewer.AcceptingReviewer
    는 모든 리뷰를 직접 통과하며 이는 리뷰 없음과 동일합니다.
  2. alluxio.worker.block.reviewer.ProbabilisticBufferReviewer
    는 현재 사용 가능한 공간의 남은 크기에 따라 Reviewer의 이전 할당 결과를 검토합니다.

기본 ProbabilisticBufferReviewer를 살펴보십시오.

public class ProbabilisticBufferReviewer implements Reviewer {
    //...
    double getProbability(StorageDirView dirView) {
        //...
        if (availableBytes > mSoftLimitBytes) {
          return 1.0;
        }
        if (availableBytes <= mHardLimitBytes) {
          return 0.0;
        }
    
        double x = capacityBytes - availableBytes;
        double k = 1.0 / (mHardLimitBytes - mSoftLimitBytes); // If HardLimit = SoftLimit, then we would have returned in the previous if-else
        double b = (capacityBytes - mHardLimitBytes + 0.0) / (mSoftLimitBytes - mHardLimitBytes);
        double y = k * x + b;
        return y;
      }
}

ProbabilisticBufferReviewer

  • 현재 저장소 디렉터리의 남은 공간이 mHardLimitBytes보다 작으면 직접 0을 반환하여 검토가 통과되지 않았음을 나타냅니다.
  • 현재 저장소 디렉터리의 남은 공간이 mSoftLimitBytes보다 크면 직접 1을 반환하여 검토를 통과했음을 나타냅니다.
  • 나머지 공간 크기가 mHardLimitBytes와 mSoftLimitBytes 사이이면 (0, 1) 사이의 값이 반환됩니다.


위에서 언급한 FreeSpace 는 assignSpace가 evict Block을 지원하여 스토리지 디렉토리가 새 데이터를 수용할 수 있는 충분한 공간을 만들 수 있도록 합니다. 그렇다면 축출이 수행될 때 축출할 블록을 결정하는 방법은 무엇입니까?

Evict Block은 freeSpace를 통해 이루어지며, 공간이 부족하면 충분한 공간이 비워질 때까지 freeSpace에서 블록을 하나씩 제거합니다.

public synchronized void freeSpace(long sessionId, long minContiguousBytes,
      long minAvailableBytes, BlockStoreLocation location) {
    Iterator<Long> evictionCandidates = mBlockIterator.getIterator(location, BlockOrder.NATURAL);
    while (true) {
      //...
      if (contiguousSpaceFound && availableBytesFound) {
        break;
      }

      if (!evictionCandidates.hasNext()) {
        break;
      }
      long blockToDelete = evictionCandidates.next();
      if (evictorView.isBlockEvictable(blockToDelete)) { // 有一些 block 是不会被 evict 的
        try {
          BlockMeta blockMeta = mMetaManager.getBlockMeta(blockToDelete);
          removeBlockFileAndMeta(blockMeta);
          //...
      }
    //...
  }

물론 제거되지 않는 몇 가지 블록이 있습니다.

public boolean isBlockEvictable(long blockId) {
    boolean pinned = isBlockPinned(blockId);
    boolean locked = isBlockLocked(blockId);
    boolean marked = isBlockMarked(blockId);
    boolean isEvictable = !pinned && !locked && !marked;
    if (!isEvictable) {
      LOG.debug("Block not evictable: {}. Pinned: {}, Locked: {}, Marked: {}", blockId, pinned,
          locked, marked);
    }

    return isEvictable;
  }

현재 두 가지 유형의 퇴거 규칙이 있습니다.

  1. alluxio.worker.block.annotator.LRUAnnotator
    LRU 규칙, 즉 가장 먼저 제거되는 규칙은 가장 오랫동안 액세스되지 않은 규칙입니다.
  2. alluxio.worker.block.annotator.LRFUAnnotator
    는 LRFU 및 LRU 규칙과 결합될 수 있으며, LRFU 또는 LRU에 가까운 규칙을 만들기 위해 매개변수를 전달할 수도 있습니다.

사용된 기본 전략은 LRUAnnotator이며 속성 alluxio.worker.block.annotator.class를 통해 변경할 수 있습니다.
기본 LRUAnnotator를 살펴보십시오.

public class LRUAnnotator implements BlockAnnotator<LRUAnnotator.LRUSortedField> {
  private static final Logger LOG = LoggerFactory.getLogger(LRUAnnotator.class);

  private AtomicLong mLRUClock;

  @Override
  public BlockSortedField updateSortedField(long blockId, LRUSortedField oldValue) {
    long clockValue = mLRUClock.incrementAndGet();
    return new LRUSortedField(clockValue);
  }

  /**
   * Sorted-field for LRU.
   */
  protected class LRUSortedField implements BlockSortedField {
    private Long mClockValue;

    private LRUSortedField(long clockValue) {
      mClockValue = clockValue;
    }

    @Override
    public int compareTo(BlockSortedField o) {
      Preconditions.checkState(o instanceof LRUSortedField);
      return mClockValue.compareTo(((LRUSortedField) o).mClockValue);
    }
    //...
}

LRUAnnotator는 단조 증가하는 AtomicLong을 사용하여 각 블록의 접근 순서를 식별함을 알 수 있으며, AtomicLong이 클수록 더 빨리 접근된다.

{{o.name}}
{{m.name}}

Supongo que te gusta

Origin my.oschina.net/u/5904778/blog/5567182
Recomendado
Clasificación