Spring Boot에서 각 사용자의 환율 제한을 설정하려면 어떻게 해야 합니까?
많은 요청 콜을 처리하는 Spring Boot Rest API를 개발하고 있습니다.My Controller는 다음과 같습니다.
@RestController
public class ApiController {
List<ApiObject> apiDataList;
@RequestMapping(value="/data",produces={MediaType.APPLICATION_JSON_VALUE},method=RequestMethod.GET)
public ResponseEntity<List<ApiObject>> getData(){
List<ApiObject> apiDataList=getApiData();
return new ResponseEntity<List<ApiObject>>(apiDataList,HttpStatus.OK);
}
@ResponseBody
@Async
public List<ApiObject> getApiData(){
List<ApiObject> apiDataList3=new List<ApiObject> ();
//do the processing
return apiDataList3;
}
}
그래서 각 사용자의 환율 제한을 설정하려고 합니다.모든 사용자가 분당 5개의 요청만 요청할 수 있다고 가정해 보십시오.분당 5개의 API 콜만 발신하도록 각 사용자의 환율 제한을 설정하려면 어떻게 해야 합니까?또, 유저가 그 이상의 api 콜을 요구했을 경우, 429 응답을 반송할 수 있습니까?IP 주소가 필요합니까?
어떤 도움이라도 감사합니다.
각 유저(IP 주소)에 대해서, 초당 요구를 억제하려고 하는 유저를 위한 솔루션을 다음에 나타냅니다.이 솔루션에는 구글의 1.8+를 다시 쓴 카페인 라이브러리가 필요합니다.Guava library
을 합니다.LoadingCache
클래스: 요구 수 및 클라이언트 IP 주소를 저장합니다.,도합니다.javax.servlet-api
는 ''의존관계'를입니다.servlet filter
여기서 요구 카운트가 발생합니다.을 사용하다
import javax.servlet.Filter;
@Component
public class requestThrottleFilter implements Filter {
private int MAX_REQUESTS_PER_SECOND = 5; //or whatever you want it to be
private LoadingCache<String, Integer> requestCountsPerIpAddress;
public requestThrottleFilter(){
super();
requestCountsPerIpAddress = Caffeine.newBuilder().
expireAfterWrite(1, TimeUnit.SECONDS).build(new CacheLoader<String, Integer>() {
public Integer load(String key) {
return 0;
}
});
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
String clientIpAddress = getClientIP((HttpServletRequest) servletRequest);
if(isMaximumRequestsPerSecondExceeded(clientIpAddress)){
httpServletResponse.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
httpServletResponse.getWriter().write("Too many requests");
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
private boolean isMaximumRequestsPerSecondExceeded(String clientIpAddress){
Integer requests = 0;
requests = requestCountsPerIpAddress.get(clientIpAddress);
if(requests != null){
if(requests > MAX_REQUESTS_PER_SECOND) {
requestCountsPerIpAddress.asMap().remove(clientIpAddress);
requestCountsPerIpAddress.put(clientIpAddress, requests);
return true;
}
} else {
requests = 0;
}
requests++;
requestCountsPerIpAddress.put(clientIpAddress, requests);
return false;
}
public String getClientIP(HttpServletRequest request) {
String xfHeader = request.getHeader("X-Forwarded-For");
if (xfHeader == null){
return request.getRemoteAddr();
}
return xfHeader.split(",")[0]; // voor als ie achter een proxy zit
}
@Override
public void destroy() {
}
}
으로는 IP 하는 모든 합니다.LoadingCache
이것은 각 엔트리에 유효기간이 있는 특별한 맵과 같습니다.컨스트럭터에서는 유효기간이 1초로 설정되어 있습니다.「 」 、 「 IP 」 、 「 LoadingCache 」1 「 LoadingCache 」만료 시 지도에서 자동으로 삭제됩니다.는, 「1」의 「IP」가 .isMaximumRequestsPerSecondExceeded(String clientIpAddress)
는 이러한 요구를 총 요구 수에 추가하지만 그 전에 초당 최대 요구량이 이미 초과되었는지 여부를 확인합니다.이 경우 true가 반환되고 필터는 Too many requests를 나타내는 상태 코드 429의 오류 응답을 반환합니다.
이렇게 하면 사용자당 초당 일정한 양의 요청만 수행할 수 있습니다.
.Caffeine
: " " "에 "pom.xml
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<exclusions>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<artifactId>log4j-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
★★★★★★★★★★★★★★★★★★★★★에 주의해 주세요.<exclusion>
을 사용하고 . 사용하고 있습니다.log4j2
Spring이 logback
도서관.사용하시는 경우logback
나서 '나', '나', '나'를 삭제해 .<exclusion>
이러한 POM 의존관계 또는 로깅은 이 라이브러리에서 활성화되지 않습니다.
편집: 필터가 저장된 패키지의 컴포넌트 스캔을 Spring에 맡겨야 합니다.그렇지 않으면 필터가 작동하지 않습니다.또, @Component로 주석이 붙어 있기 때문에, 필터는 디폴트(/*)로 모든 엔드 포인트에 대해서 동작합니다.
스프링이 필터를 검출했을 경우는, 기동시에 로그에 다음과 같은 것이 표시됩니다.
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter:'requestThrottleFilter' to: [/*]
편집 19-01-2022:
초기 솔루션에는 너무 많은 요청을 차단하는 데 한 가지 단점이 있으며 이로 인해 코드를 변경했습니다.먼저 이유를 설명하겠습니다.
사용자가 초당 3개의 요청을 할 수 있다고 가정합니다.사용자가 1초 이내에 첫 번째 요구를 그 1초의 첫 번째 200밀리초 동안 실행한다고 가정합니다.의 엔트리가 ""에 됩니다.requestCountsPerIpAddress
1번이 사용자는 두 번째가 경과하고 엔트리가 삭제될 때까지 마지막 100밀리초 동안만 4개의 연속된 요청을 수행한다고 가정합니다.즉, 사용자가 효과적으로 차단되는 것은 네 번째 요청 시도 시 최대 100밀리초뿐입니다.100밀리초가 지나면 즉시 3개의 새로운 요청을 할 수 있습니다.
를 할 수 되었습니다.는 첫 번째 요구 때 할 수 에 의해, 「」의 가 「500」으로됩니다).LoadingCache
개개 2 개둘 ( 2 ) 둘밀밀 ( 500 )를밀밀 ( 500 )를를를 ) 나 then 。 내에 을 할 수 반해 됩니다.사용자가 엔트리가 만료된 직후에 3개의 요청을 하면 1초 이내에 5개의 요청을 효과적으로 작성할 수 있습니다.단, 3개의 요청만 허용됩니다(이전 엔트리가 만료되기 전 마지막 500밀리초 동안 2개 + 새로운 엔트리의 처음 500밀리초 동안 3개).따라서 이는 요청을 억제하는 매우 효율적인 방법이 아닙니다.
구아바 라이브러리와 관련하여 교착상태에 빠진 문제가 있어서 도서관을 카페인으로 변경했습니다.를 계속 이 guava 행을 .requestCountsPerIpAddress.asMap().remove(clientIpAddress);
밑에if(requests > MAX_REQUESTS_PER_SECOND) {
암호에 입력되어 있습니다.기본적으로는 IP 주소의 현재 엔트리를 삭제합니다.그 후 다음 줄에 다시 추가되어 해당 엔트리의 유효기간이 1초로 리셋됩니다.
이로 인해 사용자가 마지막 요청 후 1초 동안 요청 송신을 중지할 때까지 REST 엔드포인트에 계속 스팸을 보내는 것만으로 409 응답이 무기한 반환됩니다.
봄에는 그 부품이 없습니다.
- 솔루션의 일부로 구축할 수 있습니다.필터를 생성하여 스프링 컨텍스트에 등록합니다.필터는, 착신 콜을 체크해, 시간대에 유저 마다의 착신 요구를 카운트 합니다.토큰 버킷알고리즘이 가장 유연하기 때문에 사용합니다.
- 현재 솔루션과 독립적인 구성 요소를 구축할 수 있습니다.작업을 수행하는 API 게이트웨이를 만듭니다.Zuul 게이트웨이를 확장하고 토큰버킷 알고리즘을 사용할 수 있습니다.
- API 게이트웨이로 동작할 수 있고 환율 제한 및 슬롯링을 지원하는 Mulesoft ESB와 같은 이미 내장된 컴포넌트를 사용할 수 있습니다.내가 직접 써본 적은 없어.
- 마지막으로 환율 제한 및 조절 등을 지원하는 API Manager를 사용할 수 있습니다.Mull Soft, WSO2, 3Scale, Kong 등 체크 아웃...(대부분 비용이 들며 일부는 오픈 소스이며 커뮤니티 에디션도 있습니다).
스프링에는 개봉 즉시 환율 제한이 없습니다.
bucket4j-spring-boot-starter 프로젝트는 토큰 버킷알고리즘과 함께 bucket4j 라이브러리를 사용하여 REST api에 대한 액세스를 환율 제한합니다.응용 프로그램 속성 파일을 통해 구성할 수 있습니다.IP 주소 또는 유저명에 근거해 액세스를 제한하는 옵션이 있습니다.
사용자와는 독립적으로 10초 이내에 최대 5개의 요청을 허용하는 간단한 설정 예로서 다음과 같습니다.
bucket4j:
enabled: true
filters:
- cache-name: buckets
url: .*
rate-limits:
- bandwidths:
- capacity: 5
time: 10
unit: seconds
Netflix Zuul을 사용하는 경우 다음과 같은 스토리지 옵션을 사용하는 Spring Cloud Zuul Rate Limit을 사용할 수 있습니다.영사, 레디스, 스프링 데이터 및 버킷4j.
언급URL : https://stackoverflow.com/questions/44042412/how-to-set-rate-limit-for-each-user-in-spring-boot
'programing' 카테고리의 다른 글
ORA-011033 해결 방법: ORACLE 초기화 또는 셧다운 진행 중 (0) | 2023.02.09 |
---|---|
iFrame의 각도, onLoad 함수 (0) | 2023.02.09 |
TypeScript에서 가져오기 및 설정 (0) | 2023.02.09 |
Data Contract Json Serializer 및 Enums (0) | 2023.02.09 |
스프링 부트 액추에이터 엔드포인트의 응답 MIME 유형 (0) | 2023.02.09 |