Eureka:服务注册
@EnableEurekaServer:指明该模块作为Eureka注册中心的服务器
@EnableEurekaClient:指明这是一个Eureka客户端,要注册进EurekaServer中
位置:主启动类
@LoadBlanced:开启默认的负载均衡:轮询
位置:配置类
@EnableDiscoveryClient:服务发现
位置:主启动类
Zookeeper:服务注册
@EnableDiscoveryClient :开启服务发现
CAP:理论
Eureka主要保证高可用:AP
Zookeeper/Consul主要保证数据的一致:CP
web界面:
Eureka/Consul都有一个web界面。
Zookeeper只有一个linux客户端。
从CAP理论分析一下异同:
Eureka主要满足AP
Zookeeper/Consul主要满足CP
C:Consistency 强一致性
A:Avaliability 可用性
P: Partition tolerance 分区容错性
P在分布式中永远都要保证。
所以要么是CP,要么是AP。
三个只能占2个。
CAP理论关注粒度是数据,而不是整体系统设计的角度。
1. 最多只能同时较好的满足两个
CAP理论的核心:一个分布式系统不可能同时很好的满足三个需求。因此根据CAP原理将
NOSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类。
CA:单点集群,满足一致性,可用性的系统,通常扩展性不强大。
CP:满足一致性,分区容错性的系统,对数据一致性要求高,所以性能负担大。
Zookeeper/Consul
要求数据必须一致性。
AP:满足可用性,分许容错性的系统,通常可能对一致性要求低一些。
Eureka
场景:商场,暂时不一致错一点没关系,只要能正常访问下单即可。
Eureka通过设置一些属性,也可以通过牺牲高可用性实现一致性的要求。
2. 分布式必须满足:P: Partition tolerance 分区容错性
Ribbon
Spring Cloud Ribbon是基于NetFlix Ribbon实现的一套客户端 负载均衡工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。
一句话,实现负载均衡的一套客户端工具结合RestTemplate实现调用。
原因是spring-boot-netfix-eureka-client自带了spring-starter-ribbon引用
所谓的负载均衡,就是Ribbon结合RestTemplate实现调用微服务之间的调用。
指明访问的服务CLOUD-PAYMENT-SERVICE,和指定了负载均衡策略 在主配置类加上如下注解:
@RibbonClient(name = “CLOUD-PAYMENT-SERVICE”, configuration =
MySelfRule.class)
OpenFegin
想要远程调用别的服务
1、引入open-fegin
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、创建feign包,编写一个接口、告诉springcloud这个接口需要调用远程服务
//告诉spring cloud这个接口是一个远程客户端,要调用coupon服务,
//再去调用coupon服务/coupon/coupon/member/list对应的方法
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
}
3、声明接口的每一个方法都是调用哪个远程服务的那个请求
//告诉spring cloud这个接口是一个远程客户端,要调用coupon服务,
//再去调用coupon服务/coupon/coupon/member/list对应的方法
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
@RequestMapping("/coupon/coupon/member/list")
public R membercoupons();//得到一个R对象
}
4、开启远程调用功能
@EnableFeignClients(basePackages="com.atguigu.gulimall.member.feign")
位置:主启动类
basePackages:找到接口所在的包,即feign包
5、Controller类中,注入这个service,并执行其中的方法
6、案例
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
/**
* 1、CouponFeignService.saveSpuBounds(spuBoundTo);
* 1)、@RequestBody将这个对象转为json。
* 2)、找到gulimall-coupon服务,给/coupon/spubounds/save发送请求。
* 将上一步转的json放在请求体位置,发送请求;
* 3)、对方服务收到请求。请求体里有json数据。
* (@RequestBody SpuBoundsEntity spuBounds);将请求体的json转为SpuBoundsEntity;
* 只要json数据模型是兼容的。双方服务无需使用同一个to
* @param spuBoundTo
* @return
*/
@PostMapping("/coupon/spubounds/save")
R saveSpuBounds(@RequestBody SpuBoundTo spuBoundTo);
@PostMapping("/coupon/skufullreduction/saveinfo")
R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);
}
Hystrix
是一个用于处理分布式系统延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等。
Hystrix能够保证在一个依赖出问题的情况下,不会导致整个服务失败,避免级联故障,以提高分布式系统的弹性
Hystrix一般用于80客户侧降级
主要功能
服务降级
服务熔断
接近实时的监控
限流
隔离
服务降级:fallback
假如对方的系统不可用了,你需要给我一个兜底的解决办法或备选响应。
服务熔断:break
类似保险丝达到最大访问服务后,直接拒绝访问,拉闸断电,然后调用服务降级的方法并返回友好提示。
先熔断,拒绝访问,再调用服务降级返回备选响应(友好提示),再恢复调用链路。
服务限流:flowlimit
秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行。
服务降级 : 服务生产者
1、服务降级:支付侧(生产者服务)
设置自身调用超时时间的峰值,峰值内可以正常运行。
超过了就需要有兜底的方法处理,做服务降级fallback。
向调用方返回一个符合预期的,可处理的备选响应(FallBack)
2、业务类上启动@HystrixCommand
规定这个线程的超时时间是3s,3s后就由fallbackMethod指定的方法帮我“兜底”(服务降级)
服务降级:会自动调用@HystrixCommand中fallbackMethod指定的方法。
@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler", commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",
value = "3000")
})
3、主启动类上要激活
@EnableCircuitBreaker
服务降级 : 服务消费者
服务降级即可以放在消费端/客户端也可以放在服务端。
一般是放在客户端。
1、修改yml文件
开启feign客户端支持hystrix属性
2、主启动类:@EnableHystrix
注意: @EnableHystrix注解包含了在8001主配置类上加的@EnableCircuitBreaker注解
3、 业务类
@HystrixCommand(fallbackMethod = “paymentInfo_TimeoutHandler”, commandProperties = {
@HystrixProperty(name=“execution.isolation.thread.timeoutInMilliseconds”,value = “3000”)
})
面临的问题
- 我们现在服务降级的方法和业务处理的方法混杂在了一块,耦合度高。
- 如果每个接口,每个方法都需要一个“兜底”的方法,那么就会造成代码臃肿。
所以我们需要一个:全局的服务降级,global fallback。
需要特殊照顾的方法,我们再精确的配置服务降级。
解决代码臃肿的问题
没有配置过fallback,就找在该类上配置的defaultfallback,配置过的就找自己单独配置的。
需要使用服务降级的方法还是要加上@HystrixCommand,只是不再单独指定一个降级方法。
通用的和独享的各自分开,避免了代码膨胀,合理减少了代码量。
@DefaultProperties(defaultFallback = “”)
解决代码耦合度高的问题
1、抓住关键点
你只要是用Feign进行微服务的调用,那么一定有这个
@FeignClient(value = “CLOUD-PROVIDER-HYSTRIX-PAYMENT”)注解的接口,这个接口就能实现调用其他微服务的操作.
2、我们将这个接口中的全部方法来进行统一的fallback服务降级
3、 服务降级:客户端去调用服务端,碰上服务端宕机或关闭
4、具体操作
根据cloud-consumer-feign-hystrix-order80已经有的PaymentHystrixService接口,
重新新建一个类(PaymentFallbackService)实现该接口,统一为接口里的方法进行异常处理。
想要实现的效果是:
正常的话就找指定的微服务中的方法。
异常的话就找PaymentFallbackService,由它来进行统一的处理。
将新建的用来处理服务降级的类,添加到IOC中并且配置到Feign客户端定义的接口中。
发现执行的服务降级,而且我们没有在业务层为paymentInfo_OK()方法进行任何的服务降级处理。
也没有加@HystrixCommand注解。在业务层paymentInfo_OK()方法没有耦合的代码
@FeignClient(value = “CLOUD-PROVIDER-HYSTRIX-PAYMENT”,
fallback = PaymentFallbackService.class)和
@Component
public class PaymentFallbackService implements PaymentHystrixService{}
结合解决服务降级在业务层产生耦合代码的情况。
Hystrix:服务熔断
Hystrix的服务熔断理论
服务熔断也会触发服务降级
类比保险丝,达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。
流程:服务降级—>进而熔断—>恢复调用链路
熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者
响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
当再次检测到该节点微服务调用响应正常后,恢复调用链路。
在SpringCloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况。
当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。
熔断机制的注解是@HystrxiCommand
半开状态:
比如说一个微服能承受100的并发量,某一时刻有500人同时访问。该服务就会崩掉,熔断,直接当掉。
外部此时不能访问了,过了一会,发现没有那么高的并发量了。感觉并发量在我的承受之内了(100)。
比如1s/72次,那么就试着这放开这些并发请求。
放着放着发现能够适应当前的并发量了,我再把闸道合上。
放着放着的状态就是半开状态,然后再把断路器合上变成打开的状态。
案例
@HystrixCommand(fallbackMethod = “paymentCircuitBreaker_fallback”, commandProperties = {
@HystrixProperty(name = “circuitBreaker.enabled”, value = “true”), //是否开启断路器
当在配置时间窗口内达到此数量的失败后,进行短路。10个/10s 注意分母是10s。 默认20个/10s
@HystrixProperty(name = “circuitBreaker.requestVolumeThreshold”, value = “10”),
//短路多久以后开始尝试是否恢复,默认5s
@HystrixProperty(name = “circuitBreaker.sleepWindowInMilliseconds”, value = “10000”),
//失败率达到多少后跳闸
@HystrixProperty(name = “circuitBreaker.errorThresholdPercentage”, value = “60”),
})
服务熔断总结
1. 熔断类型
1. 熔断打开:
请求不再进行调用当前服务,再有请求调用时将不会调用主逻辑,而是直接调用降级fallback。实现
了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟效果。
内部设置时钟一般为MTTR(平均故障处理时间),当打开熔断时长达到所设时钟则进入半熔断状态。
2. 熔断关闭
熔断关闭后,服务正常开始调用。
3. 熔断半开
部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务回复正常,关闭熔断。
2. 断路器默认开启的条件
1. 当(失败频率)满足一定的阈值时: > 20次/10s
2. 当失败率达到一定的时候:10s内50%的失败请求。
注意:两个条件要都满足,才会开启断路器。
比如10s内出错21次,正确100次。
满足情况1,不满足情况2.
断路器也不会开启。
3. 一段时间后,默认是5s,这个时候断路器从开启变成半开状态。会放行一些请求,
如果成功,断路器关闭,若失败继续开启。
3. 熔断器开启式,主逻辑怎么恢复呢?
Nacos:注册中心
Nacos就是 注册中心+配置中心 的组合。
等价于:Eureka + Config + Bus
1、POM
父POM
<!--spring cloud 阿里巴巴-->
<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>
子POM
<dependencies>
<!--spring cloud alibaba nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
2、yml
spring:
application:
name: naocs-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
3、主启动类
@EnableDiscoveryClient
Nacos:配置中心
基础
1、引入配置中心依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2、项目中创建 bootstrap.properties 文件作为配置中心文件
# 会优先于application.properties,进行加载
# 当前模块的名字
spring.application.name=gulimall-coupon
#配置中心的地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
3、编写controller去获取配置文件的变量
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@Value("${coupon.user.name}")//从application.properties中获取//不要写user.name,他是环境里的变量
private String name;
@Value("${coupon.user.age}")
private Integer age;
@RequestMapping("/test")
public R test(){
return R.ok().put("name",name).put("age",age);
}
}
4、对nacos进行配置管理---->配置列表
浏览器去nacos里的配置列表,点击+号,
需要给配置中心默认添加一个 叫数据集(Data ID)
data ID:gulimall-coupon.properties。默认规则,应用名.properties
给应用名.properties添加配置,然后点击发布
# gulimall-coupon.properties
coupon.user.name="张三"
coupon.user.age=12
5、实现修改后实现自动刷新,在controller上加上这个注解
@RefreshScope
6、总结
重启后,在nacos浏览器里修改配置,修改就可以观察到能动态修改了
nacos的配置内容优先于项目本地的配置内容
进阶
命名空间:用作配置隔离。(一般每个微服务一个命名空间)
默认public。默认新增的配置都在public空间下
开发、测试、开发可以用命名空间分割。properties每个空间有一份。
在bootstrap.properties里配置
spring.cloud.nacos.config.namespace=b176a68a-6800-4648-833b-be10be8bab00
可以选择对应的命名空间 ,即写上对应环境的命名空间ID 也可以为每个微服务配置一个命名空间,微服务互相隔离,只加载自己命名空间下的所有配置
配置集:一组相关或不相关配置项的集合。
配置集ID:类似于配置文件名,即Data ID
配置分组:
默认所有的配置集都属于DEFAULT_GROUP
自己可以创建分组,比如双十一,618,双十二
spring.cloud.nacos.config.group=DEFAULT_GROUP # 更改配置分组
总结
最终方案:每个微服务创建自己的命名空间,然后使用配置分组区分环境(dev/test/prod)
加载多配置集
我们要把原来application.yml里的内容都分文件抽离出去。
分成datasource.yml、mybatis.yml、other.yml
我们在nacos里创建好后,在coupons里指定要导入的配置即可。
spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=true
spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].refresh=true
spring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[2].refresh=true
总结
微服务中的任何配置信息,任何配置文件都可以放在配置中心里面
只需要在bootstrap.properties说明加载配置中心哪些配置文件即可
以前springboot任何方法从配置文件中获取值,都能使用
有配置中心的,优先使用配置中心的
gateway
一、Gateway的三大核心概念
1. Route路由
路由是构建网关的基本模块,它由ID,目标URI,一些列的断言和过滤器组成,
如果断言为true则匹配该路由。
路由转发:
发送请求调用微服务时,负载均衡分派到微服务之前,会经过网关。
具体分派到哪个微服务,要符合网关的路由转发规则,才能转发到指定微服务。
2. Predicate断言
参考的是Java8的java.util.function.Predicate
开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由。
3. Filter过滤
指的是Spring框架中GatewayFliter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
处理请求前和处理请求后都可能有Filter
核心流程:当请求到达网关,网关利用断言,判定这次请求是否符合某个路由规则,符合则根据该路由规则把请求路由到指定地方,期间需要经过一系列filter进行过滤。
核心逻辑:路由转发+执行过滤器链
二、能干嘛
路由、权限坚定、监控、
限流、服务降级、服务熔断
三、配置
(1)pom
<!--引入网关gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
前提要有nacos服务注册的依赖,并在applicationyml配置了nacos,进行注册
(2)开启注册服务发现
@EnableDiscoveryClient
主启动类
(3)yml
#网关配置
spring:
cloud:
gateway:
routes:
- id: baidu_route # 路由id:baidu_route,没有规则,唯一就行
uri: http://www.baidu.com # 匹配后提供服务的路由地址
predicates:
- Query=url,baidu # 断言,是否有参数url,且值为百度
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: test_route
uri: http://www.qq.com
predicates:
- Query=url,qq
Config
@EnableConfigServer
Sentinel
@SentinelResource