diff --git a/nacos-server-gateway/pom.xml b/nacos-server-gateway/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..d64072584a57b78fd10185937e77f3fbfd2d6e98 --- /dev/null +++ b/nacos-server-gateway/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + + com.kwan.springcloudalibaba + nacos-server-parent + 1.0.0-SNAPSHOT + + + nacos-server-gateway + nacos-server-gateway + nacos-server-gateway + + + + com.kwan.springcloudalibaba + nacos-server-feign-api + 1.0.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + org.springframework.boot + spring-boot-starter-actuator + + + org.projectlombok + lombok + + + com.alibaba.csp + sentinel-core + + + + com.alibaba.csp + sentinel-transport-simple-http + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + + com.alibaba.csp + sentinel-datasource-nacos + + + junit + junit + + + + org.springframework.cloud + spring-cloud-starter-openfeign + 2.0.0.RELEASE + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + 2.0.0.RELEASE + + + com.alibaba.csp + sentinel-spring-webmvc-adapter + 1.8.2 + + + + + \ No newline at end of file diff --git a/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/GatewayApplication.java b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/GatewayApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..6df2a841a7fc459c910cdcc2ba93417d068338d5 --- /dev/null +++ b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/GatewayApplication.java @@ -0,0 +1,40 @@ +package com.kwan.springcloudalibaba; + +import com.alibaba.cloud.nacos.ribbon.NacosRule; +import com.netflix.loadbalancer.IPing; +import com.netflix.loadbalancer.IRule; +import com.netflix.loadbalancer.PingUrl; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; + + +/** + * http://localhost:18088/sentinel/nameInfo + * + * @author : qinyingjie + * @version : 2.2.0 + * @date : 2023/1/17 12:37 + */ +@EnableFeignClients +@EnableDiscoveryClient +@SpringBootApplication +public class GatewayApplication { + + @Bean + public IRule randomRule() { + return new NacosRule(); //nacos的策略 + } + + @Bean + public IPing iping() { + return new PingUrl(); + } + + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + System.out.println("-------------------------------网关服务启动成功-------------------------------"); + } +} diff --git a/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/constant/RespConstant.java b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/constant/RespConstant.java new file mode 100644 index 0000000000000000000000000000000000000000..6deffcfe5c49c819ff810bd64a401a39316930a4 --- /dev/null +++ b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/constant/RespConstant.java @@ -0,0 +1,6 @@ +package com.kwan.springcloudalibaba.constant; + +public class RespConstant { + public static final Integer RESP_CODE_FLOW_LIMITING_EXCEPTION = 441; + public static final String RESP_MSG_FLOW_LIMITING_EXCEPTION = "流量控制"; +} diff --git a/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/FlowLimitController.java b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/FlowLimitController.java new file mode 100644 index 0000000000000000000000000000000000000000..566b234138be5ca0ea7dcf66d3ee99859c9f1f52 --- /dev/null +++ b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/FlowLimitController.java @@ -0,0 +1,120 @@ +package com.kwan.springcloudalibaba.controller; + +import com.alibaba.csp.sentinel.annotation.SentinelResource; +import com.alibaba.csp.sentinel.slots.block.BlockException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.TimeUnit; + +/** + * 限流测试 + * http://localhost:18088/sentinel/nameInfo + * + * @author : qinyingjie + * @version : 2.2.0 + * @date : 2023/2/2 17:13 + */ +@Slf4j +@RestController +@RequestMapping("/flowLimit") +public class FlowLimitController { + + + /** + * http://127.0.0.1:8086/flowLimit/testA + */ + @GetMapping("/testA") + public String testA() { + System.out.println("------ testA ------"); + return "------testA"; + } + + @GetMapping("/testB") + public String testB() { + try { + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("------ testB ------"); + return "------testB"; + } + + @GetMapping("/testC") + public String testC() { + try { + int a = 1 / 0; + System.out.println("------ testC ------"); + } catch (Exception e) { + e.printStackTrace(); + } + return "------testC"; + } + + @GetMapping("/testD") + public String testD() { + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "------testD"; + } + + @SentinelResource + @GetMapping("/testE") + public String testDD() { + try { + TimeUnit.SECONDS.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "------testE"; + } + + /** + * 热点规则 + * + * @param p1 + * @param p2 + * @return + */ + @GetMapping("/testHotKey") + @SentinelResource(value = "testHotKey") + public String testHotKey(@RequestParam(value = "p1", required = false) String p1, + @RequestParam(value = "p2", required = false) String p2) { + return "------testHotKey"; + } + + + @GetMapping("/testHotKey2") + @SentinelResource(value = "testHotKey2", blockHandler = "dealHandler_testHotKey") + public String testHotKey2(@RequestParam(value = "p1", required = false) String p1, + @RequestParam(value = "p2", required = false) String p2) { + log.info("testE 热点参数"); + return "------testHotKey2"; + } + + /** + * 自定义异常 + * + * @param p1 + * @param p2 + * @param exception + * @return + */ + public String dealHandler_testHotKey(String p1, String p2, BlockException exception) { + // 默认 Blocked by Sentinel (flow limiting) + return "-----dealHandler_testHotKey"; + } + + @GetMapping("/persistent") + public String persistent() { + log.info("persistent 测试持久化"); + return "------persistent 测试持久化"; + } +} \ No newline at end of file diff --git a/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/LocalController.java b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/LocalController.java new file mode 100644 index 0000000000000000000000000000000000000000..dd52ad47a1fcde9126defcde61eb56ee60f4ef1b --- /dev/null +++ b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/LocalController.java @@ -0,0 +1,52 @@ +package com.kwan.springcloudalibaba.controller; + +import com.alibaba.csp.sentinel.Entry; +import com.alibaba.csp.sentinel.SphU; +import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.slots.block.RuleConstant; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + + +@RestController +public class LocalController { + + public static void main(String[] args) { + initFlowRules(); + while (true) { + Entry entry = null; + try { + entry = SphU.entry("HelloWorld"); + /*您的业务逻辑 - 开始*/ + System.out.println("hello world"); + /*您的业务逻辑 - 结束*/ + } catch (BlockException e1) { + /*流控逻辑处理 - 开始*/ + System.out.println("block!"); + /*流控逻辑处理 - 结束*/ + } finally { + if (entry != null) { + entry.exit(); + } + } + } + } + + /** + * 资源 HelloWorld 每秒最多只能通过 20 个请求。 + */ + private static void initFlowRules() { + List rules = new ArrayList<>(); + FlowRule rule = new FlowRule(); + rule.setResource("HelloWorld"); + rule.setGrade(RuleConstant.FLOW_GRADE_QPS); + // Set limit QPS to 20. + rule.setCount(1); + rules.add(rule); + FlowRuleManager.loadRules(rules); + } +} \ No newline at end of file diff --git a/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/SentinelController.java b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/SentinelController.java new file mode 100644 index 0000000000000000000000000000000000000000..2caa13238709dbaaacb9dc233dacf9a4117c3401 --- /dev/null +++ b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/controller/SentinelController.java @@ -0,0 +1,70 @@ +package com.kwan.springcloudalibaba.controller; + +import com.alibaba.csp.sentinel.annotation.SentinelResource; +import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.kwan.springcloudalibaba.api.FeignUserService; +import com.kwan.springcloudalibaba.common.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * http://localhost:18088/sentinel/nameInfo + * + * @author : qinyingjie + * @version : 2.2.0 + * @date : 2023/2/2 17:13 + */ +@RestController +@RequestMapping("/sentinel") +public class SentinelController { + @Autowired + private FeignUserService feignUserService; + + /** + * feign调用 + * http://127.0.0.1:8085/nacos/consumer/1 + *

+ * http://localhost:9091/user/1 + * + * @param id + * @return + */ + @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_PROBLEM_JSON_VALUE) + public Result getUserById(@PathVariable Integer id) { + return Result.ok(feignUserService.selectOne(id)); + } + + /** + * 获取配置的变量 + * http://localhost:8086/sentinel/nameInfo + */ + @GetMapping(value = "/nameInfo", produces = MediaType.APPLICATION_PROBLEM_JSON_VALUE) + public Result nameInfo() { + return Result.ok(); + } + + /** + * http://localhost:8086/sentinel/world + * + * @return + */ + @GetMapping("/world") + @SentinelResource(value = "helloWorld", blockHandler = "helloBlock") + public String helloWorld() { + return "Hello world"; + } + + /** + * 回调地址 + * + * @param e + * @return + */ + public String helloBlock(BlockException e) { + return "你已被流控"; + } +} \ No newline at end of file diff --git a/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/handler/UrlBlockHandler.java b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/handler/UrlBlockHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..5f44b3980fef33465021879f39cf7b28765bda2f --- /dev/null +++ b/nacos-server-gateway/src/main/java/com/kwan/springcloudalibaba/handler/UrlBlockHandler.java @@ -0,0 +1,47 @@ +package com.kwan.springcloudalibaba.handler; + +import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler; +import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException; +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; +import com.alibaba.csp.sentinel.slots.block.flow.FlowException; +import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException; +import com.alibaba.csp.sentinel.slots.system.SystemBlockException; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.kwan.springcloudalibaba.common.Result; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Component +public class UrlBlockHandler implements BlockExceptionHandler { + + @Override + public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception { + String msg = null; + if (e instanceof FlowException) {//限流异常 + msg = "接口已被限流"; + } else if (e instanceof DegradeException) {//熔断异常 + msg = "接口已被熔断,请稍后再试"; + } else if (e instanceof ParamFlowException) { //热点参数限流 + msg = "热点参数限流"; + } else if (e instanceof SystemBlockException) { //系统规则异常 + msg = "系统规则(负载不满足要求)"; + } else if (e instanceof AuthorityException) { //授权规则异常 + msg = "授权规则不通过"; + } + httpServletResponse.setStatus(500); + httpServletResponse.setCharacterEncoding("UTF-8"); + httpServletResponse.setContentType("application/json;charset=utf-8"); + //ObjectMapper是内置Jackson的序列化工具类,这用于将对象转为JSON字符串 + ObjectMapper mapper = new ObjectMapper(); + //某个对象属性为null时不进行序列化输出 + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.writeValue(httpServletResponse.getWriter(), + Result.error(300, msg) + ); + } + +} \ No newline at end of file diff --git a/nacos-server-gateway/src/main/resources/bootstrap.yml b/nacos-server-gateway/src/main/resources/bootstrap.yml new file mode 100644 index 0000000000000000000000000000000000000000..0919312993109971b6836578eb9b84a6f3c214f4 --- /dev/null +++ b/nacos-server-gateway/src/main/resources/bootstrap.yml @@ -0,0 +1,34 @@ +#端口号 +server: + port: 8088 + +#spring配置 +spring: + application: + name: nacos-server-sentinel-consumer + profiles: + active: dev + cloud: + nacos: + discovery: + server-addr: http://120.79.36.53:8848 #服务注册地址 + config: + server-addr: http://120.79.36.53:8848 #配置中心地址 + file-extension: yaml #文件类型 + group: DEV_GROUP #组别 + namespace: 4cd9bd32-8f25-45cd-b919-df1a0df146e0 #命名空间 + refresh-enabled: true #默认自动刷新 + sentinel: + transport: + dashboard: 127.0.0.1:8181 + port: 8719 #默认端口,如果被占用则从8719依次+1扫描 + datasource: + ds1: + nacos: + server-addr: http://120.79.36.53:8848 + username: nacos + password: nacos + dataId: nacos-server-sentinel-consumer # 微服务名称 + groupId: DEFAULT_GROUP + data-type: json + rule-type: flow # 流控规则 \ No newline at end of file diff --git a/nacos-server-gateway/src/test/java/com/kwan/springcloudalibaba/SentinelConsumerApplicationTests.java b/nacos-server-gateway/src/test/java/com/kwan/springcloudalibaba/SentinelConsumerApplicationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..9a5f4beba753d7f84dab9570f2ba925d3f7b4566 --- /dev/null +++ b/nacos-server-gateway/src/test/java/com/kwan/springcloudalibaba/SentinelConsumerApplicationTests.java @@ -0,0 +1,13 @@ +package com.kwan.springcloudalibaba; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SentinelConsumerApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/nacos-server-sentinel-consumer/src/main/resources/bootstrap.yml b/nacos-server-sentinel-consumer/src/main/resources/bootstrap.yml index e2c6ba1b582da70f938fb8b4606f598bcfb75282..fa7dfb5285ece1f28ac96956715740732a256626 100644 --- a/nacos-server-sentinel-consumer/src/main/resources/bootstrap.yml +++ b/nacos-server-sentinel-consumer/src/main/resources/bootstrap.yml @@ -11,9 +11,9 @@ spring: cloud: nacos: discovery: - server-addr: localhost:8848 #服务注册地址 + server-addr: http://120.79.36.53:8848 #服务注册地址 config: - server-addr: localhost:8848 #配置中心地址 + server-addr: http://120.79.36.53:8848 #配置中心地址 file-extension: yaml #文件类型 group: DEV_GROUP #组别 namespace: 4cd9bd32-8f25-45cd-b919-df1a0df146e0 #命名空间 @@ -25,7 +25,9 @@ spring: datasource: ds1: nacos: - server-addr: localhost:8848 + server-addr: http://120.79.36.53:8848 + username: nacos + password: nacos dataId: nacos-server-sentinel-consumer # 微服务名称 groupId: DEFAULT_GROUP data-type: json diff --git a/pom.xml b/pom.xml index 5ec25d079aee6c3e39940e76a8d476baa1619dc1..80446cb36590cb4625529ce28ef738a9ef060daa 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,7 @@ nacos-server-consumer nacos-server-feign-api nacos-server-sentinel-consumer + nacos-server-gateway @@ -45,13 +46,13 @@ pom import - - - - - - - + + + + + + + com.netflix.archaius archaius-core