# springclouddemo **Repository Path**: raoyuehua/springclouddemo ## Basic Information - **Project Name**: springclouddemo - **Description**: 微服务学习 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-12-23 - **Last Updated**: 2022-02-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 服务注册与发现 当服务很多时,单靠代码手动管理是很麻烦的,需要一个公共组件,统一管理多服务,包括服务是否正常运行等. # 服务治理 在传统的rpc远程调用框架中,管理每个服务和服务之间的依赖关系比较复制,管理起来不方便, 所以需要使用服务治理来管理服务和服务之间的依赖关系。 服务治理主要体是实现服务的调用、负载均衡、容错、发现和注册等。 ## CAP C: Consistency 强一致性 A: Availability 可用性 P: Partition tolerance 分区容错性 ### CAP核心 一个分布式系统不可能同时很好的满足一致性、可用性、分区容错性这三个需求,最多只能同时较好的满足俩个。CP 或 AP. 因此,根据CAP原理将NoSQL数据库分成了满足CA、CP、AP三大类 CA: 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大 CP: 满足一致性,分区容忍必的系统,通常性能不是特别高 AP: 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。 ## Eureka 用于==服务注册==,目前官网已经停止更新** 采用了CS的设计架构 Eureka包含了俩个组件:Eureka Server 和 Eureka Client Eureka Server:提供微服务的注册服务 各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用的服务节点的信息, 服务节点的信息可以在界面中直观看到。 Eureka Client:通过注册中心进行访问 是一个java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置使用轮询算法实现的负载均衡器,在应用启动后, 将会向Eureka Servver 发送心跳(默认周期30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server 将会从服务注册列表中把这个服务节点删除(默认90秒) ### 单机版Eureka singleeurekademo 在主启动类上加上@EnableEurekaServer 注解 启动Eureka Eureka server: singleeurekademo Eureka client: providerpay Eureka client: consumerorder 在 providerpay 的pom.xml文件中加入 org.springframework.cloud spring-cloud-starter-netflix-eureka-client 在 providerpay 的application.yml文件中加入 eureka: client: #表示是否将自己注册进Eureka server 默认为true registerWithEureka: true #是否从Eureka server抓取已有的注册信息,默认为true,单节点无所谓,集群时必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true serviceUrl: defaultZone: http://localhost:7001/eureka 在 providerpay 的主启动类cn.ryh.providerpay.ProviderpayApplication文件中加入@EnableEurekaClient注解 在 consumerorder 的pom.xml文件中加入 org.springframework.cloud spring-cloud-starter-netflix-eureka-client 在 consumerorder 的application.yml文件中加入 eureka: client: #表示是否将自己注册进Eureka server 默认为true registerWithEureka: true #是否从Eureka server抓取已有的注册信息,默认为true,单节点无所谓,集群时必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true serviceUrl: defaultZone: http://localhost:7001/eureka 在 consumerorder 的主启动类cn.ryh.providerpay.ProviderpayApplication文件中加入@EnableEurekaClient注解 ### 集群Eureka 原理:互相注册,相互守望。 clustereurekaone clustereurekatwo clustereurekathree 更改C:\Windows\System32\drivers\etc\host文件,加入 127.0.0.1 clustereureka7002.com 127.0.0.1 clustereureka7003.com 127.0.0.1 clustereureka7004.com 通过修改application.yml的eureka.client.serviceurl.defaultZone 属性进行配置进行互相注册,相互守望。 2→3,4 3→2,4 4→2,3 http://clustereureka7002.com:7002/ http://clustereureka7003.com:7003/ http://clustereureka7004.com:7004/ 查看页面上的 DS Replicas 7002 上应该显示为:clustereureka7003.com clustereureka7004.com 将providerpay 复制三份分别为clusterproviderpaytwo、clusterproviderpaythree、clusterproviderpayfour 修改其端口号server.port: 8004 然后将consumerorder中的访问的url修改为微服务名称,并且得在注入RestTemplate的方法上加上@LoadBalanced注解 (该注解为开启RestTemplate的负载均衡) ### Eureka actuator微服务信息完善 在yml配置文件中 加入 eureka.instance.instance-id: XXXX 来修改eureka在web上显示的主机名称 加入eureka.instance.prefer-ip-address: true 来开启ip地址的显示 使用这个俩个配置时pom.xml中需要引入 spring-boot-starter-web 和 spring-boot-starter-actuator 可以通过访问:http://localhost:8002/actuator/health 来确定服务的状态是否假死 ### Eureka服务发现 对于注册进Eureka服务中的微服务,可以通过服务发现来获得改服务的信息 在PaymentController中注入org.springframework.cloud.client.discovery.DiscoveryClient 并在主启动类上加上@EnableDiscoveryClient 注解 然后访问 http://localhost:8002/discovery/getServers http://localhost:8003/discovery/getServers http://localhost:8004/discovery/getServers 可以通过返回的信息 data":{"discoveryClients":[{"services":["cloud-payment-service","cloud-order-service"],"order":0}, {"services":[],"order":0}],"services":["cloud-payment-service","cloud-order-service"],"order":0}} 中可以发现,Eureka中的注册的服务有 cloud-payment-service 和 cloud-order-service 然后访问http://localhost:8002/discovery/getInstances/cloud-payment-service 来获取cloud-payment-service服务的所有服务注册信息 代码见:cn.ryh.ribbonproviderpayone.discovery.controller.DiscoveryController ### Eureka自我保护 概述 保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务 注册表的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。 总结 某时刻某一个的微服务不能用了,Eureka不会立刻进行清理,依旧会对该微服务信息进行保存 如何禁止保护? #关闭自我保护机制,保证不可用服务及时被剔除,默认为true开启 eureka.server.enable-self-preservation: false #设置接受心跳时间间隔,毫秒 默认60秒 eureka.server.eviction-interval-timer-in-ms: 2000 ## Zookeeper Zookeeper的安装及配置见 [Zookeeper概述](https://gitee.com/raoyuehua/zookeeperdemo) ### Zookeeper服务注册与使用 1、首先需要再pom.xml中引入 org.springframework.cloud spring-cloud-starter-zookeeper-discovery 2、在application.yml中配置 服务名称及zookeeper服务器地址 spring: application: name: cloud-zookeeper-order-service cloud: zookeeper: connect-string: 119.3.50.65:2181 若zookeeper使用的集群,这里的地址就填集群的地址:119.3.50.65:2181,119.3.50.65:2181,..,.. 这样 3、在主启动类上加上 @EnableDiscoveryClient 注解 这样注册进zookeeper的节点属于临时节点。(既服务断掉zookeeper就删除了该节点) ## Consul Consul是一套开源的分布式服务发现和配置管理系统,由HashiCorp公司用Go语言开发。 ### Consul概述 提供了微服务系统中服务治理,配置中心,控制总线等功能。这些功能中的每一个都可以根据需求单独使用,也可以一起使用构建全方位的服务网格, 总之Consul提供了一种完整的服务网格解决方案。 ### Consul优点 它具有很多有点。例如:基于raft协议,比较简洁、支持健康检查、同时支持HTTP和DNS协议、支持跨数据中心的WAN集群、提供图像界面、跨平台,支持 Linux,Mac,Windows ### Consul安装 [安装教程](https://learn.hashicorp.com/consul) windows: 直接下载解压运行.exe文件 linux: // 下载 wget https://releases.hashicorp.com/consul/1.10.4/consul_1.10.4_linux_amd64.zip // 解压 unzip consul_1.10.4_linux_amd64.zip // 校验 // 若校验不成功则配置有下环境变量 // vim /etc/profile // CONSUL_HOME=/usr/local/consul // export PATH=$PATH:CONSUL_HOME // 刷新变量 // source /etc/profile ./consul -v // 启动 nohup ./consul agent -dev -client 0.0.0.0 -ui & // 验证是否启动 netstat -anp|grep 8500 // 浏览器访问 ip+8500 例:http://119.3.50.65:8500/ ### Consul服务注册与使用 1、首先需要再pom.xml中引入 org.springframework.cloud spring-cloud-starter-consul-discovery 2、在application.yml中配置 服务名称及consul服务器地址 spring: application: name: cloud-consul-order-service cloud: consul: host: 119.3.50.65 port: 8500 discovery: service-name: ${spring.application.name} // healthbeat.enable 为 true 就是打开心跳机制(解决 Consul注册中心注册的服务总是红叉 (All service checks failing)) heartbeat: enabled: true consul使用集群后续补充 3、在主启动类上加上 @EnableDiscoveryClient 注解 ## 三个注册中心异同点 |组件名 |语言 |CAP|服务健康检查|对外暴露接口|SpringCloud集成 |Eureka |Java |AP |可配支持 |HTTP |已集成 |Consul |Go |CP |支持 |HTTP/DNS |已集成 |Zookeeper|Java |CP |支持 |客户端 |已集成 ## Ribbon Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,基于 Netflix Ribbon 实现的一个工具类框架。 目前已进入维护模式。(未来可能用Spring Cloud Loadbalancer 进行替代) ### Ribbon概述 Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项,如连接超时、 重试等。简单的说就是在配置文件中列出Load Balancer 后面所有的机器,Ribbon会自动的帮助我们基于某种规则(如简单的轮询,随机等)去连接 这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。 使用eureka时因为其已经集成了Ribbon所以无须再pom.xml中去引入。若是不使用eureka则需要引入 ### LB负载均衡(Load Balancer) 是什么 将用户的请求平摊分配到多个服务上,从而达到系统的HA(高可用)。常见的负载均衡软件有Nginx,LVS。硬件有F5等。 又分集中式LB和进程内LB #### 集中式LB 即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如Nginx),由改设施负责把访问请求通过某种策略转发至服务的提供方 #### 进程内LB 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。 Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。 ### Ribbon VS Nginx区别 Nginx是服务器负载均衡,客户端所有请求都会交给Nginx,然后由Nginx实现转发请求。即负载均衡是由服务端实现。 Ribbon是本地负载均衡,在调用微服务接口时,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。 ### Ribbon核心组件IRule 根据特定的算法从服务列表中选取一个要访问的服务 常见的有: com.netflix.loadbalancer.RandomRule 随机 com.netflix.loadbalancer.RoundRobinRule 轮询 等 如何替换规则: 不能放在模块的@ComponentSacn(@SpringBootApplication)所扫描的当前包下及子包下。 在ribbon/ribbon-order/src/main/java/cn/ryh/包下 新建 ribbonrule包。并创建 MyRule类 随便在主启动 ribbon/ribbon-order/src/main/java/cn/ryh/ribbonorder/RibbonOrderApplication.java 类 加上 @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MyRule.class) 注解 启动ribbon下的所有模块 然后访问 http://localhost/consumer/getServer 其是随机在访问CLOUD-PAYMENT-SERVICE下的服务。 ### Ribbon负载均衡算法 restTemplate接口的第几次请求 % 服务器集群总数量 = 实际调用服务器下标位置。每次重启后 restTemplate接口计算从新从1开始 ### Ribbon使用自己写的负载均衡算法 首先注释掉获取RestTemplate Bean方法上的@LoadBalanced注解。 具体实现代码见 ribbon/ribbon-order/src/main/java/cn/ryh/ribbonorder/loadbalanced ribbon/ribbon-order/src/main/java/cn.ryh.ribbonorder.consumer.controller.ConsumerController.useMyLoadBalanced ## OpenFeign Feifn是一个声明式的Web服务客户端,让编写Web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。 ### OpenFeign概述 Feign旨在使编写Java Http客户端变得更容易 以前是使用Ribbon+RestTemplate时,利用RestTemplate对Http请求的封装处理,形成一套模板化的调用方法。 但在实际开发中,由于微服务的调用可能不止一处,往往一个接口会被多出调用,所以通常会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用 Feign在此基础上做了进一步封装,用它来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它 (例如 以前是Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Ribbon 时,自动封装服务调用客户端的开发量。 Feign集成了Ribbon,利用Ribbon维护了服务列表信息,并且通过轮询实现了客户端负载均衡。与Ribbon不同的是,通过Feign只需要定义服务绑定接口 且以声明式的方法,优雅而简单的实现了服务调用。 ### OpenFeign与Feign的区别 OpenFeign是在Feign的基础上支持了SpringMVC的注解,OpenFeign的@FeignClient可以解析SpringMVC的@RequesMapping注解下的接口,并通过 动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。 简单来说OpenFeign就是Feign的升级版。 ### OpenFeign使用 在pom.xml中引入 org.springframework.cloud spring-cloud-starter-openfeign 在主启动类加上 @EnableFeignClients 注解 在创建一个接口类,并在接口类上 加上 @FeignClient(value = "CLOUD-PAYMENT-SERVICE")注解。value的值为所需要调用的服务名 定义对应的方法调用服务的接口,并需要在方法上加上对应的请求注解和路径, 然后再controller中就可以直接调用接口。 代码见 openfeign/openfeign-order/src/main/java/cn/ryh/openfeign/service/PaymentFeignService.java ### OpenFeign超时控制 默认请求超时为1秒,超过即报错 因为OpenFeign集成了Ribbon,所以超时控制是通过配置ribbon来进行实现 ribbon: #指建立连接后从服务端读取到可用资源所用的时间 ReadTimeout: 5000 #建立连接所用的时间,适用于网络状况正常的情况下,两端连接所需要的时间 ConnectTimeout: 5000 ### OpenFeign日志打印 OpenFeign提供了日志打印功能,我们可以同配置来调整日志级别。 日志级别: NONE:默认的,不显示任何日志 BASIC:仅记录请求方法、URL、响应状态码及执行时间 HEADERS:除了BASIC中定义的信息之外,还有请求头和响应头的信息 FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据 @Configuration public class OpenFeignLoggerConfig { @Bean public Logger.Level loggerLevel(){ return Logger.Level.FULL; } } 并再yml中增加 logging: level: # OpenFeign 日志以什么级别监控哪个接口 cn.ryh.openfeign.service.PaymentFeignService: debug 随后调用对应接口可以再后台查看到对应的日志输出。 ## Hystrix Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在 一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提供分布式系统的弹性。 ### 断路器 是一种开关装置,当某个服务单元发生故障以后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期,看处理的备选响应(FallBack) 而不是长时间等待或者抛出调用方无法处理的异常。这样就保证了服务调用方的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延, 乃至雪崩。(简单理解就是家庭用电的保险丝,家里若是发生短路,直接保险丝熔断,防止其他电器短路损坏。) ### 服务降级(fallback) 服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示。 通常是 程序异常、超时、服务熔断触发服务降级、线程池/信号量打满也会导致降级 如何使用: 在某个方法上加上@HystrixCommand注解 @HystrixCommand(fallbackMethod = "getServerTimeOutFallback",commandProperties = { //3秒钟以正常,超过3秒走兜底方法。 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500") }) @GetMapping(value = "/getServerTimeOut") public String getServerTimeOut() { return paymentFeignService.getServerTimeOut(); } 并声明降级后所走的方法 public String getServerTimeOutFallback() { return "Spring cloud with hystrix order getServerTimeOutFallback"; } 并在主启动类上加上 @EnableHystrix(或@EnableCircuitBreaker) 注解 服务降级可以放在客户端也可以放在服务端,一般放在客户端。 全局配置 第一种,在对应的Controller类上加上@DefaultProperties(defaultFallback = "defaultFallback") 注解 然后申明defaultFallback方法。 在方法上只写@HystrixCommand 即可 这一种配置,如果某个方法单独配了自己的fallback方法会走其自己配置的。 第二种,在feign接口中的 @FeignClient(value = "CLOUD-PAYMENT-SERVICE",fallback = PaymentFeignServiceImpl.class) 增加fallback属性配置,其值为新建一个类并实现 feign接口,并实现对应的方法。 并在yml配置文件中添加 feign: hystrix: enabled: true hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 5000 在controler方法上也不需要使用@HystrixCommand 注解了 这一种配置,如果在某个方法上申明自己的fallback方法是无效的。 ### 服务熔断(break) 1.调用失败会触发降级,而降级会调用fallback方法 2.但无论如何降级的流程一定会先调用正常方法再调用fallback方法 3.假如单位时间内调用失败次数过多,也就是降级次数过多,则触发熔断 4.熔断以后就会跳过正常方法直接调用fallback方法 5.所谓“熔断后服务不可用”就是因为跳过了正常方法直接执行fallback 简答理解就是:保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好的提示。 使用: @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求次数,默认20次 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间范围 默认20秒 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸 60%,默认50% }) 短路器打开的条件为: 在设置的时间范围内(例:10秒),访问次数超过设置的次数(例:10次),并且失败率达到设置的值(例:60%),这三个条件同时满足才会打开短路器。 当开启的时候,所有请求都不会进行转发,一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。 如果成功,断路器会关闭,若失败,继续开启。过一段时间后继续重复设置为半开状态。。。 ### 服务限流(flowLimit) 秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒处理N个有序进行。 ### HystrixDashboard 新建hystrix-dashboard 项目 在想要进行监控的hystrix项目中的主启动类加上 @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; } 随便访问http://localhost:9001/hystrix/ 在监控地址栏中填入:http://localhost:8004/hystrix.stream 出现loading时,访问一下 http://localhost:8004/payment/payment/circuit/1 即可 ![img.png](hystrix/hystrix监控图表说明.png) ## Gateway Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤功能,例如:熔断、限流、重试等。 Spring Cloud Gateway 使用的WebFlux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架 ### Gateway和Zuul的区别 1、Zuul 1.X 是基于阻塞I/O的API Gateway 2、Zuul 1.X 基于Servlet2.5使用阻塞框架它不支持任何长连接(如WebSocket),Zuul的设计模式和Ngix很像,每次I/O操作都是从工作线程中选择 一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用Java实现,而JVM本身会有第一次加载比较慢的情况,使得Zuul的 性能相对较差。 3、Zuul 2.X理念更先进,想基于Netty非阻塞和支持长连接,但Spring Cloud目前还没有整合。Zuul 2.x的性能比1.X有较大的提升,在性能方面, 根据官方提供的基准测试,Gatewat的RPS(每秒请求数)是Zuul的1.6倍。 4、Gateway建立在Spring Framework5、Project Reactor和SpringBoot2之上,使用非阻塞API. 5、Gatewat还支持WebSocket,并且与Spring紧密集成拥有更好的开发体验。 ### Gateway三大核心概念 1、路由(Route) Route 是网关的基础元素,由 ID、目标 URI、断言、过滤器组成。当请求到达网关时,由 Gateway Handler Mapping 通过断言进行路由匹配(Mapping),当断言为真时,匹配到路由。 2、断言(Predicate) 参考的是java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数), 如果请求与断言相匹配则进行路由 3、过滤(Filter) 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。 Web请求通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行了一些精细化控制。 Predicate就是我们的匹配条件,而Filter就可以理解为一个无所不能的拦截器。有了这俩个元素在加上目标的URI,就可以实现一个具体的路由了。 ### Gateway工作流程 客户端向Gateway发出请求,然后在Gateway Handler Mapping 中找到与请求匹配的路由。将其发送到Gateway Web Handler. Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。 过滤器链是由多个过滤器组成的,过滤器在发送代理请求之前(pre)或之后(post)可以执行一些业务逻辑,有着非常重要的作用。 例如:过滤器可以在发送代理请求之前做参数校验、流量监控、日志输出、转换协议等 在发送代理请求之后可以做响应内容、响应头的修改、流量监控、日志输出等。 #### Gateway使用 1、使用配置方式 具体见gateway/gateway-config项目的yml配置文件 2、使用编码方式 具体见gateway/gateway-code的GatewayConfig.java配置类 filter官方提供的可以查看https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories ## Config SpringCloud config 为微服务框架提供集中化的外部配置支持,配置服务器为各个不同的微服务应用的所有环境提供一个中心化的外部配置。 ### Config概述 其分为 服务端 和 客户端俩部分 服务端: 服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。 客户端: 客户端则是通过指定的配置中心来管理资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。 Config默认使用Git来存储配置文件(也有其它方式,比如支持svn和本地文件,但最推荐的还是Git,而且使用的是http/https访问的形式) 优点: 1、集中管理配置文件 2、不同环境不同配置,动态化的配置更新,分环境部署比如:dev/test/prod/beta/release 3、运行期间动态调整配置,不再需要在每个微服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。 4、当配置变动时,服务不需要重启即可感知到配置的变化并应用新的配置。 5、将配置信息以Rest接口的形式暴露 ### Config使用 服务端: 1、pom.xml中引入 org.springframework.cloud spring-cloud-config-server 2、在yml配置文件中增加 spring: cloud: config: server: git: uri: git@gitee.com:raoyuehua/spingcloudconfig.git search-paths: - spingcloudconfig label: master 3、在主启动类上加上 @EnableConfigServer 注解 ip/{label}/{application}-{profile}.yml(最推荐使用这种方式) 例: http://localhost:3344/dev/config-dev.yml http://localhost:3344/dev/config-prod.yml http://localhost:3344/master/config-prod.yml 客户端: 1、pom.xml中引入 org.springframework.cloud spring-cloud-starter-config 2、新建bootstap.yml配置文件 bootstrap.yml是系统级,application.yml是用户级的,所以其优先级更高,所以其比application.yml先加载 启动服务 随后访问 http://localhost:3355/configClient/configInfo,可以获取到对应的配置信息 http://localhost:3344/master/config-dev.yml 这时通过git修改配置信息 刷新页面会发现3355服务器还是获取到之前的配置 3344能够访问到修改后的数据 这时在bootstrap.yml 中增加如下配置 management: endpoints: web: exposure: include: "*" 并在Controller上加上@RefreshScope 注解 这时再次修改配置文件,然后 调用 curl -X POST "http://localhost:3355/actuator/refresh" 随后在刷新3355会发现其也能够读取到最新配置 ## Bus 在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有的微服务实例都连接上来。由于该主题产生的消息会被 所有实例监听和消费,所以称其为消息总线。在总线上的各个实例,都可以方便的广播一些消息给其他实例。 支持 RibbitMQ和kafka ### Bus基本原理 SpringCloudBus能管理和传播分布式系统间的消息,就像一个分布式执行器,可以用于广播状态更改,事件推送等,也可以当作微服务之间的通信通道。 ConfigClient实例都监听MQ中同一个topic(默认是SpringCloudBus).当一个服务刷新数据的时候,它会把这个消息放入到Topic中,这样其它监听同一 Topic的服务就能得到通知,然后去更新自身的配置。 ### Bus使用 事先在Windows或者Linux中安装好RibbitMQ 1、在pom.xml中加入 org.springframework.cloud spring-cloud-starter-bus-amqp 2、在config server 的yml中加入 rabbitmq: host: 119.3.50.65 port: 5672 username: guest password: guest management: endpoints: web: exposure: include: 'bus-refresh' 3、在config client 的yml中加入 rabbitmq: host: 119.3.50.65 port: 5672 username: guest password: guest 4、更改配置文件后发送请求 curl -X POST "http://localhost:3344/actuator/bus-refresh" 然后刷新3355 3366发现其都能够获取到最新配置了。 http://config-3344.com/config-dev.yml http://localhost:3355/configClient/configInfo http://localhost:3366/configClient/configInfo 5、定点通知例只通知3355 curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355" 只通知3366 curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3366" 在bus-refresh地址后加上对应的服务名和对应的端口号,就能实现单独只通知某一台服务器。不加端口只是通知某个服务集群下的所有机器。 ## Stream 屏蔽底层消息中间件的差异,降低切换版本,统一消息的编程模型 目前仅支持 RibbitMQ和kafka ### Stream简介 SpringCloudStream是一个构建消息驱动微服务的框架。 应用程序通过inputs或者outputs来与SpringCloudStream中binder对象交互 通过我们配置来binding(绑定)而SpringCloudStream的binder对象负责与消息中间件交互 通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。 SpringCloudStream为了一些供应商的消息中间件产品提供了个性化的自动配置实现,引用了发布-订阅、消费组、分区的三个概念。 ### Stream优点 在没有绑定器(binder)这个概念的情况下,我们的应用要直接与消息中间件进行信息交互的时候,由于各个消息中间件构建的初衷不同,它们的实现细节上 会有较大的差异。通过定义绑定器作为中间层,完美地实现了应用程序与消息中间件细节之间的隔离。通过向应用暴露统一的Channel通道,使得应用程序 不需要考虑各种不同的消息中间件实现。 ### Binder 通过定义绑定器作为中间层,完美地实现了应用程序与消息中间件细节之间的隔离. input对应于消费者,output对应于生产者。 ### Channel 通道,是队列Queue的一种抽象,在消息通讯系统中就是实现存储和转发的媒介,通过Channel对队列进行配置。 ### Source和 Sink 简单的可以理解为参照对象是SpringCloudeStrem自身,从Stream发布消息就是输出,接受消息就是输入。 ### 编码API和常用注解 ![img.png](stream/img.png) ### Stream使用 1、在pom.xml中添加 org.springframework.cloud spring-cloud-starter-stream-rabbit 2、在yml配置文件中添加 cloud: stream: binders: # 在此处配置要绑定的rabbitmq的服务信息; defaultRabbit: # 表示定义的名称,用于于binding整合 type: rabbit # 消息组件类型 bindings: # 服务的整合处理 input: # 这个名字是一个通道的名称 生成者使用output 消费者使用input destination: ryhExchange # 表示要使用的Exchange名称定义 content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain” binder: defaultRabbit # 设置要绑定的消息服务的具体设置 # 设置rabbitmq的相关的环境配置 rabbitmq: host: 119.3.50.65 port: 5672 username: guest password: guest 3、生成者通过如下代码产生消息 @EnableBinding(Source.class) public class MessageProviderImpl implements MessageProvider { @Resource private MessageChannel output; @Override public String send() { String serial = UUID.randomUUID().toString(); output.send(MessageBuilder.withPayload(serial).build()); System.out.println("*****serial: "+serial); return serial; } } 4、消费者使用如下代码接收消息 @Component @EnableBinding(Sink.class) public class ReceiveMessageListenerController { @Value("${server.port}") private String serverPort; @StreamListener(Sink.INPUT) public void input(Message message) { System.out.println("消费者1号,接受:"+message.getPayload()+"\t port:"+serverPort); } } 具体代码可以看 stream 模块下的内容 ### Stream解决重复消费和消息持久化问题 以上面的配置存在消息重复消费的问题。生成者发一个消息,俩个消费者都接收到了。 持久化问题,假如生成者发送消息时,消费者离线了,这时重新启动消费者消费者是不接收不到之前生成者发送的消息的。 在配置文件中加入group配置即可解决这俩个问题。 统一分组的消费者实现了轮询分组,每次只能有个消费者获取到消息,这样就能避免重复消费。 因为未配置group分组,每个消费者都随机分配了一个组,这样如果重新再次启动的话获取的组号是不一样的 这样之前发的消息当然就接收不到了。 若是指定了分组,重启后还是这个分组,那么这个分组里之前未消费的信息现在就能够获取到了。 ## Sleuth 提供了一套完整的服务跟踪的解决方案 Trace:类似于树结构的Span集合,表示一条调用链路,存在唯一标识 span:表示调用链路来源,通俗的理解span就是一次请求信息 ### Sleuth使用 https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/ 1、下载对应的zipkin-server-2.12.9.exec.jar 包,并以命令行运行jar 2、在需要加入Sleuth的微服务的pom.xml中添加 org.springframework.cloud spring-cloud-starter-zipkin 3、在yml中添加 zipkin: base-url: http://localhost:9411 sleuth: sampler: probability: 1 #取值范围0~1 1表示全部分析 4、启动对应的服务并进行服务调用,然后访问http:localhost:9411(为jar包运行的地址) 5、在对应的页面就可以查看依赖关系等。 ## Nacos 一个更易于构建云原生应用的动态服务发现,配置管理和服务管理中心 Nacos = Eureka+Config+Bus 替代Eureka做服务注册中心,替代Config做服务配置中心 Nacos支持AP和CP模式的切换 通过 curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP' 进行切换 ### Nacos下载 到 https://github.com/alibaba/nacos/releases 中可以直接下载已经打包好的,下载比较慢。 可以用gitee克隆仓库然后到gitee中下载对应版本的源代码,自行构建 cd nacos/ mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U ls -al distribution/target/ ### Nacos安装运行 以Linux版本为例(因为如果项目生产部署的话是以Linux为主) 1、解压 tar -zxvf nacos-server-2.0.3.tar.gz 2、找到目录下的nacos/conf/nacos-mysql.sql并创建一个nacos_config的库然后执行对应的语句(只支持mysql数据) 3、在/usr/local/nacos/conf/application.properties中添加 spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://119.3.50.65:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user=root db.password=Ryh3625241995 4、启动Nacos sh startup.sh -m standalone 5、访问http://119.3.50.65:8848/nacos/#/login 账户密码都是 nacos 集群: 1、解压 2、设置mysql数据数源,并application.properties中的端口(一台机器部署三个或者多个nacos),多台机器的可以不用修改端口, 但是得保证机器互通 若 spring.datasource.platform=mysql 这个打开会有报错 则把其注释掉 3、修改或新建cluster.conf文件 文件内容: #it is ip:prot #example 192.168.0.34:8858 192.168.0.34:8868 192.168.0.34:8878 一台机器上端口号不要使用连续挨在一起的端口, 只能使用内网ip。端口除了对应的8858 之外还要打开 9848和9849 (8858+1000) 4、进入每个nacos的bin目录然后使用 ./startup.sh 启动nacos 5、服务注册进nacos集群,在填写server-addr时,通过 ip+prot,ip+port的方式连接集群 6、通过部署nginx代理nacos服务,nginx.conf配置如下: events { worker_connections 1024; } #配置nacos TCP转发 stream { upstream nacos1 { server 192.168.0.34:9858; server 192.168.0.34:9868; server 192.168.0.34:9878; } server { listen 9848; proxy_pass nacos1; } upstream nacos2 { server 192.168.0.34:9859; server 192.168.0.34:9869; server 192.168.0.34:9879; } server { listen 9849; proxy_pass nacos2; } } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #配置nacos; upstream nacos-servers { server 192.168.0.34:8858; server 192.168.0.34:8868; server 192.168.0.34:8878; } server { listen 8848; server_name 119.3.50.65; location / { proxy_pass http://nacos-servers; } ......后面的无需改动 7、通过访问nginxip:8848/nacos 能够访问nacos页面控制台,服务注册进nacos集群,在填写server-addr时,通过nginx ip:8848 的方式连接集群 8、能够在页面中看到对应的服务,则配置成功。 ### Nacos使用 作为服务注册中心 1、在pom.xml中添加 com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery 2、在yml配置文件中添加 spring: application: name: nacos-consumer cloud: nacos: discovery: server-addr: 119.3.50.65:8848 3、在主启动类上加上@EnableDiscoveryClient 注解 启动对应的微服务,然后到http://119.3.50.65:8848/nacos 中可以在服务管理中看到对应的服务已经注册进了nacos 并访问 http://localhost:8801/consumer/payment/nacos/13 可以轮询的访问 nacos-consumer(因为nacos内集成了ribbon) 作为作为配置中心 1、在pom.xml中添加 com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config 2、新增bootstrap.yml 新增bootstrap.yml是为了保证先从配置中心进行配置拉取,拉取配置后才能保证项目正常启动。 server: port: 8802 spring: application: name: nacos-consumer cloud: nacos: discovery: server-addr: 119.3.50.65:8848 #服务注册中心地址 config: server-addr: 119.3.50.65:8848 #配置中心地址 file-extension: yaml #指定yaml格式的配置 group: NACOS_CONSUMER_TEST #使用Group区分配置,默认分组可以不用填 3、在因为配置中心的配置类上加上@RefreshScope注解 4、在nacos中增加对应的配置 Nacos中的dataid的组成格式与SpringBoot配置文件中的匹配规则: ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension} prefix默认为spring.application.name的值 spring.profile.active既为当前环境对应的profile,可以通过配置项spring.profile.active 来配置 file-exetension为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension配置 然后访问 http://localhost:8801/config/info 可以获取到对应的配置信息 其自带动态刷新,修改完配置后重新访问下就能够获取到最新配置 通过修改spring.profiles.active的值 来获取不同的配置文件 nacos-consumer-dev.yaml spring.profiles.active: dev nacos-consumer-test.yaml spring.profiles.active: test 也可以设置不同的Group来进行区分 在配置文件中加入group配置 group: NACOS_CONSUMER_TEST #使用Group区分配置,默认分组可以不用填 也可以增加不同的命名空间来进行区分 在配置文件中加入namespace配置 #使用namespace区分配置,默认命名空间可以不用填,且该值应填命名空间ID namespace: de4c4c89-3505-4533-9d1d-939dfa5c9ceb ## Sentinel 分布式系统的流量防卫兵 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 分为两个部分: 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。 ### Sentinel特征 丰富的应用场景 Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、 集群流量控制、实时熔断下游不可用应用等。 完备的实时监控 Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。 广泛的开源生态 Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。 您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。 完善的 SPI 扩展机制 Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。 ### Sentinel安装启动 1、到https://github.com/alibaba/Sentinel/releases 下载sentinel-dashboard的jar包 2、下载后使用 java -jar sentinel-dashboard-1.8.1.jar --server.port=8858 启动 (前提 jdk为1.8) --注意版本关系,不然是不会成功 查看版本关系 https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明 也可以使用docker启动 docker pull bladex/sentinel-dashboard docker run --name sentinel -d -p 8858:8858 -p 8719:8719 -d aa398704ebd3 然后访问 http://119.3.50.65:8858/ 查看sintinel控制台 账户密码都为 sintinel ### Sentinel使用 1、在pom.xml中添加 com.alibaba.cloud spring-cloud-starter-alibaba-sentinel 2、在yml中添加 cloud: sentinel: transport: dashboard: 119.3.50.65:8858 # 配置sentinel地址,保证能和项目地址互通 port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口 3、主启动类上加上 @EnableDiscoveryClient注解 启动服务,然后随便访问一个接口,然后在查看sintinel控制台,然后根据需求进行配置流控规则等。 ### 流控规则 规则配置页面解释 资源名: 唯一名称,默认为请求路径 针对来源:Sentinel可以针对调用者进行限流,填写服务名。默认default(不区分来源) 阈值类型/单机阈值: QPS(每秒请求数量):当调用该api的QPS达到设定的单机阈值时,进行限流。 并发线程数:当调用该api的线程数达到设定的单机阈值时,进行限流。(该模式无法选择流控效果) 是否集群:不需要集群 流控模式: 直接:api达到限流条件时,直接限流 关联:当关联的资源到达阈值时,就限流自己 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值就行进行限流)[api级别的针对来源] 流控效果: 快速失败:直接失败,抛异常 Warm Up:根据冷加载因子(默认3)的值,从阈值/冷加载因子得到的阈值,经过预热时长,才达到设置的QPS阈值(单位为秒) 例,阈值为10,则 10/3=3,既阈值刚开始为3,经过预热时长后,阈值慢慢提高到10. 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效。(其实选择线程数的话流控效果是无法选择的,单位:毫秒) 集群流控 https://github.com/alibaba/Sentinel/wiki/集群流控 ### 降级规则 规则配置页面解释 资源名: 唯一名称,默认为请求路径 熔断策略: 慢调用比例: 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动 被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态既半开状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。 异常比例: 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被 熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再 次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。 异常数: 当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的 一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。 异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。 最大 RT: 慢调用比例策略专有,即请求的最大的响应时间。单位毫秒 比例阈值: 慢调用比例策略、异常比例策略都有, 取值范围0.0~1.0. 异常数: 异常数策略专有,既异常请求数阈值 熔断时长: 熔断时长,单位为 s 最小请求数: 统计时长内,熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断 统计时长: 统计时长(单位为 ms),默认1000ms. ### 热点规则 规则配置页面解释 资源名: 为@SentinelResource注解value的值 参数索引: 为方法中的参数索引,而不是url中的,因为方法中可能会设置参数为非必传。 单机阈值: 统计窗口时间内,带有指定参数的请求访问数超过阈值时,则进行限流 统计时间窗口: 设定统计时间窗口的时间。单位:秒 若是从簇点链路对url进行热点规则配置时,则没有高级选可选。需从热点规则进入,然后选择对应的资源名进行编辑即可添加参数例外项。 参数例外项 参数类型: byte、int、long、double、float、char、String 参数值: 例外项的参数对应的指定值。 限流阈值: 例外项的参数对应的指定值的限流阈值 设置完成后点击添加,可以添加多个。 方法上需要增加 @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey") 注解,如果不加该注解配置是无效的。 且热点配置的需要是value的值,而不是对应的url ### 系统规则 规则配置页面解释 阈值类型: LOAD: 自适应(仅对 Linux/Unix-like 机器生效)系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值, 且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。 设定参考值一般是 CPU cores * 2.5 RT: 当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。 线程数: 当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。 入口QPS: 当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。 CPU使用率: 当系统CPU使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。 ### @SentinelResource详解 注意:注解方式埋点不支持 private 方法 用于定义资源,并提供可选的异常处理和 fallback 配置项 @SentinelResource 注解包含以下属性: value: 资源名称,必需项(不能为空) entryType: entry 类型,可选项(默认为 EntryType.OUT) blockHandler / blockHandlerClass: 若本次访问被限流或服务降级,则调用blockHandler指定的接口。 blockHandler对应处理BlockException的函数名称,可选项。blockHandler函数访问范围需要是public,返回类型需要与原方法相匹配, 参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。 blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定blockHandlerClass为对应的类的Class对象, 注意对应的函数必需为static函数,否则无法解析。 fallback / fallbackClass: 若本接口出现未知异常,则调用fallback指定的接口。 fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常 (除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:返回值类型必须与原函数返回值类型一致; 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象, 注意对应的函数必需为 static 函数,否则无法解析。 defaultFallback(since 1.6.0): 默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。 默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。 若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。 defaultFallback 函数签名要求:返回值类型必须与原函数返回值类型一致;方法参数列表需要为空,或者可以额外多一个Throwable类型的 参数用于接收对应的异常。 defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象, 注意对应的函数必需为 static 函数,否则无法解析。 exceptionsToIgnore(since 1.6.0): 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。 1.8.0 版本开始,defaultFallback 支持在类级别进行配置 特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级时只会进入 blockHandler 处理逻辑。 若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException)。 使用@SentinelResource 中的value 设置为流控\熔断的资源名,需要指定blockHandler方法,未指定时页面会直接出现Error page 只设置了blockHandler的话,若是发生业务异常,其是不会进行处理的会直接出现Error page 只设置了fallback的话,若是发生业务异常,会走配置fallback方法,若是发生了限流和熔断还是会走fallback方法。 若是blockHandler和fallback都配,若是发生业务异常未达到限流\熔断条件,会走配置的fallback方法, 若是发生了限流和熔断会走blockHandler方法, 并不会因为其限流\熔断抛出的BlockException而进入fallback方法. 若是配置了exceptionsToIgnore,则若是发生了其中配置的异常就不会走配置的fallback方法。若是其未设置fallback方法,那么该配置也就没有意义。 ### 规则持久化-push模式 1、到https://github.com/alibaba/Sentinel/releases/下载对应的源码 2、将pom.xml中的 com.alibaba.csp sentinel-datasource-nacos test 的scope标签注释掉 3、将sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/下整个nacos目录拷贝到 sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule下 4、将sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/NacosConfig.java中的 ConfigFactory.createConfigService("localhost") 设置为nacos的ip地址和端口 ConfigFactory.createConfigService("119.3.50.65:8848"); 5、将sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/FlowControllerV1.java中的 @Autowired private SentinelApiClient sentinelApiClient; 替换为 @Autowired @Qualifier("flowRuleNacosProvider") private DynamicRuleProvider> ruleProvider; @Autowired @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher> rulePublisher; 并将 List rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port); 修改为 List rules = ruleProvider.getRules(app); 并将 sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules); 修改为 rulePublisher.publish(app, rules); 6、在客户端中新增如下配置 1、在pom.xml中增加 com.alibaba.csp sentinel-datasource-nacos 2、在yml中添加 sentinel: datasource: # 名称随意 flow: nacos: server-addr: 119.3.50.65:8848 dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP # 规则类型,取值见: # org.springframework.cloud.alibaba.sentinel.datasource.RuleType rule-type: flow degrade: nacos: server-addr: 119.3.50.65:8848 dataId: ${spring.application.name}-degrade-rules groupId: SENTINEL_GROUP rule-type: degrade system: nacos: server-addr: 119.3.50.65:8848 dataId: ${spring.application.name}-system-rules groupId: SENTINEL_GROUP rule-type: system authority: nacos: server-addr: 119.3.50.65:8848 dataId: ${spring.application.name}-authority-rules groupId: SENTINEL_GROUP rule-type: authority param-flow: nacos: server-addr: 119.3.50.65:8848 dataId: ${spring.application.name}-param-flow-rules groupId: SENTINEL_GROUP rule-type: param-flow 7、打包启动sentinel,并启动客户端,然后增加流控规则,并测试规则,然后查看nacos,会发现多了一个xxx--flow-rules的配置文件(xxx为客户端服务名) 这时把客户端停止,然后重新启动,可以发现其规则并没有消失,流控规则持久化就调整好了。 8、其他规则持久化和流控规则是一样的 1、首先创建其规则对应的Publisher类和Provider 2、在NacosConfig类中增加对应的转换器Converter 3、修改对应的controller 规则对应controller路径sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller 流控规则-FlowControllerV1 熔断规则-DegradeController 热点规则-ParamFlowRuleController 系统规则-SystemController 授权规则-AuthorityRuleController ## Seata Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。 ### 分布式事务处理过程 ID+三组件模型 ID: Transaction ID XID 全局唯一的事务ID; 三组件: 事务协调者:Transaction Coordinator(TC) 实际应用中是Seata服务器 维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚;TC 不存在单点问题,它的数据是存到数据库的,它是无状态的, 可以做到高可用并且 TC 的数据量并不大,它自己的事务就用本地事务就行了,它不用再搞一个分布式事务,也不用跨数据中心 事务管理器:Transaction Manager(TM) 实际应用中是指标记了@GlobalTransactional注解 事务发起方 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议; 资源管理器:Resource Manager(RM) 实际应用中是指每个参与TM发起事务的业务数据库 控制分支事务的边界和行为,负责分支注册、状态汇报,并接收 TC 指令,驱动分支(本地)事务的提交或回滚RM 做的事就是在业务 SQL 基础上做一层拦截,然后想干啥干啥 处理过程 1、TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的事务ID; 2、XID在微服务调用链路的上下文传播 3、RM向TM注册分支事务,将其纳入XID对应全局事务的管辖 4、TM向TC发起针对XID的全局提交或回滚协议 5、TC调度XID管辖下的全部分支事务完成提交或回滚请求 ### Seata安装 1、下载指定版本的seata 下载地址 https://github.com/seata/seata/releases 2、到https://github.com/seata/seata/tree/develop/script/server/db下获取mysql.sql文件,然后新建一个seata数据库, 并执行mysql.sql 3、到https://github.com/seata/seata/tree/develop/script/client/at/db下获取mysql.sql文件,然后到每个业务数据中执行 4、到https://github.com/seata/seata/tree/develop/script/config-center下获取config.txt。 若使用的是seata1.4.2以前的版本需要使用对应的脚本将config.txt中的配置上传到对应的配置中心。 以Nacos为例: 使用https://github.com/seata/seata/tree/develop/script/config-center/nacos下的nacos-config.sh 通过命令sh nacos-config.sh -h 119.3.50.65 -p 8848 -g SEATA_GROUP -t SEATA 参数说明: -h:主机,默认值为localhost。 -p:端口,默认值为8848。 -g:配置分组,默认值为'SEATA_GROUP'。 -t:租户信息,对应Nacos的命名空间ID字段,默认值为''。 -u:用户名,nacos 1.2.0+关于权限控制,默认值为''。 -w:密码,nacos 1.2.0+关于权限控制,默认值为''。 执行完以后到nacos中 可以查看到对应的新增配置项即可。 若使用的是seata1.4.2及以上版本时,需要在配置中心新建一个Data ID为seataServer.properties的配置项,并把config.txt中的内容复制 进去。 5、修改file.conf文件 主要是将 mode = "file" 修改为 mode = "db",并修改对应的数据库信息。注意mysql8的driverClassName为com.mysql.cj.jdbc.Driver 6、修改registry.conf文件 主要是将 registry config的type修改为使用的对应的配置中心,例如 type='nacos',然后修改对应的nacos配置信息 7、然后进入bin目录 使用 sh seata-server.sh -h 119.3.50.65 (-h 指定对应的服务器外网ip),启动seata,然后到nacos中查看seata是否已经注册进了nacos 到此seata已安装完成。 ### Seata使用 1、在pom.xml中引入 com.alibaba.cloud spring-cloud-alibaba-seata io.seata seata-spring-boot-starter io.seata seata-spring-boot-starter 1.4.2 2、在yml文件中新增 seata: enabled: true # application-id: seata-server #和seata registry 文件中的 application一致 tx-service-group: test-tx-group #此处配置自定义的seata事务分组名称 要与配置文件中的vgroupMapping一致 enable-auto-data-source-proxy: true #是否开启数据源自动代理,默认为true service: vgroupMapping: test-tx-group: default #此处的test-tx-group 需和 tx-service-group:后面配置的值一致 config: type: nacos nacos: server-addr: http://119.3.50.65:8848 group: "SEATA_GROUP" namespace: "SEATA" username: nacos password: nacos dataId: seataServer.properties registry: #registry根据seata服务端的registry配置 type: nacos nacos: application: seata-server #配置自己的seata服务 server-addr: http://119.3.50.65:8848 #根据自己的seata服务配置 cluster: default #配置自己的seata服务cluster, 默认为 default namespace: "SEATA" #根据自己的seata服务配置 username: nacos #根据自己的seata服务配置 password: nacos #根据自己的seata服务配置 group: SEATA_GROUP #根据自己的seata服务配置 3、在主启动类上加上@EnableAutoDataSourceProxy注解,启用数据源代理。 4、在有分布式业务的方法上加上@GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)注解 name 随便起,需保证唯一,rollbackFor表示出现改异常时进行回滚 ### Seata AT模式原理