SpringCloud 学习
1.初始环境搭建
-
SpringCloud 和 SpringBoot之间的选择
- cloud: Hoxton.SR1
- boot: 2.2.2.RELEASE
- cloud alibaba: 2.1.0.RELEASE
- java: Java8
- Maven: 3.5及以上
- Mysql: 5.7及以上
2.SpringCloud热门组件
1.注册中心
-
Eureka服务注册与发现(已停更)
-
服务治理
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。 Eureka包含两个组件:Eureka Server和Eureka Client。 Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。 Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。 在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。 Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
-
-
Zookeeper服务注册与发现
-
Consul服务注册与发现
-
三个注册中心的异同
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UENywKZg-1615341758121)(.\注册中心异同.png)]
-
CAP分布式架构(CAP理论关注粒度是数据,而不是整体系统设计策略)
- C(Consistency 强一致性)
- A (Availability 可用性)
- P(Partition tolerance 分区容错性)
2.Ribbon(服务调用)
- Ribbon概述(维护中)——负载均衡+RestTemplate
1. SpringCloud Ribbon 是一个客户端的负载均衡组件,主要提供负载均衡算法。
2. Ribbon中负载均衡算法实现:
AbstractLoadBalancerRule:负载均衡策略的抽象类,在该抽象类中定义了负载均衡器ILoadBalancer对象,该对象能够在具体实现选择服务策略时,获取到一些负载均衡器中维护的信息来作为分配依据,并以此设计一些算法来实现针对特定场景的高效策略。
-
RestTemplate
delete() 在特定的URL上对资源执行HTTP DELETE操作 exchange() 在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的 execute() 在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象 getForEntity() 发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象 getForObject() 发送一个HTTP GET请求,返回的请求体将映射为一个对象 postForEntity() POST 数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得到的 postForObject() POST 数据到一个URL,返回根据响应体匹配形成的对象 headForHeaders() 发送HTTP HEAD请求,返回包含特定资源URL的HTTP头 optionsForAllow() 发送HTTP OPTIONS请求,返回对特定URL的Allow头信息 postForLocation() POST 数据到一个URL,返回新创建资源的URL put() PUT 资源到特定的URL
-
Ribbon核心组件IRule
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dHjc0TFC-1615341758125)(.\IRule.png)]
名称 | 作用 |
---|---|
RoundRobinRule | 轮询 |
RandomRule | 随机 |
RetryRule | 先按照RoundRobinRule策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用服务 |
WeightedResponseTimeRule | 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择 |
BestAvailableRule | 会过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务 |
AvailabilityFilteringRule | 先过滤掉故障实例,再选择开发较小的实例 |
ZoneAvoidanceRule | 默认规则,复合判断server所在区域的性能和server的可用性选择服务器 |
-
如何替换
-
项目结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EPlQ2vBN-1615341758127)(C:\Users\张勇召\Desktop\cloud\Ribbon替换算法项目结构.png)]
-
项目代码
package com.ruobai.myrule; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MySelfRule { @Bean public IRule myRule(){ return new RandomRule();//定义为随机 } }
-
-
自定义轮询算法
负载均衡算法:rest接口第几次请求数%服务器集群总数量 = 实际调用服务器位置下标,每次服务其重启后rest接口计数从1开始
如: 总计数:2台 List = 2 instance List[0] instance = 127.0.0.1:8002 List[1] instance = 127.0.0.1:8001 1 % 2 = 1 -> index = 1 list.get(index),服务地址为127.0.0.1:8001 2 % 2 = 1 -> index = 0 list.get(index),服务地址为127.0.0.1:8002 3 % 2 = 1 -> index = 1 list.get(index),服务地址为127.0.0.1:8001 4 % 2 = 0 -> index = 0 list.get(index),服务地址为127.0.0.1:8002 如此类推......
3.OpenFeign(服务调用)
- 概述
1. Feign是声明性Web服务客户端。它使编写Web服务客户端更加容易。要使用Feign,请创建一个接口并对其进行注释。它具有可插入注释支持,包括Feign注释和JAX-RS注释。 Feign还支持可插拔编码器和解码器。 Spring Cloud添加了对Spring MVC注释的支持,并支持使用Spring Web中默认使用的相同HttpMessageConverters。 Spring Cloud集成了Ribbon和Eureka以及Spring Cloud LoadBalancer,以在使用Feign时提供负载平衡的http客户端。
-
OpenFeign应用
-
Config
/** * @apiNote :Feign日志开启 * FULL开启详细日志 * */ @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
-
Service
@Component @FeignClient("CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id); @GetMapping("/payment/feign/timeout") public String paymentFeignTimeout(); }
-
4.Hystrix(服务降级、服务熔断、服务 限流)
-
概述
1.hystrix是Netlifx开源的一款容错框架,防雪崩利器,具备服务降级,服务熔断,依赖隔离,监控(Hystrix Dashboard)等功能。 2.服务降级:服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,feedback。发生原因:程序运行异常、超时、服务熔断触发服务降级、线程池/信号量打满也会导致服务降级 3.服务熔断:类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示——服务的降级-->进而熔断-->恢复调用链路 4.服务限流:秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
-
Hystrix应用
-
Hystrix开启服务降级和服务熔断
package com.ruobai.springcloud; import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; /** *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑 *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream", *只要在自己的项目里配置上下面的servlet就可以了 *两种方法: * 1.yml中配置: * management: * endpoints: * web: * exposure: * include: 'hystrix.stream' * 监控地址为:http://localhost:8001/actuator/hystrix.stream * 2.创建ServletRegistrationBean的Bean * @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:8001/hystrix.stream * / /** * @EnableCircuitBreaker * */ @SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker public class PaymentHystrixMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentHystrixMain8001.class,args); } // @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; // } }
-
服务降级、服务熔断配置
package com.ruobai.springcloud.service; import cn.hutool.core.util.IdUtil; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.PathVariable; import java.util.concurrent.TimeUnit; @Service public class PaymentService { /** * @param id * @return * */ public String paymentInfo_OK(Integer id){ return "线程池:"+Thread.currentThread().getName()+" paymentInfo_OK,id:"+id+"\t"+"haa~"; } /**@ApiNote: 服务提供者服务降级 * @HystrixCommand: 一旦调用服务方法失败并抛出错误信息后, * 会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法 * @Param: @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000") 设置超时时间3秒 * */ @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000") }) public String paymentInfo_timeOut(Integer id){ // int age = 10/0; int timeNumber = 3; try { TimeUnit.SECONDS.sleep(timeNumber); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池:"+Thread.currentThread().getName()+" paymentInfo_timeOut,id:"+id+"\t"+"haa~"+"耗时(秒):"+timeNumber; } public String paymentInfo_TimeOutHandler(Integer id){ return "线程池:"+Thread.currentThread().getName()+" 系统繁忙或者运行报错,请稍后再试"+id+"\t"+"/(ㄒoㄒ)/~~"; } //=====服务熔断 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//请求次数超过了峰值,熔断器将会从关闭到打开 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),//时间窗口期 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),//失败率达到多少后跳闸 }) public String paymentCircuitBreaker(@PathVariable("id") Integer id){ if ( id < 0){ throw new RuntimeException("*****id 不能为负数"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName()+"\t"+"调用成功,流水号: "+serialNumber; } public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){ return "id 不能为负数,请稍后再试,/(ㄒoㄒ)/~~ id:"+id; } }
-
-
Hystrix dashboard
-
dashboard(控制面板)开启
需要在yml文件中设置监控点
management: endpoints: web: exposure: include: 'hystrix.stream'
package com.ruobai.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class HystrixDashboardMain9001 { public static void main(String[] args) { SpringApplication.run(HystrixDashboardMain9001.class,args); } }
-
5.GateWay(服务网关)
-
概述
1.SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。 2.SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 2.0之前的非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。 3.Spring Cloud Gateway 的目标,不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
-
GateWay应用
-
Route(路由)
routes: - id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 #uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service #匹配后提供服务的路由地址
-
Filter(自定义过滤器)
package com.ruobai.springcloud.filter; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.util.Date; @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("*****用户名为null,非法用户,/(ㄒoㄒ)/~~"); exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }
-
Predicate(断言)
predicates: - Path=/payment/lb/** # 断言,路径相匹配的进行路由 - After=2021-02-07T15:50:29.733183100+08:00[Asia/Shanghai] # - Before=2021-02-28T15:50:29.733183100+08:00[Asia/Shanghai] # - Between=2021-02-07T15:50:29.733183100+08:00[Asia/Shanghai],2021-02-28T15:50:29.733183100+08:00[Asia/Shanghai] # - Cookie=username,zzyy #Cookie验证成功 # - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式 # - Method=GET # - Query=username,\d+
-
6.Config(配置中心)
-
概述
1.Spring Cloud Config为分布式系统中的外部化配置提供服务器端和客户端支持。使用Config Server,您可以在中心位置管理所有环境中应用程序的外部属性。客户端和服务器上的概念与Spring Environment和PropertySource抽象完全相同,因此它们非常适合Spring应用程序,但可以与以任何语言运行的任何应用程序一起使用。在应用程序从开发人员到测试人员再到生产人员的整个部署管道中进行移动时,您可以管理这些环境之间的配置,并确保应用程序具有它们迁移时所需的一切。服务器存储后端的默认实现使用git,因此它可以轻松支持配置环境的标记版本,并且可以通过各种工具来访问这些内容来管理内容。添加替代实现并将其插入Spring配置很容易。
-
pom依赖
-
config server
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
-
config client
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
-
-
yml配置
-
native config server
server: port: 8762 spring: application: name: nativeConfigserver profiles: active: native cloud: config: server: native: search-locations: classpath:/shared
-
native config client
spring: application: name: configclient profiles: active: dev cloud: config: uri: http://localhost:8762 fail-fast: true
-
GitHub config server
server: port: 8888 spring: application: name: configserver cloud: config: server: git: uri: https://github.com/ruobai-s/aispringcloud.git search-paths: config username: 2522100775@qq.com password: zyzonlyyou0809 label: master eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true
-
GitHub config client
spring: cloud: config: name: configclient label: master discovery: enabled: true service-id: configserver eureka: client: registerWithEureka: false fetchRegistry: false service-url: defaultZone: http://localhost:8761/eureka/
-
-
Config Server 启动器
@SpringBootApplication @EnableConfigServer public class NativeConfigServerApplication { public static void main(String[] args) { SpringApplication.run(NativeConfigServerApplication.class,args); } }
-
Config Client
package com.ruobai;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class,args);
}
}
7.Bus-RabbitMQ(消息总线)
-
概述
Spring Cloud Bus将轻量级消息代理程序链接到分布式系统的节点。 然后可以使用此代理来广播状态更改(例如配置更改)或其他管理指令。 一个关键思想是,总线就像是横向扩展的Spring Boot应用程序的分布式执行器。 但是,它也可以用作应用之间的通信渠道。 该项目为AMQP经纪人或Kafka提供了入门服务。
-
RabbitMQ
-
概述
1.RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而群集和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。 2.主要特性 可伸缩性:集群服务 消息持久化:从内存持久化消息到硬盘,再从硬盘加载到内存
-
概念模型
-
-
pom依赖
<!--添加消息总线RabbitMQ支持--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
-
server yml
#rabbitmq相关配置 rabbitmq: host: 192.168.16.129 port: 5672 username: ems password: 123 virtual-host: /ems ##rabbitmq相关配置,暴露bus刷新配置的端点 management: endpoints: #暴露bus刷新配置的端点 web: exposure: include: 'bus-refresh'
-
client yml
#rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口 rabbitmq: host: 192.168.16.129 port: 5672 username: ems password: 123 virtual-host: /ems # 暴露监控端点 management: endpoints: web: exposure: include: "*"
-
Bus-RabbitMQ启动器
package com.ruobai.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableConfigServer public class ConfigCenterMain3344 { public static void main(String[] args) { SpringApplication.run(ConfigCenterMain3344.class,args); } }
-
Bus-RabbitMQ Client
package com.ruobai.springcloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RefreshScope //实时监控刷新点进行配置更行 public class ConfigClientController { @Value("${server.port}") private String serverPort; @Value("${config.info}") private String configInfo; @GetMapping("/configInfo") public String getConfigInfo() { return "serverPort:"+serverPort+"\t\n\n configInfo:"+configInfo; } }
8.Cloud Stream(消息驱动)
-
概述
1.在实际开发过程中,服务与服务之间通信经常会使用到消息中间件,而以往使用了哪个中间件比如RabbitMQ,那么该中间件和系统的耦合性就会非常高,如果我们要替换为Kafka那么变动会比较大,这时我们可以使用SpringCloudStream来整合我们的消息中间件,来降低系统和中间件的耦合性。 2.应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream 中binder 交互,通过我们配置来 binding ,而 Spring Cloud Stream 的 binder 负责与消息中间件交互。所以,我们只需要搞清楚如何与 Spring Cloud Stream 交互就可以方便使用消息驱动的方式。通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,引用了发布-订阅、消费组、分区的三个核心概念。目前仅支持RabbitMQ、Kafka。 3.Stream 解决了什么问题:Stream解决了开发人员无感知的使用消息中间件的问题,因为Stream对消息中间件的进一步封装,可以做到代码层面对中间件的无感知,甚至于动态的切换中间件(rabbitmq切换为kafka),使得微服务开发的高度解耦,服务可以关注更多自己的业务流程
-
常用注解
组成 说明 Middleware 中间件,目前只支持RabbitMQ和Kafka Binder Binder是应用与消息中间件之间的封装,目前实行了Kafka和RabbitMQ的Binder,通过Binder可以很方便的连接中间件,可以动态的改变消息类型(对应于Kafka的topic,RabbitMQ的exchange),这些都可以通过配置文件来实现 @Input 注解标识输入通道,通过该输入通道接收到的消息进入应用程序。 @Output 注解标识输出通道,发布的消息将通过该通道离开应用程序 @StreamListener 监听队列,用于消费者的队列的消息接收 @EnableBinding 指信道channel和exchange绑定在一起