Skip to content

Commit 6fa05ff

Browse files
authored
[ISSUE #9921] Limit the concurrency of Pop revive (#9922)
1 parent 8c7bf52 commit 6fa05ff

File tree

2 files changed

+27
-2
lines changed

2 files changed

+27
-2
lines changed

broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import java.util.concurrent.ConcurrentHashMap;
6666
import java.util.concurrent.ConcurrentMap;
6767
import java.util.concurrent.LinkedBlockingQueue;
68+
import java.util.concurrent.Semaphore;
6869
import java.util.concurrent.TimeUnit;
6970
import java.util.concurrent.atomic.AtomicBoolean;
7071
import java.util.concurrent.atomic.AtomicLong;
@@ -533,6 +534,7 @@ public CompletableFuture<Boolean> revive(PopConsumerRecord record) {
533534
});
534535
}
535536

537+
@SuppressWarnings("StatementWithEmptyBody")
536538
public void clearCache(String groupId, String topicId, int queueId) {
537539
while (consumerLockService.tryLock(groupId, topicId)) {
538540
}
@@ -551,12 +553,26 @@ public long revive(AtomicLong currentTime, int maxCount) {
551553
List<PopConsumerRecord> consumerRecords = this.popConsumerStore.scanExpiredRecords(
552554
currentTime.get() - TimeUnit.SECONDS.toMillis(3), upperTime, maxCount);
553555
long scanCostTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
556+
557+
// When reading messages from local storage, the current thread is used
558+
// directly for data retrieval. When reading original messages from remote
559+
// storage (such as distributed file systems), so concurrency needs to be
560+
// controlled via semaphore.
561+
Semaphore semaphore = new Semaphore(brokerConfig.getPopReviveConcurrency());
554562
Queue<PopConsumerRecord> failureList = new LinkedBlockingQueue<>();
555563
List<CompletableFuture<?>> futureList = new ArrayList<>(consumerRecords.size());
556564

557565
// could merge read operation here
558566
for (PopConsumerRecord record : consumerRecords) {
559-
futureList.add(this.revive(record).thenAccept(result -> {
567+
CompletableFuture<Boolean> future;
568+
try {
569+
semaphore.acquire();
570+
future = this.revive(record);
571+
} catch (Exception e) {
572+
semaphore.release();
573+
throw new RuntimeException(e);
574+
}
575+
futureList.add(future.thenAccept(result -> {
560576
if (!result) {
561577
if (record.getAttemptTimes() < brokerConfig.getPopReviveMaxAttemptTimes()) {
562578
long backoffInterval = 1000L * REWRITE_INTERVALS_IN_SECONDS[
@@ -572,7 +588,7 @@ public long revive(AtomicLong currentTime, int maxCount) {
572588
log.error("PopConsumerService drop record, message may be lost, record={}", record);
573589
}
574590
}
575-
}));
591+
}).whenComplete((result, ex) -> semaphore.release()));
576592
}
577593

578594
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();

common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ public class BrokerConfig extends BrokerIdentity {
249249
private boolean popConsumerKVServiceInit = false;
250250
private boolean popConsumerKVServiceEnable = false;
251251
private int popReviveMaxReturnSizePerRead = 16 * 1024;
252+
private int popReviveConcurrency = 32;
252253
private int popReviveMaxAttemptTimes = 16;
253254
// each message queue will have a corresponding retry queue
254255
private boolean useSeparateRetryQueue = false;
@@ -674,6 +675,14 @@ public void setPopConsumerKVServiceEnable(boolean popConsumerKVServiceEnable) {
674675
this.popConsumerKVServiceEnable = popConsumerKVServiceEnable;
675676
}
676677

678+
public int getPopReviveConcurrency() {
679+
return popReviveConcurrency;
680+
}
681+
682+
public void setPopReviveConcurrency(int popReviveConcurrency) {
683+
this.popReviveConcurrency = popReviveConcurrency;
684+
}
685+
677686
public int getPopReviveMaxReturnSizePerRead() {
678687
return popReviveMaxReturnSizePerRead;
679688
}

0 commit comments

Comments
 (0)