1.Nacos
官网版本说明:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
父目录的pom文件
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><modules><module>order</module><module>stock</module><module>common</module></modules><groupId>com.example</groupId><artifactId>alibaba</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging><name>alibaba</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><sping-cloud-alibaba.version>2.2.7.RELEASE</sping-cloud-alibaba.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version><spring-boot.version>2.3.12.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${sping-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
order项目的依赖,因为引用到common项目中的order类,所以这里导入了common的依赖,其中还引入了nacos的配置中心依赖。
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>alibaba</artifactId><groupId>com.example</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>order</artifactId><dependencies><dependency><groupId>com.example</groupId><artifactId>common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency></dependencies></project>
nacos的控制台版本可以从maven中查找一下依赖(需要下个插件才能看到),查看对应的client版本,没安装插件这样也能看到。
配置文件的结构
介绍一下配置中心,需要被一个bootstrap.yml文件
spring:application:name: ordercloud:nacos:config:file-extension: yaml# config和discovery都需要配置,不然就会走默认的publicserver-addr: 1.116.220.231:10480namespace: c698366c-d971-43bc-a846-fe416f56aed3group: DEFAULT_GROUPdiscovery:server-addr: 1.116.220.231:10480namespace: c698366c-d971-43bc-a846-fe416f56aed3group: DEFAULT_GROUP
application.yml指定当前的版本
spring:profiles:active: dev
application-dev.yml
server:port: 11220
测试一下配置中心实时刷新的效果
/*** @author 杨胖胖*/@RestController@RequestMapping("order")//@RequiredArgsConstructor(onConstructor = @__(@Autowired))@RefreshScope// nacos配置中心实时刷新public class OrderController {@Value("${config.info}")private String config;@GetMapping("pay")public Order order() {return new Order(2, "订单", 300);}@GetMapping("config")public String config() {return config;}}
nacos配置中心添加一下我们需要的配置文件,dataId这个名字是根据bootstrap.yml文件spring.applicatin.name加上application.yml中的spring.profiles.active拼接起来的,比如说我的就是order-dev.yaml
这里我还创建了命名空间
配置一下内容并发布出去
现在来访问一下看看效果
修改配置中心数据后在访问一次,数据已经发生变化了。

2.Sentinel
官方文档:https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6
引入maven依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!-- sentinel持久化到nacos--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>
老样子先看一下对应的控制台版本依赖
yaml中添加配置
server:port: 11220spring:cloud:sentinel:transport:dashboard: 127.0.0.1:9999# sentinel与控制台通信的端口,默认8719重复了会自动+1port: 8719
流控规则
默认sentinel是懒加载的,所以需要请求后才能看到sentinel的界面,密码和账号默认是sentinel
我们来添加个流控规则测试一下
对应的测试代码
package com.young.order.controller;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.RestController;/*** @author 杨胖胖*/@RestController@RequestMapping("flow")@Slf4jpublic class FlowLimitController {@GetMapping("a")public String testA(){log.info("调用A");return "A";}@GetMapping("b")public String testB(){log.info("调用B");return "B";}}
快速请求这个接口让qps大于1,现在就能看到这个错误。
再来看一下这个关联
现在通过jmeter来访问flow/b
然后浏览器访问flow/a 看一下效果,已经被限流
预热默认的clodFactor为3,即请求QPS从threshold/3开始,经过预热时长达到阈值。
这张图也就是5秒内10/3慢慢预热到10
测试的时候可以通过浏览器一直请求,你会发现点很快的时候请求会被拒绝,但是慢慢的就正常了,因为完成预热了,阈值变成10了。
匀速排队其实可以看一下官网的解释
降级
异常数与异常比例都好理解这里就不再赘述了

测试代码
@GetMapping("c")public String testC() throws InterruptedException {TimeUnit.SECONDS.sleep(1);log.info("调用C");return "C";}
热点规则
配置热点规则为第0个参数,阈值1,大于阈值1秒内抛出异常

测试代码
@GetMapping("d")@SentinelResource(value = "flow/d", blockHandler = "deal")public String testD(String p1, String p2) {log.info("调用D");return "D";}public String deal(String p1, String p2, BlockException blockException){return "自定义异常";}
请求超出阈值后的效果
请求其它参数不会受到规则的影响
高级配置,参数值为5的时候阈值300
执行看一下效果,都是能正常请求的。

SentinelResource统一触发规则配置
import com.alibaba.csp.sentinel.slots.block.BlockException;/*** @author 杨胖胖*/public class SentinelHandler {public static String handlerException1(BlockException blockException) {return "全局自定义sentinel异常处理1";}public static String handlerException2(BlockException blockException) {return "全局自定义sentinel异常处理2";}}
@GetMapping("e")@SentinelResource(value = "flow/e", blockHandlerClass = SentinelHandler.class,blockHandler = "handlerException1")public String testE() {log.info("调用E");return "E";}

测试效果
处理代码的异常,全局可以配置fallbackClass,这里只演示fallback
@GetMapping("f")@SentinelResource(value = "flow/e", fallback = "handlerFallback")public String testF() {throw new RuntimeException("异常");}public String handlerFallback() {return "自定义代码异常处理";}
测试效果
exceptionsToIgnore可以让抛异常的方法不走fallback,这里不演示了。
持久化到Nacos
持久化需要加入这个依赖
<!-- sentinel持久化--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>
配置,我这里是配合着上面的配置一直玩的
server:port: 11220spring:cloud:sentinel:transport:dashboard: 127.0.0.1:9999# sentinel与控制台通信的端口,默认8719重复了会自动+1port: 8719datasource:ds1:nacos:server-addr: 1.116.220.231:10480dataId: order-datagroupId: DEFAULT_GROUPdata-type: jsonrule-type: flownamespace: c698366c-d971-43bc-a846-fe416f56aed3
解释一下配置的意思
这里配置的是json,我们还需要到nacos里面配置,yaml里面的 dataId: order-data和nacos这里的名字对应
这里就已经能看到配置生效了
请求一下接口,目前已经达到我们的目的了
3.Fegin
pom添加依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
@SpringBootApplication// 启动类添加fegin注解@EnableFeignClientspublic class StockApplication {public static void main(String[] args) {SpringApplication.run(StockApplication.class);}}
现在需要去调用订单接口的order/pay,编写feignClient
/*** @author 杨胖胖*/// 这里的name=order其实是注册到nacos上微服务的名字,这样请求的时候就是去nacos里面拿注册的服务@FeignClient(name="order")public interface OrderFeignClient {/*** 下单* @return 订单信息*/@GetMapping("order/pay")Order order();}
Controller来测试一下,我这里启动了两个order服务,feign默认集成了ribbon,ribbon默认负载均衡是轮询,这里要集成nacos,ribbon才能生效
/*** @author 杨胖胖*/@RestController@RequestMapping("stock")@RequiredArgsConstructor(onConstructor = @__(@Autowired))@Slf4jpublic class StockController {private final OrderFeignClient orderFeignClient;@GetMapping("query")public String stock() {log.info("调用订单信息:{}", orderFeignClient.order());return "查看订单";}}

接口请求了四次的效果,果然是轮询
日志级别
代码配置日志
定义一个日志类
/*** @author 杨胖胖*/public class OrderFeignConfiguration {@Beanpublic Logger.Level level() {return Logger.Level.FULL;}}
/*** @author 杨胖胖*/@FeignClient(name = "order",configuration = OrderFeignConfiguration.class)public interface OrderFeignClient {/*** 下单** @return 订单信息*/@GetMapping("order/pay")Order order();}
application.yml添加日志配置
logging:level:com.stock.feignclient.OrderFeignClient: debug
访问一下看看效果
全局日志配置
代码的全局配置,记得把之前局部配置的去掉
@SpringBootApplication@EnableFeignClients(defaultConfiguration = OrderFeignConfiguration.class)public class StockApplication {public static void main(String[] args) {SpringApplication.run(StockApplication.class);}}
配置文件的全局
feign:client:config:# 指定微服务的日志级别,default代表全局# order:default:loggerLevel: full
多参数构造与常见问题
https://www.imooc.com/article/289000
https://www.imooc.com/article/289005
fegin脱离ribbon访问任意的url
@FeignClient(name = "baidu", url = "https://www.baidu.com/")public interface TestBaidu {@GetMapping("")String index();}
/*** @author 杨胖胖*/@RestController@RequestMapping("stock")@RequiredArgsConstructor(onConstructor = @__(@Autowired))@Slf4jpublic class StockController {private final OrderFeignClient orderFeignClient;private final TestBaidu testBaidu;@GetMapping("query")public String stock() {log.info("调用订单信息:{}", orderFeignClient.order());return "查看订单";}@GetMapping("baidu")public String baidu() {return testBaidu.index();}}
访问效果
性能优化
fegin使用httpclient去请求而不是用默认的urlconnect
添加依赖
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId></dependency>
添加配置
feign:httpclient:enabled: true
4.Gateway
新建一个gateway项目引入依赖
老样子我们要集成nacos一起使用
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>
application.yml配置,在没有配置routes的情况下,nacos+gateway启用了locator.enabled配置,访问的时候只需要路径带服务器名称和地址就能通过网关去访问。
server:port: 11330spring:cloud:nacos:server-addr: 1.116.220.231:10480discovery:namespace: c698366c-d971-43bc-a846-fe416f56aed3group: DEFAULT_GROUPgateway:discovery:locator:# 让gateway通过服务发现组件找到其它微服务enabled: trueapplication:name: gateway
看一下效果
http://127.0.0.1:11330/secret-order/order/pay
自定义谓词工厂
@Datapublic class TimeBeweenConfig {private LocalTime start;private LocalTime end;}
@Componentpublic class TimeBetweenRoutePredicateFactoryextends AbstractRoutePredicateFactory<TimeBeweenConfig> {public TimeBetweenRoutePredicateFactory() {super(TimeBeweenConfig.class);}@Overridepublic Predicate<ServerWebExchange> apply(TimeBeweenConfig config) {LocalTime start = config.getStart();LocalTime end = config.getEnd();return exchange -> {LocalTime now = LocalTime.now();return now.isAfter(start) && now.isBefore(end);};}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("start", "end");}public static void main(String[] args) {DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);System.out.println(formatter.format(LocalTime.now()));}}
配置加上这段routes,只允许上午4:00,下午12:00访问,其它时间访问都是404
server:port: 11330spring:cloud:nacos:server-addr: 1.116.220.231:10480discovery:namespace: c698366c-d971-43bc-a846-fe416f56aed3group: DEFAULT_GROUPgateway:discovery:locator:# 让gateway通过服务发现组件找到其它微服务enabled: trueroutes:- id: after-routeuri: lb://secret-orderpredicates:- After=2030-01-20T17:43:00.789-07:00[America/Denver]- TimeBetween=上午4:00,下午12:00application:name: gateway
测试的时候遇到一个小坑:
访问的地址得是127.0.0.1:11330/order/pay而不是127.0.0.1:11330/secret-order/order/pay
因为这个是研究到了深夜,真是无语嘞。
看到大目老师的解释我才恍然大悟。
