[ISSUE-378][HugePartition][Part-2] Introduce memory usage limit and data flush by zuston · Pull Request #471 · apache/uniffle · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/server_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ This document will introduce how to deploy Uniffle shuffle servers.
|rss.server.leak.shuffledata.check.interval|3600000|The interval of leak shuffle data check (ms)|
|rss.server.max.concurrency.of.single.partition.writer|1|The max concurrency of single partition writer, the data partition file number is equal to this value. Default value is 1. This config could improve the writing speed, especially for huge partition.|
|rss.metrics.reporter.class|-|The class of metrics reporter.|
|rss.server.huge-partition.size.threshold|20g|Threshold of huge partition size, once exceeding threshold, memory usage limitation and huge partition buffer flushing will be triggered.|
|rss.server.huge-partition.memory.limit.ratio|0.2|The memory usage limit ratio for huge partition, it will only triggered when partition's size exceeds the threshold of 'rss.server.huge-partition.size.threshold'|

### Advanced Configurations
|Property Name|Default| Description |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package org.apache.uniffle.client.impl.grpc;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
Expand Down Expand Up @@ -179,8 +181,33 @@ private AppHeartBeatResponse doSendHeartBeat(String appId, long timeout) {
return blockingStub.withDeadlineAfter(timeout, TimeUnit.MILLISECONDS).appHeartbeat(request);
}

