SpringCloud
1.Eureka服务注册与发现
1.1Eureka基础知识
服务治理
- SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理
在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂、所以需要进行服务治理,管理服务与服务之间依赖关联,以实现服务调用,负载均衡、容错等,实现服务发现与注册
服务注册
- Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心
1.2Eureka注册中心应用实例
启动顺序:先启动注册中心,先启动生产者,再启动消费者
注册模块
pom文件
<!--引入Eureka服务端组件: 所以当前项目就是一个注册中心--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
yml配置文件
server: port: 7001 #ip:服务端口号 访问注册中心页面 eureka: instance: hostname: localhost client: #当前应用是一个注册中心,不需要将自己注册到注册中心上,注册中心集群环境,需要注册 register-with-eureka: false #从注册中心上抓取服务列表,因为自身就是注册中心,所有无需抓取,集群环境需要抓取 fetchRegistry: false #服务地址 service-url: defaultZone: http://localhost:7001/eureka
启动类
//启动注册中心服务端 @EnableEurekaServer @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } }
服务发布者模块
yml配置
eureka: client: register-with-eureka: true fetchRegistry: true service-url: defaultZone: http://localhost:7001/eureka
pom文件
<!--eureka客户端模块--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
启动类
//Eureka客户端 @EnableEurekaClient @SpringBootApplication public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); } }
服务消费者模块
- yml pom 启动类文件与发布者相同
config配置文件
//创建远程调用配置 @SpringBootConfiguration public class ApplicationContextConfig { @Bean @LoadBalanced //远程调用进行负载均衡,不加该注解只能用固定url进行访问 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
controller进行远程调用
@RestController @Slf4j public class OrderController { //不能写死,应该用服务注册名 // public static final String PAYMENT_URL = "http://localhost:8001"; public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"; //创建远程调用 @Autowired private RestTemplate restTemplate; @PostMapping("/consumer/payment/create") public CommonResult<Payment> create(Payment payment){ return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class); //写操作 } @GetMapping("/consumer/payment/get/{id}") public CommonResult<Payment> getPayment(@PathVariable("id") Long id){ return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class); } }
2.Ribbon负载均衡
2.1Ribbon简介
- Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具
- Ribbon客户端组件提供一系列完善的配置项,如:连接超时,重试等
- 在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器
2.2 Ribbon功能
- 提供客户端的软件负载均衡算法和服务调用,LB(负载均衡)就是将用户的请求平均分配到多个服务器上,从而达到系统的HA(高可用),常见的负载均衡有软件Nginx,LVS,硬件F5
Ribbon的本地负载均衡客户端 vs Nginx服务端负载均衡区别
- Nginx是服务器负载均衡,客户端所有请求都会交给Nginx,然后,由nginx实现转发请求。即负载均衡是由服务器端完成的
- Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用
- Ribbon=负载均衡+RestTemplate调用
2.2 Ribbon 工作原理
- 第一步,先选择EurekaServer,它优先选择在同一个区域内负载较少的server
- 第二步,再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略。比如:轮询、随机和根据响应时间加权
总结:Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例
2.3 应用实例
pom坐标 (Eureka客户端自带Ribbon)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
默认策略是轮询策略 只需要添加@LoadBalanced注解即可实现轮询访问
//消费端创建远程调用配置 @SpringBootConfiguration public class ApplicationContextConfig { @Bean @LoadBalanced //远程调用进行负载均衡,不加该注解只能用固定url进行访问 默认是轮训策略,即每个服务访问一次 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
修改轮询策略
消费端要创建不在主程序扫描类路径范围的包
@Configuration //标明为配置类 public class MySelfRule { //修改访问策略为随机 @Bean public IRule randomRule(){ return new RandomRule(); } }
+ 其他策略
+ com.netflix.loadbalancer.**RoundRobinRule 轮询**,默认策略。
+ com.netflix.loadbalancer.**RandomRule 随机**
+ com.netflix.loadbalancer.**RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务**
+ **WeightedResponseTimeRule** 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
+ **BestAvailableRule** 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
+ **AvailabilityFilteringRule** 先过滤掉故障实例,再选择并发较小的实例
+ **ZoneAvoidanceRule** 默认规则,复合判断server所在区域的性能和server的可用性选择服务器
启动类添加注解 @RibbonClient
//指定哪一个服务进行随机轮询策略 name指定服务名 configuration指定配置类 @RibbonClient(name="CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class) //Eureka客户端 @EnableEurekaClient @SpringBootApplication public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class,args); } }
3.OpenFeign服务接口调用
3.1 openFeign简介
- Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可
- SpringCloud对Feign进行了封装,使其支持了SpringMVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡
3.2openFeign功能
- 在使用编写Java Http客户端变得更容易
- 在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是DAO接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可,即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量
- Feign集成了 Ribbon
利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
3.3 应用实例
pom坐标
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
yml配置
server: port: 80 spring: application: name: cloud-consumer-feign-order80 eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:7001/eureka
启动类
@SpringBootApplication @EnableEurekaClient //启用Eureka客户端 @EnableFeignClients//启用feign接口 public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class,args); } }
service层
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id); }
controller层
@RestController public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; //调用远程的微服接口 @GetMapping(value = "/consumer/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){ return paymentFeignService.getPaymentById(id); } }
3.4feign超时控制
- Feign客户端默认只等待一秒钟,如果服务端处理需要超过1秒钟,会导致Feign客户端直接报错
设置超时控制
- 使用Feign调用接口分两层,ribbon的调用和hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间
修改配置文件
#设置Feign客户端超时时间(openfeign默认支持ribbon) ribbon: ReadTimeout: 3000 ConnectTimeout: 3000 MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用 MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用 OkToRetryOnAllOperations: false #是否所有操作都重试 #hystrix的超时时间 hystrix: command: default: execution: timeout: enabled: true isolation: thread: timeoutInMilliseconds: 9000
- 一般情况下 都是 ribbon 的超时时间(<)hystrix的超时时间(因为涉及到ribbon的重试机制)
- 根据上面的参数计算重试的次数:MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries *MaxAutoRetriesNextServer) 即重试3次 则一共产生4次调用
- 如果在重试期间,时间超过了hystrix的超时时间,便会立即执行熔断,fallback。所以要根据上面配置的参数计算hystrix的超时时间,使得在重试期间不能达到hystrix的超时时间,不然重试机制就会没有意义
hystrix超时时间的计算: (1 + MaxAutoRetries + MaxAutoRetriesNextServer) ReadTimeout 即按照以上的配置 hystrix的超时时间应该配置为 (1+1+1)3=9秒
- 当ribbon超时后且hystrix没有超时,便会采取重试机制。当OkToRetryOnAllOperations设置为false时,只会对get请求进行重试。如果设置为true,便会对所有的请求进行重试,如果是put或post等写操作,如果服务器接口没做幂等性,会产生不好的结果,所以OkToRetryOnAllOperations慎用。
- 如果不配置ribbon的重试次数,默认会重试一次 (注意:默认情况下,GET方式请求无论是连接异常还是读取异常,都会进行重试.非GET方式请求,只有连接异常时,才会进行重试)
3.5feign日志输出
- Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节
日志级别
- NONE:默认的,不显示任何日志
- BASIC:仅记录请求方法、RUL、响应状态码及执行时间
- HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息
- FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据
yml (配置在消费者端)
logging: level: com.atguigu.springcloud.service.PaymentFeignService: debug
配置对象 (配置在消费者端)
import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { @Bean public Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
4.Hystrix断路器
4.1 hystrix断路器简介
- 复杂分布式体系结构中的应用程序有数十个依赖关系,每一个依赖关系在某些时候将不可避免的失败.多个模块发生依赖,容易造成服务雪崩不可用
- Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性
- “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(Fallback),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩
4.2 hystrix断路器功能
服务降级
- 服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示
哪些情况会触发降级
- 程序运行异常
- 超时自动降级
- 服务熔断触发服务降级
- 线程池/信号量打满也会导致服务降级
- 人工降级
- 生产端,消费端都可以进行服务降级,大多数情况是在消费端降级
服务熔断
- 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示,就是保险丝
- 服务的降级->进而熔断->恢复调用链路
服务限流
- 秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
4.3 hystrix服务降级使用案例
pom坐标
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
生产端服务降级测试
测试方法 impl层
//用于设置降级处理的配置 @HystrixCommand(fallbackMethod = "payment_TimeoutHandler",commandProperties = { @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000") //5秒钟以内就是正常的业务逻辑 }) @GetMapping("/payment/hystrix/timeout/{id}") public String payment_Timeout(Integer id){ int timeNumber = 6; try { TimeUnit.SECONDS.sleep(timeNumber); }catch (Exception e) {e.printStackTrace();} return "线程池:"+Thread.currentThread().getName()+" paymentInfo_TimeOut,id: "+id+"\t"+"呜呜呜"+" 耗时(秒)"+timeNumber; } //兜底方法,上面方法出问题,我来处理,返回一个出错信息 public String payment_TimeoutHandler(Integer id) { return "线程池:"+Thread.currentThread().getName()+" payment_TimeoutHandler,系统繁忙,请稍后再试\t o(╥﹏╥)o "; }
- 启动类开启 @EnableCircuitBreaker //开启熔断器
- 超时和异常情况都会走兜底方法
消费端服务降级测试
测试方法 controller层
//超时降级演示 @HystrixCommand(fallbackMethod = "payment_TimeoutHandler",commandProperties = { @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")//超过1.5秒就降级自己 }) @GetMapping("/consumer/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentHystrixService.payment_Timeout(id); log.info("*******result:"+result); return result; } //兜底方法,上面方法出问题,我来处理,返回一个出错信息 public String payment_TimeoutHandler(Integer id) { return "我是消费者80,对方支付系统繁忙请10秒后再试。或自己运行出错,请检查自己。"; }
yml配置开启
feign: hystrix: enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
- 启动类开启 @EnableHystrix (@EnableHystrix等价于@EnableCircuitBreaker )
4.4 hystrix服务降级 全局降级方法
- 服务降级方法类名上加 @DefaultProperties(defaultFallback = "payment_TimeoutHandler") //全局降级方法
全局降级方法
public String payment_Global_FallbackMethod(){ return "Global异常处理信息,请稍后再试,(┬_┬)"; }
降级处理方法
//超时降级演示 @HystrixCommand(commandProperties = { @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")//超过1.5秒就降级自己 }) @GetMapping("/consumer/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id){ String result = paymentHystrixService.payment_Timeout(id); log.info("*******result:"+result); return result; }
- 如果方法有自己的降级方法,则优先级大于全局降级方法
4.5 hystrix服务降级 降级方法与业务方法分离
消费端实例
实现远程调用方法
import org.springframework.stereotype.Component; @Component public class PaymentFallbackService implements PaymentHystrixService { @Override public String paymentInfo_OK(Integer id) { return "-----PaymentFallbackService fall back-paymentInfo_OK , (┬_┬)"; } @Override public String paymentInfo_TimeOut(Integer id) { return "-----PaymentFallbackService fall back-paymentInfo_TimeOut , (┬_┬)"; } }
远程调用方法 fallback指定降级实现类
@Component @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class) public interface PaymentHystrixService { @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id); @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id); }
yml配置
feign: hystrix: enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
4.6hystrix 服务熔断
熔断概念
- 熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息
- 当检测到该节点微服务调用响应正常后,恢复调用链路
- 在SpringCloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状态,当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@HystrixCommand
实例
熔断方法 达到设定参数后,即便参数正确也会走降级方法,过段时间自己恢复
//服务熔断 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //当在配置时间窗口(默认10s)内达到此数量的失败后,打开断路,默认20个 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //断路多久以后开始尝试是否恢复,默认5s @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //出错百分比阈值,当达到此阈值后,开始短路。默认50% }) public String paymentCircuitBreaker(Integer id){ if (id < 0) throw new RuntimeException("*****id 不能负数"); String serialNumber = IdUtil.simpleUUID();//hutool.cn工具包 return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber; } //降级方法 public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){ return "id 不能负数,请稍候再试,(┬_┬)/~~ id: " +id; }
参数
快照时间窗、请求总数阈值、错误百分比阈值
- 快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒
- 请求总数阈值:在快照时间窗内,必须满足请求总数阈值才有资格熔断。默认20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。
- 错误百分比阈值:当请求总数在快照时间窗内超过了阈值,比如发生了30次调用,如果在这30次调用,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阈值情况下,这时候就会将断路器打开
4.7 hystrix 服务监控hystrixDashboard
- 概述: 除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stram项目实现了对以上指示的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面
创建单独监测模块
pom坐标
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
- 启动类加 @EnableHystrixDashboard
被监测目标生产者模块
pom
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
配置bean对象
/** *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑 *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream", *只要在自己的项目里配置上下面的servlet就可以了 */ @Bean public ServletRegistrationBean getServlet() { HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); registrationBean.setLoadOnStartup(1); registrationBean.addUrlMappings("/hystrix.stream");//流路径 registrationBean.setName("HystrixMetricsStreamServlet"); return registrationBean; }
测试
- 打开监控页面 监控模块地址 ip:端口号/hystrix
- 填入监测模块的数据流 (http://localhost:8001/hystrix.stream)
阅读可视化界面
- 实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。
该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实体中快速的发现故障实例和高压力实例
- 曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势
5.gateway 网关
5.1 网关概述
- 官网 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
- cloud全家桶1.0版本使用的网关为Zuul网关.2.0以后换位自己开发的gateway网关
- Gateway是在spring生态系统之上构建的API网关服务,基于Spring5,SpringBoot2和Project Reactor等技术。
- Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等
- Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通讯框架Netty
- Gateway的目标提供统一的路由方式且基于Filter链的方式提供了网关基本的功能,例如:安全、监控/指标、和限流
5.2 网关作用
- 反向代理
- 鉴权
- 流量控制
- 熔断
- 日志监控
5.3 网关三大核心概念
Route路由
- 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
Predicate 断言
- 参考的是java8的java.util.function.Predicate
- 开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
Filter 过滤
- 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改
总结
- Web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。
Predicate就是我们的匹配条件: 而Filter,就是可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标url,就可以实现一个具体的路由了
- 客户端向Spring Cloud Gateway发出请求。然后在Gateway Handler Mapping中找到与请求匹配的路由,将其发送到Gateway Web Handler.
Handler再通过指定的过滤器链来将请求发送给我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前("pre")或之后("post")执行业务逻辑。
Filter在*"pre"类型*的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在*"post"类型*的过滤器中可以做响应内容、响应头的修改,日志的输出,流量控制等有着非常重要的作用
5.4 网关代理应用
pom
<!--新增gateway,不需要引入web和actuator模块--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
yml配置文件
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: routes: - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名 uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: - Path=/payment/get/** #断言,路径相匹配的进行路由 - id: payment_routh2 uri: http://localhost:8001 predicates: - Path=/payment/lb/** #断言,路径相匹配的进行路由
5.5 通过微服务名实现动态路由
- 默认情况下Gateway会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
yml配置
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由 routes: - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名 #uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service #uri的协议为lb,表示启用Gateway的负载均衡功能 predicates: - Path=/payment/get/** #断言,路径相匹配的进行路由 - id: payment_routh2 #uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service predicates: - Path=/payment/lb/** #断言,路径相匹配的进行路由 eureka: instance: hostname: cloud-gateway-service client: service-url: register-with-eureka: true fetch-registry: true defaultZone: http://localhost:7001/eureka
5.6 断言 Predicate
概述
- Gateway将路由匹配作为Spring WebFlux HandlerMapper基础框架的一部分
- Gateway包括许多内置的Route Predicate工厂,所有这些Predicate都与HTTP请求的不同属性匹配,多个Route Predicate工厂可以进行组合
- Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给 Route
- Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理
常用断言 ( yml 配置下 predicates数组)
After Route Predicate 未到指定时间不能进行访问
- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
Before Route Predicate 在这时间之前访问
- Before=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
Between Route Predicate 在时间之后访问
- Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
Cookie Route Predicate 携带指定cookie才能访问
- Cookie=username,zhangshuai #并且Cookie是username=zhangshuai才能访问
Header Route Predicate 请求头中有指定值才行
- Header=X-Request-Id, \d+ #请求头中要有X-Request-Id属性并且值为整数的正则表达式
Host Route Predicate 地址为指定路径
- Host=**.atguigu.com
Method Route Predicate 指定请求方式
- Method=GET
Path Route Predicate 指定路径
- Path=/payment/lb/** #断言,路径相匹配的进行路由
Query Route Predicate 参数名称为指定值才能访问路由
- Query=username, \d+ #要有参数名称并且是正整数才能路由
5.7 自定义过滤器
编写过滤器组件
@Component @Slf4j //GlobalFilter全局过滤器 public class MyLogGateWayFilter implements GlobalFilter,Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("*********come in MyLogGateWayFilter: "+new Date()); //getFirst获取第一个参数 String username = exchange.getRequest().getQueryParams().getFirst("username"); if(!Objects.equals(username, "zhaoyongbin")){ //可以校验token 达到鉴权效果 log.info("*****用户名为{}非法用户,(┬_┬)",username); exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); //禁止访问 return exchange.getResponse().setComplete(); } //放行 return chain.filter(exchange); } /** * 设置过滤器执行顺序,数值越低,优先级越搞 * * @return */ @Override public int getOrder() { return 0; } }
6. SpringCloud Sleuth分布式链路请求跟踪
6.1概述
- 在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一个复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败,Spring Cloud Sleuth提供了一套完整的服务跟踪的解决方案
- Sleuth在分布式系统中提供追踪解决方案并且兼容支持了zipkin(负责展现)
6.2 搭建链路追踪步骤
- 下载zipkin https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/
- 运行jar 控制台 http://localhost:9411/zipkin/
- 完整的调用链路,表示一请求链路,一条链路通过Trace Id唯一标识,Span标识发起的请求信息,各span通过parent id 关联起来。
需要链路追踪的服务都要加pom坐标跟yml配置
pom
<!--包含了sleuth+zipkin--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
yml
server: port: 8001 spring: application: name: cloud-payment-service zipkin: base-url: http://localhost:9411 sleuth: sampler: #采样率值介于0~1之间,1表示全部采样 probability: 1
7.SpringCloud Alibaba
7.1简介
- 网飞公司的Hystrix和Ribbon都停止更新,由阿里推出的一套可替代的开发组件
组件功能
- Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
- Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
- RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
- Dubbo:Apache Dubbo™ 是一款高性能 Java RPC 框架。
- Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
- Alibaba Cloud ACM:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。
- Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
- Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
- Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
组件pom坐标
<!--spring cloud alibaba 2.1.0.RELEASE--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
- 组件学习网站 官网:https://spring.io/projects/spring-cloud-alibaba#overview
7.2 nacos服务注册和配置中心
7.2.1 nacos简介
- 前四个字母分别为Naming和Configuration的前两个字母,最后的s为Service,即nacos
- Nacos就是注册中心+配置中心的组合 等价于:Nacos = Eureka+Config+Bus
- 区别于Eureka,nacos可以单独部署模块,而不需要自己搭建
7.2.2 下载安装nacos
- 官网文档 https://nacos.io/zh-cn/index.html
- github地址 https://github.com/alibaba/Nacos
- 需要java8+ maven的环境
- 下载软件 https://github.com/alibaba/nacos/releases/tag/1.1.4
- 管理员权限运行 /Users/zyb/Documents/java/nacos/bin/startup.sh -m standalone
- 运行成功后 地址 http://localhost:8848/nacos 默认账号密码都是nacos
7.2.3 注册中心测试
父模块
<!--spring cloud alibaba 2.1.0.RELEASE--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
生产者模块
依赖注册中心的子模块
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
yml配置
server: port: 9001 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848 #配置Nacos地址 management: endpoints: web: exposure: include: '*' #默认只公开了/health和/info端点,要想暴露所有端点只需设置成星号
- 主启动类注解 @EnableDiscoveryClient
(等价于@EanbleEurekaClient 适用于Eureka nacos zookeeper consul注册中心)
消费者模块 pom坐标 启动类注解相同
yml配置
server: port: 83 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: localhost:8848 #消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者【可选】,注意:nacos-payment-provider含有IP和端口) #自定常量 service-url: nacos-user-service: http://nacos-payment-provider
远程调用配置bean
@Configuration public class ApplicationContextConfig{ @Bean @LoadBalanced //开启轮询负载均衡 nacos包含了ribbon的包 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
controller层
@RestController @Slf4j public class OrderNacosController{ @Resource private RestTemplate restTemplate; @Value("${service-url.nacos-user-service}") private String serverURL; @GetMapping(value = "/consumer/payment/nacos/{id}") public String paymentInfo(@PathVariable("id") Long id){ return restTemplate.getForObject(serverURL+"/payment/nacos/"+id,String.class); } }
7.2.4 Nacos 和cap定理
CAP定理
- 一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
- 可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
- 分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择
- CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP
常用注册中心类型
Nacos支持AP和CP模式的切换
curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
- eureka AP
- zookeeper CP
7.2.5 Nacos 注册中心功能
引入pom坐标
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
yml配置
- Nacos同springcloud-config一样,在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动
- springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application
bootstrap.yml
server: port: 3377 spring: application: name: nacos-config-client cloud: nacos: discovery: server-addr: localhost:8848 #服务注册中心地址 config: server-addr: localhost:8848 #配置中心地址 file-extension: yaml #指定yaml格式的配置(yml和yaml都可以)
application.yml
spring: profiles: active: dev #表示开发环境
- 主启动类注解 @EnableDiscoveryClient
controller 主要是@RefreshScope 注解
@RestController @RefreshScope //通过SpringCould原生注解@RefreshScope实现配置自动更新 public class ConfigClientController{ @Value("${config.info}") //对应nacos配置:nacos-config-client-dev.yaml //${config.info}也可以写在配置文件的属性值上,然后再读取对应属性名称,间接获取云端配置 private String configInfo; @GetMapping("/config/info") public String getConfigInfo() { return configInfo; } }
云端添加配置
- 配置列表->新建配置->dataID 公式得出->选择合适的格式
dataID
- ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
- 若 spring.profile.active为空 则连接符-也不存在
- spring.application.name为默认值,若配置spring.cloud.nacos.config.prefix则使用该值
- 通过上面配置可以得出dataID应为 nacos-config-client-dev.yaml
- 每次修改云端配置,部署项目会自动刷新配置
多配置管理
- nacos可以创建名称空间跟组来区分不同配置
相关yml配置
spring: application: name: nacos-config-client cloud: nacos: discovery: server-addr: localhost:8848 #服务注册中心地址 config: server-addr: localhost:8848 #配置中心地址 file-extension: yaml #指定yaml格式的配置(yml和yaml都可以) prefix: abc #若该值为空 则使用spring.application.name group: DEV_GROUP #分组 namespace: 6546dece-b034-4f09-ae51-8783e3b5fc2b #名称空间
7.2.6 nacos配置中心数据持久化
原本内置一个小型数据库delby,替换为mysql
- 安装mysql 需要5.6.5+以上版本
初始化sql文件 在config下有nacos-config.sql(先新建库再执行)
- 修改nacos/conf/application.properties文件
spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true db.user=root db.password=zyb199802
- 如果数据库是其他高版本 需要在nacos跟目录下创建plugins/mysql/mysql对应版本驱动的jar包
- 启动 /Users/zyb/Documents/java/nacos/bin/startup.sh -m standalone
评论 (0)