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

feature: add single server rate limit #6756

Open
wants to merge 48 commits into
base: 2.x
Choose a base branch
from

Conversation

xjlgod
Copy link
Contributor

@xjlgod xjlgod commented Aug 14, 2024

  • I have registered the PR changes.

Ⅰ. Describe what this PR did

Support flow limiting control for a single server:

  • Flow limiting components: Select Bucket4j components to implement flow limit control.
  • Processing flow limit control: Process flow limiting at the top level in DefaultCordinator, and perform flow limiting checks in the onRequest method. Only GlobalBegin request will be limited.
  • Transaction end identity: All transaction ends need to be able to correctly identify flow limit control and throw corresponding exceptions.
  • Metrics: Use a new metrics record events when current limiting is triggered

Ⅱ. Does this pull request fix one issue?

Ⅲ. Why don't you add test cases (unit test/integration test)?

Ⅳ. Describe how to verify it

Ⅴ. Special notes for reviews

Copy link

codecov bot commented Aug 24, 2024

Codecov Report

Attention: Patch coverage is 14.58333% with 164 lines in your changes missing coverage. Please review.

Project coverage is 52.47%. Comparing base (5b31862) to head (54d93dc).

Files with missing lines Patch % Lines
...ata/server/limit/ratelimit/RateLimiterHandler.java 9.09% 37 Missing and 3 partials ⚠️
...ata/server/limit/ratelimit/TokenBucketLimiter.java 36.95% 29 Missing ⚠️
...va/org/apache/seata/core/event/RateLimitEvent.java 0.00% 23 Missing ⚠️
...he/seata/server/limit/ratelimit/RateLimitInfo.java 0.00% 23 Missing ⚠️
...e/properties/server/ServerRateLimitProperties.java 7.69% 12 Missing ⚠️
...rver/limit/ratelimit/RateLimiterHandlerConfig.java 7.69% 12 Missing ⚠️
...ache/seata/server/limit/LimitRequestDecorator.java 0.00% 8 Missing ⚠️
...apache/seata/server/metrics/MetricsSubscriber.java 0.00% 6 Missing ⚠️
...erver/limit/AbstractTransactionRequestHandler.java 28.57% 5 Missing ⚠️
.../apache/seata/server/metrics/MetricsPublisher.java 0.00% 3 Missing ⚠️
... and 2 more
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##                2.x    #6756      +/-   ##
============================================
- Coverage     52.66%   52.47%   -0.19%     
- Complexity     6688     6699      +11     
============================================
  Files          1132     1140       +8     
  Lines         40286    40477     +191     
  Branches       4724     4734      +10     
============================================
+ Hits          21215    21240      +25     
- Misses        17039    17201     +162     
- Partials       2032     2036       +4     
Files with missing lines Coverage Δ
...ava/org/apache/seata/common/ConfigurationKeys.java 0.00% <ø> (ø)
...in/java/org/apache/seata/common/DefaultValues.java 0.00% <ø> (ø)
...ava/io/seata/tm/api/DefaultFailureHandlerImpl.java 64.86% <ø> (ø)
...seata/core/exception/TransactionExceptionCode.java 100.00% <ø> (ø)
...handler/GlobalTransactionalInterceptorHandler.java 29.68% <ø> (ø)
...ga/engine/tm/DefaultSagaTransactionalTemplate.java 61.76% <ø> (ø)
...ta/spring/boot/autoconfigure/StarterConstants.java 100.00% <ø> (ø)
.../apache/seata/server/metrics/MeterIdConstants.java 100.00% <100.00%> (ø)
...configure/SeataServerEnvironmentPostProcessor.java 0.00% <0.00%> (ø)
...e/seata/server/coordinator/DefaultCoordinator.java 42.31% <0.00%> (-0.14%) ⬇️
... and 10 more

... and 1 file with indirect coverage changes

@slievrly slievrly self-requested a review August 31, 2024 14:51
@slievrly slievrly added this to the 2.3.0 milestone Aug 31, 2024
@funky-eyes funky-eyes added type: feature Category issues or prs related to feature request. module/server server module labels Sep 3, 2024
/**
* The constant RATE_LIMIT_BUCKET_TOKEN_SECOND_NUM.
*/
String RATE_LIMIT_BUCKET_TOKEN_SECOND_NUM = RATE_LIMIT_PREFIX + "bucketTokenSecondNum";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bucketTokenNumPerSecond

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

Copy link
Contributor

@l81893521 l81893521 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rate limit has to immediate effect when it enable or change.

