SpringCloud2
糊涂工具包:https://www.hutool.cn/
代码地址:别人的:https://gitee.com/lixiaogou/cloud2020.git 自己的:https://gitee.com/wtt-22/cloud2021.git
初级项目
- springboot和springCloud的版本之间互相依赖网址:https://start.spring.io/actuator/info
- 子项目中引入依赖版本号就用自己的,如果没有引用那么去父工程找用dependencyManagement定义版本号
- 服务注册中心的作用:如果是一对一的服务,那么用restTemplate就可以调用
在消费者里面添加restTemplate就可以调用生产者
@RestController
@Slf4j
public class OrderController {
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/create")
public CommonResult<Payment> create(Payment payment) {
CommonResult commonResult = restTemplate.postForObject("http://localhost:8001/payment/create", payment, CommonResult.class);
return commonResult;
}
}
需要在配置类里配置一下
@Configuration
public class ApplicationContextConfig {
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
Erueka注册中心
DiscoveryClient
@GetMapping("/payment/discovery")
public Object getDiscoveryClient() {
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info("所有服务:"+service);
}
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info("当前的服务里有哪些"+instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
}
return discoveryClient;
}
启动类加上这个注解
Eureka自我保护机制
采用ap思想:高可用和容错性
导致原因:
好死不如赖活着
怎么禁止自我保护
。。。
Zookeeper
他的节点事临时性的,cp 一致性和容错性,当一个服务在心跳机制内没有回应,直接删除这个节点。
consul
三个的同异
Ribbon
和nginx得区别
nginx
ribbon
ribbon得规则替换
- 首先这个配置类不能放在跟启动类一级或者子集下边,不能让他扫描到。
@Configuration
public class MySelfRule {
//随机算法
@Bean
public IRule myRule() {
return new RandomRule();
}
}
3. @RibbonClient(name = “CLOUD-PAYMENT-SERVICE”,configuration = MySelfRule.class)
负载均衡算法:底层源码就是用cas算法atomicInteger.compareAndSet()自旋锁
IRule体系结构
OpenFeign
自己集成了ribbon
feign是在消费端使用的,一开始我们是使用得ribbon+resttemplate,现在直接用feign就可以解决服务间的调用。定义一个接口,在接口上面添加一些注解。
步骤
openfeign的超时控制
消费者调用提供者:openfeign默认等待1秒,如果结果1s内没有返回,直接报错。
但是如果我们的业务逻辑需要大于1s的时间去运行,那么就会报错,所以要双方商量一个时间。
由ribbon来控制(配置在消费者端)
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下, 两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
openfeign日志
- 日志级别
- 步骤
- 配置一个Config类并且注入这个类
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
- 在yml里面配置
logging:
level:
# feign日志以 debug 级别监控 com.atguigu.springcloud.service.PaymentFeignService 接口
com.atguigu.springcloud.service.PaymentFeignService: debug
Hystrix
服务降级
为什么要用服务降级(一般用在消费端,但是服务端也可以用)
是什么,服务熔断的理念
能干什么
-
服务降级 fallback
-
服务熔断 break
-
服务限流
hystrix是tomcat里面的线程来工作的
-
导致卡顿的原因
-
解决办法
-
服务降级配置
@HystrixCommand -
先看提供者(先解决内忧)
首先在方法上加注解
然后再启动类上开启这个注解@EnableCircuitBreaker
降级是用另一个线程池运行,这样有很好的隔离性 -
消费者(再解决外患)一般是在消费者这降级
- 在yml里添加配置
feign:
hystrix:
enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样
- 在主启动类加这个注解@EnableHystrix
- 在消费者controller类中
@HystrixCommand(fallbackMethod = "paymentInfo",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
})
疑问:如果每个方法配置一个降级的代码会膨胀,而且兜底的方法和业务逻辑混在一起,耦合度高。
所以要配置一个默认的,如果没有配置就走默认的,如果有就走精确配置的
@DefaultProperties(defaultFallback = "paymentInfo")
@HystrixCommand
public String paymentInfo(Integer id) {
return "我是消费者80,程序现在有问题 ~~~~/(ㄒoㄒ)/~~";
}
这些都是在消费者controller层做的事情,但是代码还是耦合度很高,所以打算从service入手,因为消费者想要调用服务就必须用feign,用feign就有一个对应的接口,里面有提供者所有的暴露的方法。
4. 新建一个类来实现接口
yml里面开启
继承上面feign接口的方法,对每个方法进行实现
在接口哪个类上把fallback实现类加进去
服务熔断
参数的含义
当请求中失败的次数到达你设定的值时,这时候你发送正常的请求也会降级,正确的请求多了之后,服务就会慢慢的恢复过来。
断路器打开之后
配置
服务限流
第四步:@EnableHystrixDashboard注解
第五步:pom里面都要依赖这个
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
被监控的服务最好有两个依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
springcloud升级后的坑,在被监控的服务器启动类配置
/**
* 注意:新版本Hystrix需要在主启动类中指定监控路径
* 此配置是为了服务监控而配置,与服务容错本身无关,spring cloud升级后的坑
* ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
* 只要在自己的项目里配置上下面的servlet就可以了
*
* @return ServletRegistrationBean
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
// 一启动就加载
registrationBean.setLoadOnStartup(1);
// 添加url
registrationBean.addUrlMappings("/hystrix.stream");
// 设置名称
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
每个的含义:
Gateway
为什么选择gateway
- 架构方面
- 技术方面
gateway三大核心
Route路由
概念:路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言位true则匹配该路由。
- gateway网关yml配置
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
#uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/getPaymentById/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
#uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/LB/** # 断言,路径相匹配的进行路由
- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
# - Before=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
# - Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai] , 2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
# curl http://localhost:9527/payment/lb --cookie "username=zzyy"
# - Cookie=username,zzyy #Cookie=cookieName,正则表达式
# 请求头要有X-Request-Id属性并且值为整数的正则表达式 curl http://localhost:9527/payment/lb --cookie "username=zzyy" -H "X-Request-Id:11"
# - Header=X-Request-Id, \d+
# - Host=**.atguigu.com # curl http://localhost:9527/payment/lb -H "Host:afae.atguigu.com"
- 硬编码格式,在代码里写
@Configuration
public class GateWayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_route_atguigu",
r -> r.path("/guoji").uri("http://news.baidu.com/guonei"))//访问locahost:7527/guoji的时候会转发到http://news.baidu.com/guonei地址
.build();
return routes.build();
}
}
实现动态路由
首先加上这个开启动态路由
然后配置服务名
Predicate断言
概念:
获得这个时区串串
-After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
常用的路由断言predicate
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/LB/** # 断言,路径相匹配的进行路由
- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
# - Before=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
# - Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai] , 2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
# curl http://localhost:9527/payment/lb --cookie "username=zzyy" 必须像这样
# - Cookie=username,zzyy #Cookie=cookieName,正则表达式
# 请求头要有X-Request-Id属性并且值为整数的正则表达式 curl http://localhost:9527/payment/lb --cookie "username=zzyy" -H "X-Request-Id:11"
# - Header=X-Request-Id, \d+ #请求头正则表达式是正数
# - Host=**.atguigu.com # curl http://localhost:9527/payment/lb -H "Host:afae.atguigu.com" 主机
# - Method = Get #请求方式是get
# - Query = username,\d+ #条件?必须有username而且是正数
Filter过滤
概念:
自定义过滤器
@Component
@Slf4j
public class MyLogGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*****************come in MyLogGatewayFilter" + new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null) {
log.info("用户为空,非法用户/(ㄒoㄒ)/~~");
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {//加载过滤器的顺序,数字越小优先级越高
return 0;
}
}
Config
概念
配置中心yml
3344直连gitee 3355连接3344 ,会导致gitee上的代码修改了,但是3355还是以前的版本所以要手动刷新路由。
yml
# 暴露监控端点 否则 curl -X POST "http://localhost:3355/actuator/refresh" 不可使用
management:
endpoints:
web:
exposure:
include: "*"
controller里面加@RefreshScope //刷新路由 注解
但是还是要手动去发送一个post请求,告诉3355刷新:curl -X POST “http://localhost:3355/actuator/refresh”
所以引出了消息总线Bus
Bus
rabbitmq 安装目录的sbin目录下cmd 执行rabbitmq-plugins enable rabbitmq_management命令。win10开始按钮出现可视化开启和关闭。
默认用户和密码:guest guest
动态刷新全局广播
选用服务端通知各个客户端:
这个是服务端新增的配置
1.pom
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2.yml
#rabbitmq相关配置
rabbitmq:
host: localhost
port: 15672
username: guest
password: guest
##rabbitmq相关配置,暴露bus刷新配置的端点 SpringCloud Bus动态刷新全局广播
management:
endpoints: #暴露bus刷新配置的端点
web:
exposure:
include: 'bus-refresh'
客户端
1.pom
<!--添加消息总线RabbitMQ支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2.yml
#rabbitmq相关配置
rabbitmq:
host: localhost
port: 15672
username: guest
password: guest
发送post请求刷新3344,由3344广播所有客户端。
curl -X POST “http://localhost:3344/actuator/bus-refresh”
动态刷新定点通知
Stream
作用:屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型
生产者8801
消费者8802
pom
会有重复消费问题,因为两个微服务默认是两个组
问题:消费者都配置为同一个组的就不会出现重复消费的现象
持久化:配置这个分组就算宕机了之后在重启,直接就会去rabbitmq中消费,如果不配置这个分组,宕机之后不会再去消费
Sleuth 链路监控
pom添加依赖
yml
高级篇
SpringCloud Alibaba
github:https://github.com/alibaba/spring-cloud-alibaba
Nacos
官网:https://nacos.io/zh-cn/
安装启动nacos
- 基础配置
- 作为注册中心,默认地址是8848
启动类添加@EnableDiscoveryClient注解 - 作为配置中心 3377
bootstrap.yml
application.yml
对应的nacos的dataid 为这个
${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
- 分类配置
组 :bootstrap.yml
命名空间namespace