public long requirePreAllocation(int requireSize, int retryMax, long retryIntervalMax) {
RequireBufferRequest rpcRequest = RequireBufferRequest.newBuilder().setRequireSize(requireSize).build();
// Only for tests
@VisibleForTesting
public long requirePreAllocation(int requireSize, int retryMax, long retryIntervalMax) throws Exception {
return requirePreAllocation(
"EMPTY",
0,
Collections.emptyList(),
requireSize,
retryMax,
retryIntervalMax
);
}

public long requirePreAllocation(
String appId,
int shuffleId,
List<Integer> partitionIds,
int requireSize,
int retryMax,
long retryIntervalMax) {
RequireBufferRequest rpcRequest = RequireBufferRequest.newBuilder()
.setShuffleId(shuffleId)
.addAllPartitionIds(partitionIds)
.setAppId(appId)
.setRequireSize(requireSize)
.build();

long start = System.currentTimeMillis();
RequireBufferResponse rpcResponse = getBlockingStub().requireBuffer(rpcRequest);
int retry = 0;
Expand Down Expand Up @@ -282,6 +309,9 @@ public RssSendShuffleDataResponse sendShuffleData(RssSendShuffleDataRequest requ
List<ShuffleData> shuffleData = Lists.newArrayList();
int size = 0;
int blockNum = 0;
int shuffleId = stb.getKey();
List<Integer> partitionIds = new ArrayList<>();

for (Map.Entry<Integer, List<ShuffleBlockInfo>> ptb : stb.getValue().entrySet()) {
List<ShuffleBlock> shuffleBlocks = Lists.newArrayList();
for (ShuffleBlockInfo sbi : ptb.getValue()) {
Expand All @@ -298,14 +328,21 @@ public RssSendShuffleDataResponse sendShuffleData(RssSendShuffleDataRequest requ
shuffleData.add(ShuffleData.newBuilder().setPartitionId(ptb.getKey())
.addAllBlock(shuffleBlocks)
.build());
partitionIds.add(ptb.getKey());
}

final int allocateSize = size;
final int finalBlockNum = blockNum;
try {
RetryUtils.retry(() -> {
long requireId = requirePreAllocation(allocateSize, request.getRetryMax() / maxRetryAttempts,
request.getRetryIntervalMax());
long requireId = requirePreAllocation(
appId,
shuffleId,
partitionIds,
allocateSize,
request.getRetryMax() / maxRetryAttempts,
request.getRetryIntervalMax()
);
if (requireId == FAILED_REQUIRE_ID) {
throw new RssException(String.format(
"requirePreAllocation failed! size[%s], host[%s], port[%s]", allocateSize, host, port));
Expand Down
3 changes: 3 additions & 0 deletions proto/src/main/proto/Rss.proto
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ message FinishShuffleResponse {

message RequireBufferRequest {
int32 requireSize = 1;
string appId = 2;
int32 shuffleId = 3;
repeated int32 partitionIds = 4;
}

message RequireBufferResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,20 @@ public class ShuffleServerConf extends RssBaseConf {
.noDefaultValue()
.withDescription("The env key to get json source of local storage media provider");

public static final ConfigOption<Long> HUGE_PARTITION_SIZE_THRESHOLD = ConfigOptions
.key("rss.server.huge-partition.size.threshold")
.longType()
.defaultValue(20 * 1024 * 1024 * 1024L)
Comment thread
advancedxy marked this conversation as resolved.
.withDescription("Threshold of huge partition size, once exceeding threshold, memory usage limitation and "
+ "huge partition buffer flushing will be triggered.");

public static final ConfigOption<Double> HUGE_PARTITION_MEMORY_USAGE_LIMITATION_RATIO = ConfigOptions
.key("rss.server.huge-partition.memory.limit.ratio")
.doubleType()
.defaultValue(0.2)
.withDescription("The memory usage limit ratio for huge partition, it will only triggered when partition's "
+ "size exceeds the threshold of '" + HUGE_PARTITION_SIZE_THRESHOLD.key() + "'");

public ShuffleServerConf() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.grpc.Context;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import org.apache.commons.lang3.StringUtils;
import org.roaringbitmap.longlong.Roaring64NavigableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -353,7 +354,22 @@ public void finishShuffle(FinishShuffleRequest req,
@Override
public void requireBuffer(RequireBufferRequest request,
StreamObserver<RequireBufferResponse> responseObserver) {
long requireBufferId = shuffleServer.getShuffleTaskManager().requireBuffer(request.getRequireSize());
String appId = request.getAppId();
long requireBufferId;
if (StringUtils.isEmpty(appId)) {
// To be compatible with older client version
requireBufferId = shuffleServer.getShuffleTaskManager().requireBuffer(
request.getRequireSize()
);
} else {
requireBufferId = shuffleServer.getShuffleTaskManager().requireBuffer(
appId,
request.getShuffleId(),
request.getPartitionIdsList(),
request.getRequireSize()
);
}

StatusCode status = StatusCode.SUCCESS;
if (requireBufferId == -1) {
status = StatusCode.NO_BUFFER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ public class ShuffleTaskManager {
private Map<Long, PreAllocatedBufferInfo> requireBufferIds = Maps.newConcurrentMap();
private Runnable clearResourceThread;
private BlockingQueue<PurgeEvent> expiredAppIdQueue = Queues.newLinkedBlockingQueue();
// appId -> shuffleId -> serverReadHandler

public ShuffleTaskManager(
ShuffleServerConf conf,
Expand Down Expand Up @@ -200,7 +199,13 @@ public StatusCode registerShuffle(
public StatusCode cacheShuffleData(
String appId, int shuffleId, boolean isPreAllocated, ShufflePartitionedData spd) {
refreshAppId(appId);
return shuffleBufferManager.cacheShuffleData(appId, shuffleId, isPreAllocated, spd);
return shuffleBufferManager.cacheShuffleData(
appId,
shuffleId,
isPreAllocated,
spd,
this::getPartitionDataSize
Comment thread
advancedxy marked this conversation as resolved.
);
}

public PreAllocatedBufferInfo getAndRemovePreAllocatedBuffer(long requireBufferId) {
Expand Down Expand Up @@ -335,6 +340,27 @@ public Roaring64NavigableMap getCachedBlockIds(String appId, int shuffleId) {
return blockIds;
}

public long getPartitionDataSize(String appId, int shuffleId, int partitionId) {
ShuffleTaskInfo shuffleTaskInfo = shuffleTaskInfos.get(appId);
if (shuffleTaskInfo == null) {
return 0L;
}
return shuffleTaskInfo.getPartitionDataSize(shuffleId, partitionId);
}

public long requireBuffer(String appId, int shuffleId, List<Integer> partitionIds, int requireSize) {
ShuffleTaskInfo shuffleTaskInfo = shuffleTaskInfos.get(appId);
if (shuffleTaskInfo != null) {
for (int partitionId : partitionIds) {
long partitionUsedDataSize = getPartitionDataSize(appId, shuffleId, partitionId);
if (shuffleBufferManager.limitHugePartition(appId, shuffleId, partitionId, partitionUsedDataSize)) {
return -1;
}
}
}
return requireBuffer(requireSize);
}

public long requireBuffer(int requireSize) {
long requireId = -1;
if (shuffleBufferManager.requireMemory(requireSize, true)) {
Expand Down Expand Up @@ -630,5 +656,4 @@ private void triggerFlush() {
this.shuffleBufferManager.flushIfNecessary();
}
}

Comment thread
advancedxy marked this conversation as resolved.
}
Loading