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
8 changes: 8 additions & 0 deletions conf/broker.conf
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,14 @@ subscribeThrottlingRatePerConsumer=0
# Rate period for {subscribeThrottlingRatePerConsumer}. Default is 30s.
subscribeRatePeriodPerConsumerInSecond=30

# Default messages per second dispatch throttling-limit for whole broker. Using a value of 0, is disabling default
# message dispatch-throttling
dispatchThrottlingRateInMsg=0

# Default bytes per second dispatch throttling-limit for whole broker. Using a value of 0, is disabling
# default message-byte dispatch-throttling
dispatchThrottlingRateInByte=0

# Default messages per second dispatch throttling-limit for every topic. Using a value of 0, is disabling default
# message dispatch-throttling
dispatchThrottlingRatePerTopicInMsg=0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,20 @@ public class ServiceConfiguration implements PulsarConfiguration {
+ "when broker publish rate limiting enabled. (Disable byte rate limit with value 0)"
)
private long brokerPublisherThrottlingMaxByteRate = 0;
@FieldContext(
category = CATEGORY_SERVER,
dynamic = true,
doc = "Default messages per second dispatch throttling-limit for whole broker. "
+ "Using a value of 0, is disabling default message-byte dispatch-throttling"
)
private int dispatchThrottlingRateInMsg = 0;
@FieldContext(
category = CATEGORY_SERVER,
dynamic = true,
doc = "Default bytes per second dispatch throttling-limit for whole broker. "
+ "Using a value of 0, is disabling default message-byte dispatch-throttling"
)
private long dispatchThrottlingRateInByte = 0;
@FieldContext(
category = CATEGORY_SERVER,
dynamic = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.commons.lang3.tuple.Pair;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.intercept.BrokerInterceptor;
import org.apache.pulsar.broker.service.persistent.DispatchRateLimiter;
import org.apache.pulsar.broker.service.persistent.PersistentTopic;
import org.apache.pulsar.broker.service.plugin.EntryFilter;
import org.apache.pulsar.broker.service.plugin.EntryFilterWithClassLoader;
Expand Down Expand Up @@ -270,6 +271,26 @@ public void resetCloseFuture() {
// noop
}

protected abstract void reScheduleRead();

protected boolean reachDispatchRateLimit(DispatchRateLimiter dispatchRateLimiter) {
if (dispatchRateLimiter.isDispatchRateLimitingEnabled()) {
if (!dispatchRateLimiter.hasMessageDispatchPermit()) {
reScheduleRead();
return true;
}
}
return false;
}

protected Pair<Integer, Long> updateMessagesToRead(DispatchRateLimiter dispatchRateLimiter,
int messagesToRead, long bytesToRead) {
// update messagesToRead according to available dispatch rate limit.
return computeReadLimits(messagesToRead,
(int) dispatchRateLimiter.getAvailableDispatchRateLimitOnMsg(),
bytesToRead, dispatchRateLimiter.getAvailableDispatchRateLimitOnByte());
}

protected static Pair<Integer, Long> computeReadLimits(int messagesToRead, int availablePermitsOnMsg,
long bytesToRead, long availablePermitsOnByte) {
if (availablePermitsOnMsg > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ public class BrokerService implements Closeable {
private ScheduledExecutorService brokerPublishRateLimiterMonitor;
private ScheduledExecutorService deduplicationSnapshotMonitor;
protected volatile PublishRateLimiter brokerPublishRateLimiter = PublishRateLimiter.DISABLED_RATE_LIMITER;
protected volatile DispatchRateLimiter brokerDispatchRateLimiter = null;

private DistributedIdGenerator producerNameGenerator;

Expand Down Expand Up @@ -495,6 +496,7 @@ public void start() throws Exception {
this.startConsumedLedgersMonitor();
this.startBacklogQuotaChecker();
this.updateBrokerPublisherThrottlingMaxRate();
this.updateBrokerDispatchThrottlingMaxRate();
this.startCheckReplicationPolicies();
this.startDeduplicationSnapshotMonitor();
}
Expand Down Expand Up @@ -2146,7 +2148,13 @@ private void updateConfigurationAndRegisterListeners() {
registerConfigurationListener("brokerPublisherThrottlingMaxByteRate",
(brokerPublisherThrottlingMaxByteRate) ->
updateBrokerPublisherThrottlingMaxRate());

// add listener to notify broker dispatch-rate dynamic config
registerConfigurationListener("dispatchThrottlingRateInMsg",
(dispatchThrottlingRateInMsg) ->
updateBrokerDispatchThrottlingMaxRate());
registerConfigurationListener("dispatchThrottlingRateInByte",
(dispatchThrottlingRateInByte) ->
updateBrokerDispatchThrottlingMaxRate());
// add listener to notify topic publish-rate monitoring
if (!preciseTopicPublishRateLimitingEnable) {
registerConfigurationListener("topicPublisherThrottlingTickTimeMillis",
Expand All @@ -2161,6 +2169,14 @@ private void updateConfigurationAndRegisterListeners() {
// add more listeners here
}

private void updateBrokerDispatchThrottlingMaxRate() {
if (brokerDispatchRateLimiter == null) {
brokerDispatchRateLimiter = new DispatchRateLimiter(this);
} else {
brokerDispatchRateLimiter.updateDispatchRate();
}
}

private void updateBrokerPublisherThrottlingMaxRate() {
int currentMaxMessageRate = pulsar.getConfiguration().getBrokerPublisherThrottlingMaxMessageRate();
long currentMaxByteRate = pulsar.getConfiguration().getBrokerPublisherThrottlingMaxByteRate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ default Optional<DispatchRateLimiter> getDispatchRateLimiter() {
return Optional.empty();
}

default Optional<DispatchRateLimiter> getBrokerDispatchRateLimiter() {
return Optional.empty();
}

default boolean isSystemTopic() {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ public boolean isConsumerAvailable(Consumer consumer) {
return consumer != null && consumer.getAvailablePermits() > 0 && consumer.isWritable();
}

@Override
protected void reScheduleRead() {
// No-op
}

private static final Logger log = LoggerFactory.getLogger(NonPersistentDispatcherMultipleConsumers.class);

}
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,9 @@ protected void readMoreEntries(Consumer consumer) {
protected void cancelPendingRead() {
// No-op
}

@Override
protected void reScheduleRead() {
// No-op
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public class DispatchRateLimiter {
public enum Type {
TOPIC,
SUBSCRIPTION,
REPLICATOR
REPLICATOR,
BROKER
}

private final PersistentTopic topic;
Expand All @@ -59,6 +60,14 @@ public DispatchRateLimiter(PersistentTopic topic, Type type) {
updateDispatchRate();
}

public DispatchRateLimiter(BrokerService brokerService) {
this.topic = null;
this.topicName = null;
this.brokerService = brokerService;
this.type = Type.BROKER;
updateDispatchRate();
}

/**
* returns available msg-permit if msg-dispatch-throttling is enabled else it returns -1.
*
Expand Down Expand Up @@ -136,6 +145,10 @@ private DispatchRate createDispatchRate() {
dispatchThrottlingRateInMsg = config.getDispatchThrottlingRatePerReplicatorInMsg();
dispatchThrottlingRateInByte = config.getDispatchThrottlingRatePerReplicatorInByte();
break;
case BROKER:
dispatchThrottlingRateInMsg = config.getDispatchThrottlingRateInMsg();
dispatchThrottlingRateInByte = config.getDispatchThrottlingRateInByte();
break;
default:
dispatchThrottlingRateInMsg = -1;
dispatchThrottlingRateInByte = -1;
Expand All @@ -146,7 +159,7 @@ private DispatchRate createDispatchRate() {
.dispatchThrottlingRateInMsg(dispatchThrottlingRateInMsg)
.dispatchThrottlingRateInByte(dispatchThrottlingRateInByte)
.ratePeriodInSecond(1)
.relativeToPublishRate(config.isDispatchThrottlingRateRelativeToPublishRate())
.relativeToPublishRate(type != Type.BROKER && config.isDispatchThrottlingRateRelativeToPublishRate())
.build();
}

Expand All @@ -163,9 +176,12 @@ public void updateDispatchRate() {
dispatchRateOp = Optional.of(createDispatchRate());
}
updateDispatchRate(dispatchRateOp.get());
log.info("[{}] configured {} message-dispatch rate at broker {}", this.topicName, type,
dispatchRateOp.get());

if (type == Type.BROKER) {
log.info("configured broker message-dispatch rate {}", dispatchRate.get());
} else {
log.info("[{}] configured {} message-dispatch rate at broker {}",
this.topicName, type, dispatchRate.get());
}
}).exceptionally(ex -> {
log.error("[{}] failed to get the dispatch rate policy from the namespace resource for type {}",
topicName, type, ex);
Expand All @@ -180,6 +196,10 @@ public void updateDispatchRate() {
public static boolean isDispatchRateNeeded(BrokerService brokerService, Optional<Policies> policies,
String topicName, Type type) {
final ServiceConfiguration serviceConfig = brokerService.pulsar().getConfiguration();
if (type == Type.BROKER) {
Comment thread
315157973 marked this conversation as resolved.
return brokerService.getBrokerDispatchRateLimiter().isDispatchRateLimitingEnabled();
}

Optional<DispatchRate> dispatchRate = getTopicPolicyDispatchRate(brokerService, topicName, type);
if (dispatchRate.isPresent()) {
return true;
Expand Down Expand Up @@ -318,6 +338,9 @@ public static DispatchRateImpl getPoliciesDispatchRate(final String cluster,
* @return
*/
public CompletableFuture<Optional<DispatchRate>> getPoliciesDispatchRateAsync(BrokerService brokerService) {
if (topicName == null) {
return CompletableFuture.completedFuture(Optional.empty());
}
final String cluster = brokerService.pulsar().getConfiguration().getClusterName();
return getPoliciesAsync(brokerService, topicName).thenApply(policiesOp ->
Optional.ofNullable(getPoliciesDispatchRate(cluster, policiesOp, type)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,12 @@ public synchronized void readMoreEntries() {
}
}

@Override
protected void reScheduleRead() {
topic.getBrokerService().executor().schedule(() -> readMoreEntries(), MESSAGE_RATE_BACKOFF_MS,
TimeUnit.MILLISECONDS);
}

// left pair is messagesToRead, right pair is bytesToRead
protected Pair<Integer, Long> calculateToRead(int currentTotalAvailablePermits) {
int messagesToRead = Math.min(currentTotalAvailablePermits, readBatchSize);
Expand All @@ -307,51 +313,56 @@ protected Pair<Integer, Long> calculateToRead(int currentTotalAvailablePermits)
// active-cursor reads message from cache rather from bookkeeper (2) if topic has reached message-rate
// threshold: then schedule the read after MESSAGE_RATE_BACKOFF_MS
if (serviceConfig.isDispatchThrottlingOnNonBacklogConsumerEnabled() || !cursor.isActive()) {
if (topic.getDispatchRateLimiter().isPresent()
&& topic.getDispatchRateLimiter().get().isDispatchRateLimitingEnabled()) {
if (topic.getBrokerDispatchRateLimiter().isPresent()) {
DispatchRateLimiter brokerRateLimiter = topic.getBrokerDispatchRateLimiter().get();
if (reachDispatchRateLimit(brokerRateLimiter)) {
if (log.isDebugEnabled()) {
log.debug("[{}] message-read exceeded broker message-rate {}/{}, schedule after a {}", name,
brokerRateLimiter.getDispatchRateOnMsg(), brokerRateLimiter.getDispatchRateOnByte(),
MESSAGE_RATE_BACKOFF_MS);
}
return Pair.of(-1, -1L);
} else {
Pair<Integer, Long> calculateToRead =
updateMessagesToRead(brokerRateLimiter, messagesToRead, bytesToRead);
messagesToRead = calculateToRead.getLeft();
bytesToRead = calculateToRead.getRight();
}
}

if (topic.getDispatchRateLimiter().isPresent()) {
DispatchRateLimiter topicRateLimiter = topic.getDispatchRateLimiter().get();
if (!topicRateLimiter.hasMessageDispatchPermit()) {
if (reachDispatchRateLimit(topicRateLimiter)) {
if (log.isDebugEnabled()) {
log.debug("[{}] message-read exceeded topic message-rate {}/{}, schedule after a {}", name,
topicRateLimiter.getDispatchRateOnMsg(), topicRateLimiter.getDispatchRateOnByte(),
MESSAGE_RATE_BACKOFF_MS);
}
topic.getBrokerService().executor().schedule(() -> readMoreEntries(), MESSAGE_RATE_BACKOFF_MS,
TimeUnit.MILLISECONDS);
return Pair.of(-1, -1L);
} else {
Pair<Integer, Long> calculateResult = computeReadLimits(messagesToRead,
(int) topicRateLimiter.getAvailableDispatchRateLimitOnMsg(),
bytesToRead, topicRateLimiter.getAvailableDispatchRateLimitOnByte());

messagesToRead = calculateResult.getLeft();
bytesToRead = calculateResult.getRight();

Pair<Integer, Long> calculateToRead =
updateMessagesToRead(topicRateLimiter, messagesToRead, bytesToRead);
messagesToRead = calculateToRead.getLeft();
bytesToRead = calculateToRead.getRight();
}
}

if (dispatchRateLimiter.isPresent() && dispatchRateLimiter.get().isDispatchRateLimitingEnabled()) {
if (!dispatchRateLimiter.get().hasMessageDispatchPermit()) {
if (dispatchRateLimiter.isPresent()) {
if (reachDispatchRateLimit(dispatchRateLimiter.get())) {
if (log.isDebugEnabled()) {
log.debug("[{}] message-read exceeded subscription message-rate {}/{},"
+ " schedule after a {}", name,
dispatchRateLimiter.get().getDispatchRateOnMsg(),
log.debug("[{}] message-read exceeded subscription message-rate {}/{}, schedule after a {}",
name, dispatchRateLimiter.get().getDispatchRateOnMsg(),
dispatchRateLimiter.get().getDispatchRateOnByte(),
MESSAGE_RATE_BACKOFF_MS);
}
topic.getBrokerService().executor().schedule(() -> readMoreEntries(), MESSAGE_RATE_BACKOFF_MS,
TimeUnit.MILLISECONDS);
return Pair.of(-1, -1L);
} else {
Pair<Integer, Long> calculateResult = computeReadLimits(messagesToRead,
(int) dispatchRateLimiter.get().getAvailableDispatchRateLimitOnMsg(),
bytesToRead, dispatchRateLimiter.get().getAvailableDispatchRateLimitOnByte());

messagesToRead = calculateResult.getLeft();
bytesToRead = calculateResult.getRight();
Pair<Integer, Long> calculateToRead =
updateMessagesToRead(dispatchRateLimiter.get(), messagesToRead, bytesToRead);
messagesToRead = calculateToRead.getLeft();
bytesToRead = calculateToRead.getRight();
}
}

}

if (havePendingReplayRead) {
Expand All @@ -362,7 +373,9 @@ protected Pair<Integer, Long> calculateToRead(int currentTotalAvailablePermits)
}

// If messagesToRead is 0 or less, correct it to 1 to prevent IllegalArgumentException
return Pair.of(Math.max(messagesToRead, 1), Math.max(bytesToRead, 1));
messagesToRead = Math.max(messagesToRead, 1);
bytesToRead = Math.max(bytesToRead, 1);
return Pair.of(messagesToRead, bytesToRead);
}

protected Set<? extends Position> asyncReplayEntries(Set<? extends Position> positions) {
Expand Down Expand Up @@ -578,6 +591,9 @@ protected void sendMessagesToConsumers(ReadType readType, List<Entry> entries) {
// acquire message-dispatch permits for already delivered messages
long permits = dispatchThrottlingOnBatchMessageEnabled ? totalEntries : totalMessagesSent;
if (serviceConfig.isDispatchThrottlingOnNonBacklogConsumerEnabled() || !cursor.isActive()) {
if (topic.getBrokerDispatchRateLimiter().isPresent()) {
topic.getBrokerDispatchRateLimiter().get().tryDispatchPermit(permits, totalBytesSent);
}
if (topic.getDispatchRateLimiter().isPresent()) {
topic.getDispatchRateLimiter().get().tryDispatchPermit(permits, totalBytesSent);
}
Expand Down
Loading