@xjlgod xjlgod changed the title feature: add single server rale limit feature: add single server rate limit Nov 30, 2024
@xjlgod xjlgod requested a review from l81893521 December 1, 2024 04:10
@slievrly slievrly modified the milestones: 2.3.0, 2.4.0 Dec 1, 2024
@@ -28,6 +26,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import java.util.concurrent.TimeUnit;

@@ -16,8 +16,6 @@
*/
package io.seata.tm.api;

import java.util.concurrent.TimeUnit;

import io.netty.util.HashedWheelTimer;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import io.netty.util.HashedWheelTimer;
import java.util.concurrent.TimeUnit;
import io.netty.util.HashedWheelTimer;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

Comment on lines 55 to 61
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import com.google.common.eventbus.Subscribe;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import com.google.common.eventbus.Subscribe;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import com.google.common.eventbus.Subscribe;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it


String CLIENT_ID_KEY = "clientId";

String SERVER_IP_ADDRESS_AND_PORT_KEY = "serverIpAddressAndPort";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't 'hostAndPort' more concise?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

Comment on lines 167 to 169
server.ratelimit.bucketTokenMaxNum = 1
server.ratelimit.bucketTokenInitialNum = 1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some users may blindly copy this configuration, so it's better to set the threshold to a larger value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import io.netty.channel.Channel;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import io.netty.channel.Channel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import io.netty.channel.Channel;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

Comment on lines 69 to 78
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

@xjlgod
Copy link
Contributor Author

xjlgod commented Dec 24, 2024

The rate limit has to immediate effect when it enable or change.

Had added hot config.

Comment on lines 108 to 114
GlobalBeginResponse response = new GlobalBeginResponse();
response.setTransactionExceptionCode(TransactionExceptionCode.BeginFailed);
response.setResultCode(ResultCode.Failed);
RateLimitInfo rateLimitInfo = RateLimitInfo.generateRateLimitInfo(rpcContext.getApplicationId(),
RateLimitInfo.GLOBAL_BEGIN_FAILED, rpcContext.getClientId(), XID.getIpAddressAndPort());
MetricsPublisher.postRateLimitEvent(rateLimitInfo);
response.setMsg(String.format("TransactionException[rate limit exception, rate limit info: %s]", rateLimitInfo));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

限流器应该只是限流作用,为什么要跟业务逻辑耦合在一起?
The role of limited viewership should only be limited viewership, why should it be coupled with business logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it.

return null;
}

if (request instanceof GlobalBeginRequest) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么不使用MessageType来判断,未来是否限流器可以作用于更多的request?只要对外提供一个配置项,允许用户配置一个需要限流request的集合,这里只要判断MessageType是否包含在其中即可
Why not use MessageType to determine whether the limit viewership of requests can be used in the future? Just provide a configuration item to allow users to configure a collection that needs to limit viewership of requests. Here, just determine whether MessageType is included in it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个当时是说的后面来优化,限流request的集合是指的比如是分支开始?如果是配置集合,我理解那就必须在客户端也看看是否做对应修改,以免不兼容?
This was the later optimization. Is the collection of current restriction Request refers to the start of the branch? If it is a configuration collection, you must also see the corresponding modification on the client, so as not to be incompatible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it.

Copy link
Contributor

@funky-eyes funky-eyes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pr需要登记

@@ -159,6 +159,11 @@ seata:
session:
branch-async-queue-size: 5000 #branch async remove queue size
enable-branch-async-remove: false #enable to asynchronous remove branchSession
ratelimit:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认值调大
Default value up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

@@ -131,6 +131,11 @@ seata:
session:
branch-async-queue-size: 5000 #branch async remove queue size
enable-branch-async-remove: false #enable to asynchronous remove branchSession
ratelimit:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认值调大
Default value up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

if (ConfigurationKeys.RATE_LIMIT_BUCKET_TOKEN_INITIAL_NUM.equals(dataId)) {
config.setBucketTokenInitialNum(NumberUtils.toInt(newValue, config.getBucketTokenInitialNum()));
}
rateLimiter.reInit(config);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么不直接在TokenBucketLimiter中进行监听?
Why not listen directly in TokenBucketLimiter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

因为想的是ratelimithandler下面可以通过spi加载不同的限流器,然后具体的限流器重新加载由具体的限流器实现
By ratelimithandler, you can load different current limiter through spi, and then the specific current limiter reloads by the new config from Ratelimithandler

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

# Conflicts:
#	changes/en-us/2.x.md
#	changes/zh-cn/2.x.md
#	common/src/main/java/org/apache/seata/common/ConfigurationKeys.java
Copy link
Contributor

@funky-eyes funky-eyes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
module/server server module type: feature Category issues or prs related to feature request.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants