From 8e6254adbec2db89e9f5c8242198c4bbbc64e89a Mon Sep 17 00:00:00 2001 From: atomzhong Date: Thu, 6 Apr 2023 16:08:36 +0800 Subject: [PATCH] RateLimitCaller invoke with query param and headers. --- .../service/callee/CustomLabelResolver.java | 13 +- .../callee/CustomLabelResolverReactive.java | 12 +- .../src/main/resources/bootstrap.yml | 3 + .../example/service/caller/Controller.java | 185 ++++++++++++++++++ .../service/caller/CustomLabelResolver.java | 58 ------ .../caller/CustomLabelResolverReactive.java | 46 ----- .../src/main/resources/bootstrap.yml | 2 - 7 files changed, 207 insertions(+), 112 deletions(-) create mode 100644 spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/Controller.java delete mode 100644 spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/CustomLabelResolver.java delete mode 100644 spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/CustomLabelResolverReactive.java diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/java/com/tencent/cloud/ratelimit/example/service/callee/CustomLabelResolver.java b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/java/com/tencent/cloud/ratelimit/example/service/callee/CustomLabelResolver.java index 06ff020a2..f9f405d4b 100644 --- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/java/com/tencent/cloud/ratelimit/example/service/callee/CustomLabelResolver.java +++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/java/com/tencent/cloud/ratelimit/example/service/callee/CustomLabelResolver.java @@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletRequest; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** @@ -35,12 +36,22 @@ import org.springframework.stereotype.Component; @Component public class CustomLabelResolver implements PolarisRateLimiterLabelServletResolver { + @Value("${label.key-value:}") + private String[] keyValues; @Override public Map resolve(HttpServletRequest request) { // rate limit by some request params. such as query params, headers .. + return getLabels(keyValues); + } + + static Map getLabels(String[] keyValues) { Map labels = new HashMap<>(); - labels.put("user", "zhangsan"); + for (String kv : keyValues) { + String key = kv.substring(0, kv.indexOf(":")); + String value = kv.substring(kv.indexOf(":")); + labels.put(key, value); + } return labels; } diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/java/com/tencent/cloud/ratelimit/example/service/callee/CustomLabelResolverReactive.java b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/java/com/tencent/cloud/ratelimit/example/service/callee/CustomLabelResolverReactive.java index eb6e01b03..a94662388 100644 --- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/java/com/tencent/cloud/ratelimit/example/service/callee/CustomLabelResolverReactive.java +++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/java/com/tencent/cloud/ratelimit/example/service/callee/CustomLabelResolverReactive.java @@ -17,14 +17,16 @@ package com.tencent.cloud.ratelimit.example.service.callee; -import java.util.HashMap; import java.util.Map; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; +import static com.tencent.cloud.ratelimit.example.service.callee.CustomLabelResolver.getLabels; + /** * resolver custom label from request. * @@ -32,13 +34,13 @@ import org.springframework.web.server.ServerWebExchange; */ @Component public class CustomLabelResolverReactive implements PolarisRateLimiterLabelReactiveResolver { + @Value("${label.key-value:}") + private String[] keyValues; + @Override public Map resolve(ServerWebExchange exchange) { // rate limit by some request params. such as query params, headers .. - Map labels = new HashMap<>(); - labels.put("user", "zhangsan"); - - return labels; + return getLabels(keyValues); } } diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/bootstrap.yml index 06f431b8f..67168f141 100644 --- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/bootstrap.yml @@ -22,3 +22,6 @@ management: logging: level: com.tencent.cloud.polaris: debug + +label: + key-value: user:zhangsan, user2:lisi diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/Controller.java b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/Controller.java new file mode 100644 index 000000000..f0026bb95 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/Controller.java @@ -0,0 +1,185 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.ratelimit.example.service.caller; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException.TooManyRequests; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; + +@RestController +@RequestMapping("/business") +public class Controller { + + private static final Logger LOG = LoggerFactory.getLogger(Controller.class); + + private final AtomicInteger index = new AtomicInteger(0); + private final AtomicLong lastTimestamp = new AtomicLong(0); + @Autowired + private RestTemplate restTemplate; + @Autowired + private WebClient.Builder webClientBuilder; + + private final String appName = "RateLimitCalleeService"; + + /** + * Get information. + * @return information + */ + @GetMapping("/info") + public String info() { + return "hello world for ratelimit service " + index.incrementAndGet(); + } + + @GetMapping("/info/webclient") + public Mono infoWebClient() { + return Mono.just("hello world for ratelimit service " + index.incrementAndGet()); + } + + @GetMapping("/invoke/webclient") + public String invokeInfoWebClient(@RequestParam String value1, @RequestParam String value2, @RequestHeader Map headers) throws InterruptedException, ExecutionException { + StringBuffer builder = new StringBuffer(); + WebClient webClient = webClientBuilder.baseUrl("http://" + appName).build(); + + Consumer headersConsumer = httpHeaders -> { + for (Map.Entry entry : headers.entrySet()) { + httpHeaders.add(entry.getKey(), entry.getValue()); + } + }; + + List> monoList = new ArrayList<>(); + for (int i = 0; i < 30; i++) { + Mono response = webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/business/info/webclient") + .queryParam("value1", value1) + .queryParam("value2", value2) + .build() + ) + .headers(headersConsumer) + .retrieve() + .bodyToMono(String.class) + .doOnSuccess(s -> builder.append(s).append("\n")) + .doOnError(e -> { + if (e instanceof WebClientResponseException) { + if (((WebClientResponseException) e).getRawStatusCode() == 429) { + builder.append("TooManyRequests ").append(index.incrementAndGet()).append("\n"); + } + } + }) + .onErrorReturn(""); + monoList.add(response); + } + for (Mono mono : monoList) { + mono.toFuture().get(); + } + index.set(0); + return builder.toString(); + } + + /** + * Get information 30 times per 1 second. + * + * @return result of 30 calls. + * @throws InterruptedException exception + */ + @GetMapping("/invoke") + public String invokeInfo(@RequestParam String value1, @RequestParam String value2, @RequestHeader Map headers) throws InterruptedException { + StringBuffer builder = new StringBuffer(); + CountDownLatch count = new CountDownLatch(30); + for (int i = 0; i < 30; i++) { + new Thread(() -> { + try { + HttpHeaders httpHeaders = new HttpHeaders(); + for (Map.Entry entry : headers.entrySet()) { + httpHeaders.add(entry.getKey(), entry.getValue()); + } + ResponseEntity entity = restTemplate.exchange( + "http://" + appName + "/business/info?value1={value1}&value2={value2}", + HttpMethod.GET, + new HttpEntity<>(httpHeaders), + String.class, + value1, value2 + ); + builder.append(entity.getBody()).append("\n"); + } + catch (RestClientException e) { + if (e instanceof TooManyRequests) { + builder.append("TooManyRequests ").append(index.incrementAndGet()).append("\n"); + } + else { + throw e; + } + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + count.countDown(); + } + }).start(); + } + count.await(); + index.set(0); + return builder.toString(); + } + + /** + * Get information with unirate. + * + * @return information + */ + @GetMapping("/unirate") + public String unirate() { + long currentTimestamp = System.currentTimeMillis(); + long lastTime = lastTimestamp.get(); + if (lastTime != 0) { + LOG.info("Current timestamp:" + currentTimestamp + ", diff from last timestamp:" + (currentTimestamp - lastTime)); + } + else { + LOG.info("Current timestamp:" + currentTimestamp); + } + lastTimestamp.set(currentTimestamp); + return "hello world for ratelimit service with diff from last request:" + (currentTimestamp - lastTime) + "ms."; + } + +} diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/CustomLabelResolver.java b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/CustomLabelResolver.java deleted file mode 100644 index eb0c0c741..000000000 --- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/CustomLabelResolver.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.ratelimit.example.service.caller; - -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; - -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -/** - * resolver custom label from request. - * - * @author atom - */ -@Component -public class CustomLabelResolver implements PolarisRateLimiterLabelServletResolver { - - @Value("${label.key-value:}") - private String[] keyValues; - @Override - public Map resolve(HttpServletRequest request) { - // rate limit by some request params. such as query params, headers .. - - return getLabels(keyValues); - } - - static Map getLabels(String[] keyValues) { - Map labels = new HashMap<>(); - for (String kv : keyValues) { - String key = kv.substring(0, kv.indexOf(":")); - String value = kv.substring(kv.indexOf(":")); - labels.put(key, value); - } - - return labels; - } -} diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/CustomLabelResolverReactive.java b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/CustomLabelResolverReactive.java deleted file mode 100644 index 580d5e732..000000000 --- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/java/com/tencent/cloud/ratelimit/example/service/caller/CustomLabelResolverReactive.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.ratelimit.example.service.caller; - -import java.util.Map; - -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; - -import static com.tencent.cloud.ratelimit.example.service.caller.CustomLabelResolver.getLabels; - -/** - * resolver custom label from request. - * - * @author atom - */ -@Component -public class CustomLabelResolverReactive implements PolarisRateLimiterLabelReactiveResolver { - @Value("${label.key-value:}") - private String[] keyValues; - - @Override - public Map resolve(ServerWebExchange exchange) { - // rate limit by some request params. such as query params, headers .. - - return getLabels(keyValues); - } -} diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/resources/bootstrap.yml index 35cd87735..b4610df36 100644 --- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-caller-service/src/main/resources/bootstrap.yml @@ -19,5 +19,3 @@ logging: level: com.tencent.cloud.polaris: debug -label: - key-value: user:zhangsan, user2:lisi