Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix precise publish rate limiting #11351

Closed
danielsinai opened this issue Jul 17, 2021 · 3 comments
Closed

Fix precise publish rate limiting #11351

danielsinai opened this issue Jul 17, 2021 · 3 comments
Labels
lifecycle/stale type/enhancement The enhancements for the existing features or docs. e.g. reduce memory usage of the delayed messages

Comments

@danielsinai
Copy link
Contributor

Is your enhancement request related to a problem? Please describe.
Currently, precise publish rate limiting doesn't work as expected and that's because multiple reasons

  1. Renew function called every second and resets reading from socket every second no matter how many messages produced in the last second (FixedWindow Algorithm)
  2. The FixedWindow algorithm does not fit here because a permit is not 1:1 (multiple messages in batch, bytes per second)
  3. Rate limit function passed only to the msg/s rate limiter (and that's in order to avoid calling it twice)
  4. The first message of any new producer that connects to the broker will get in

Describe the solution you'd like
1 + 2. in order to fix that, I believe we should implement another RateLimiter using the LeakingBucket Algorithm along with FixedWindow
3. we should pass a rate limit function that depends on the state of both of the rate limiters
4. I don't really have an idea how to implement a fix for it would love to hear ur opinions

Additional context
The main idea is thanks to #8611 (comment) @lhotari

@danielsinai danielsinai added the type/enhancement The enhancements for the existing features or docs. e.g. reduce memory usage of the delayed messages label Jul 17, 2021
@danielsinai
Copy link
Contributor Author

I will publish a pull request soon

sijie pushed a commit that referenced this issue Jul 29, 2021
## Master Issue: <#11351>

### Motivation
Hello, as far as I'm concerned it is well known that precise publish rate limiting does not function well. I believe my PR fixes problem number 3 stated in the issue above.

@danielsinai:
"3. Rate limit function passed only to the msg/s rate limiter (and that's in order to avoid calling it twice)"

It was passed to message rate limiter only due to the fact that there was no implementation of a way to throttle the connection whenever only **one of the limiters was exceeded**.

This PR will allow both message rate & byte rate to co-exist, limit and enable socket reading only when necessary.

### Modifications

- _tryAcquire_ function in **PublishRateLimiterDisable** will return true. If publish rate was null, this function would get called and return false, thus throttling the client for no reason. If the publish rate is null, it means it was not set by anyone so there's no reason to throttle any connection. 
```java
public boolean tryAcquire(int numbers, long bytes) {
        return true;
}
```
- **RateLimiter** _permits_ and _acquiredPermits_ were changed to volatile.
```java
 private volatile long permits;
 private volatile long acquiredPermits;
```
in order to allow reading access from multiple threads at the same time.
also the removal of _synchronized_ keyword from _getAvailablePermits()_ function.
```java
public long getAvailablePermits() {
        return Math.max(0, this.permits - this.acquiredPermits);
}
```
**This is required, since a thread dead lock will happen if not.**

- Created ~a HashMap to manage the byte and message rate limiters, and~ a function _releaseThrottle()_ to handle the auto read enable.
If one of the rate limiters has no available permits we will not re-enable the auto read from the socket.
codelipenghui pushed a commit that referenced this issue Jul 30, 2021
## Master Issue: <#11351>

### Motivation
Hello, as far as I'm concerned it is well known that precise publish rate limiting does not function well. I believe my PR fixes problem number 3 stated in the issue above.

@danielsinai:
"3. Rate limit function passed only to the msg/s rate limiter (and that's in order to avoid calling it twice)"

It was passed to message rate limiter only due to the fact that there was no implementation of a way to throttle the connection whenever only **one of the limiters was exceeded**.

This PR will allow both message rate & byte rate to co-exist, limit and enable socket reading only when necessary.

### Modifications

- _tryAcquire_ function in **PublishRateLimiterDisable** will return true. If publish rate was null, this function would get called and return false, thus throttling the client for no reason. If the publish rate is null, it means it was not set by anyone so there's no reason to throttle any connection. 
```java
public boolean tryAcquire(int numbers, long bytes) {
        return true;
}
```
- **RateLimiter** _permits_ and _acquiredPermits_ were changed to volatile.
```java
 private volatile long permits;
 private volatile long acquiredPermits;
```
in order to allow reading access from multiple threads at the same time.
also the removal of _synchronized_ keyword from _getAvailablePermits()_ function.
```java
public long getAvailablePermits() {
        return Math.max(0, this.permits - this.acquiredPermits);
}
```
**This is required, since a thread dead lock will happen if not.**

- Created ~a HashMap to manage the byte and message rate limiters, and~ a function _releaseThrottle()_ to handle the auto read enable.
If one of the rate limiters has no available permits we will not re-enable the auto read from the socket.

(cherry picked from commit 7f2ca8f)
michaeljmarshall pushed a commit that referenced this issue Dec 10, 2021
## Master Issue: <#11351>

### Motivation
Hello, as far as I'm concerned it is well known that precise publish rate limiting does not function well. I believe my PR fixes problem number 3 stated in the issue above.

@danielsinai:
"3. Rate limit function passed only to the msg/s rate limiter (and that's in order to avoid calling it twice)"

It was passed to message rate limiter only due to the fact that there was no implementation of a way to throttle the connection whenever only **one of the limiters was exceeded**.

This PR will allow both message rate & byte rate to co-exist, limit and enable socket reading only when necessary.

### Modifications

- _tryAcquire_ function in **PublishRateLimiterDisable** will return true. If publish rate was null, this function would get called and return false, thus throttling the client for no reason. If the publish rate is null, it means it was not set by anyone so there's no reason to throttle any connection.
```java
public boolean tryAcquire(int numbers, long bytes) {
        return true;
}
```
- **RateLimiter** _permits_ and _acquiredPermits_ were changed to volatile.
```java
 private volatile long permits;
 private volatile long acquiredPermits;
```
in order to allow reading access from multiple threads at the same time.
also the removal of _synchronized_ keyword from _getAvailablePermits()_ function.
```java
public long getAvailablePermits() {
        return Math.max(0, this.permits - this.acquiredPermits);
}
```
**This is required, since a thread dead lock will happen if not.**

- Created ~a HashMap to manage the byte and message rate limiters, and~ a function _releaseThrottle()_ to handle the auto read enable.
If one of the rate limiters has no available permits we will not re-enable the auto read from the socket.

(cherry picked from commit 7f2ca8f)
nicoloboschi pushed a commit to datastax/pulsar that referenced this issue Jan 26, 2022
…he#11372)

Hello, as far as I'm concerned it is well known that precise publish rate limiting does not function well. I believe my PR fixes problem number 3 stated in the issue above.

@danielsinai:
"3. Rate limit function passed only to the msg/s rate limiter (and that's in order to avoid calling it twice)"

It was passed to message rate limiter only due to the fact that there was no implementation of a way to throttle the connection whenever only **one of the limiters was exceeded**.

This PR will allow both message rate & byte rate to co-exist, limit and enable socket reading only when necessary.

- _tryAcquire_ function in **PublishRateLimiterDisable** will return true. If publish rate was null, this function would get called and return false, thus throttling the client for no reason. If the publish rate is null, it means it was not set by anyone so there's no reason to throttle any connection.
```java
public boolean tryAcquire(int numbers, long bytes) {
        return true;
}
```
- **RateLimiter** _permits_ and _acquiredPermits_ were changed to volatile.
```java
 private volatile long permits;
 private volatile long acquiredPermits;
```
in order to allow reading access from multiple threads at the same time.
also the removal of _synchronized_ keyword from _getAvailablePermits()_ function.
```java
public long getAvailablePermits() {
        return Math.max(0, this.permits - this.acquiredPermits);
}
```
**This is required, since a thread dead lock will happen if not.**

- Created ~a HashMap to manage the byte and message rate limiters, and~ a function _releaseThrottle()_ to handle the auto read enable.
If one of the rate limiters has no available permits we will not re-enable the auto read from the socket.

(cherry picked from commit 7f2ca8f)
(cherry picked from commit ab5fb72)
@codelipenghui
Copy link
Contributor

The issue had no activity for 30 days, mark with Stale label.

bharanic-dev pushed a commit to bharanic-dev/pulsar that referenced this issue Mar 18, 2022
…he#11372)

## Master Issue: <apache#11351>

### Motivation
Hello, as far as I'm concerned it is well known that precise publish rate limiting does not function well. I believe my PR fixes problem number 3 stated in the issue above.

@danielsinai:
"3. Rate limit function passed only to the msg/s rate limiter (and that's in order to avoid calling it twice)"

It was passed to message rate limiter only due to the fact that there was no implementation of a way to throttle the connection whenever only **one of the limiters was exceeded**.

This PR will allow both message rate & byte rate to co-exist, limit and enable socket reading only when necessary.

### Modifications

- _tryAcquire_ function in **PublishRateLimiterDisable** will return true. If publish rate was null, this function would get called and return false, thus throttling the client for no reason. If the publish rate is null, it means it was not set by anyone so there's no reason to throttle any connection. 
```java
public boolean tryAcquire(int numbers, long bytes) {
        return true;
}
```
- **RateLimiter** _permits_ and _acquiredPermits_ were changed to volatile.
```java
 private volatile long permits;
 private volatile long acquiredPermits;
```
in order to allow reading access from multiple threads at the same time.
also the removal of _synchronized_ keyword from _getAvailablePermits()_ function.
```java
public long getAvailablePermits() {
        return Math.max(0, this.permits - this.acquiredPermits);
}
```
**This is required, since a thread dead lock will happen if not.**

- Created ~a HashMap to manage the byte and message rate limiters, and~ a function _releaseThrottle()_ to handle the auto read enable.
If one of the rate limiters has no available permits we will not re-enable the auto read from the socket.
@lhotari
Copy link
Member

lhotari commented Aug 16, 2022

This issue was fixed by #11446 and #11372

@lhotari lhotari closed this as completed Aug 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lifecycle/stale type/enhancement The enhancements for the existing features or docs. e.g. reduce memory usage of the delayed messages
Projects
None yet
Development

No branches or pull requests

3 participants