Spring CouldAlibaba

Posted 覃会程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring CouldAlibaba相关的知识,希望对你有一定的参考价值。

Spring Could主要内容结构图:





简介

Spring Cloud Netflix将不再开发新的组件,进入维护模式。

我们都知道Spring Cloud版本迭代算是比较快的,因而出现了很多重大ISSUE都还来不及Fix就又推另一个Release了。进入维护模式意思就是目前一直以后一段时间Spring Cloud Netfli提供的服务和功能就这么多了,不在开发新的组件和功能了。以后将以维护和Merge分支Full Request为主。

Spring Cloud Alibaba的作用:

  • 服务限流降级:默认支持Servlet、Feign、RestTemplate、Dubbo和RocketMQ限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级Metrics 监控。
  • 服务注册与发现:适配 Spring Cloud服务注册与发现标准,默认集成了 Ribbon的支持。
  • 分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。
  • 消息驱动能力:基于Spring Cloud Stream为微服务应用构建消息驱动能力。
  • 阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
  • 分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于Cron表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有Worker (schedulerx-client)上执行。

Nacos服务注册和配置中心

名字的由来:前四个字母分别为Naming和Configuration的前两个字母,最后的s为Service。

Nacos是什么:

Nacos就是注册中心+配置中心的组合

相当于:Nacos = Eureka + Config + Bus

各注册中心的比较:

注意:Nacos支持AP和CP模式的切换

在父工程pom文件中引入alibaba 依赖,以下所有案例都基于该父工程

<!--  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>

Navos服务提供者注册

pom文件:

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>$project.version</version>
        </dependency>

    </dependencies>

yml文件:

server:
  port: 9001
spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
management:
  endpoints:
    web:
      exposure:
        include: "*"

启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderMain9001 
    public static void main(String[] args) 
        SpringApplication.run(NacosProviderMain9001.class,args);
    


controller:

@RestController
@RequestMapping("/payment")
public class PaymentController 

    @Value("$server.port")
    public String serverPort;

    @RequestMapping("/getPayment/id")
    public String getPayment(@PathVariable("id") Integer id)
        return "Alibaba Nacos server "+ serverPort+"-----"+id;
    


Nacos服务消费者的注册

pom文件:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

yml文件:

server:
  port: 83

spring:
  application:
    name: cloud-nacos-order
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

#消费者将要去访问的微服务名称
server-url:
  nacos-user-service: http://nacos-payment-provider

启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class NacosOrderMain83 

    public static void main(String[] args) 
        SpringApplication.run(NacosOrderMain83.class,args);
    

controller:

@RestController
public class OrderNacosController 

    @Resource
    private RestTemplate restTemplate;

    @Value("$server-url.nacos-user-service")
    private String url;

    @GetMapping("/order/getPayment/id")
    public String getPaymentInfo(@PathVariable("id") Long id) 
        return restTemplate.getForObject(url+"/payment/getPayment/"+id,String.class);
    

配置类:

@Configuration
public class ApplicationContextConfig 

    @Bean
    @LoadBalanced  //负载均衡:轮询
    public RestTemplate getRestTemplate()
        return new RestTemplate();
    

注意:Nacos是默认整合了Ribbon的,能够自动实现负载均衡,所以需要添加@LoadBalanced 注解,否则会报错。





Nacos作为服务配置中心

pom文件:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

配置文件:

Nacos同springcloud-config一样,在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动。
springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application

bootstrap文件:

server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  #Nacos服务注册中心地址
      config:
        server-addr: localhost:8848  #Nacos作为配置中心地址
        file-extension: yaml #指定yaml格式的配置
        # group: TEST_GROUP 
        namespace: 7a901d46-e75e-4e6a-b186-5980cca4249b



# $spring.application.name-$spring.profile.active.$spring.cloud.nacos.config.file-extension
#nacos-config-client-dev.yaml

application文件:

spring:
  profiles:
    active: dev

启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class ConfigNacosMain3377 

    public static void main(String[] args) 
        SpringApplication.run(ConfigNacosMain3377.class,args);
    

controller

@RestController
@RefreshScope  //支持nacos的动态刷新功能
public class ConfigClientController 

    @Value("$config.info")
    private String configInfo;

    @GetMapping("/config/info")
    public String getConfigInfo() 
        return configInfo;
    


Nacos界面配置对应:

最后公式:

$spring.application.name$spring.profiles.active.$(spring.cloud.nacos.config.file-extension


启动项目,成功获取配置文件

多环境多项目管理

问题1:
实际开发中,通常一个系统会准备
dev开发环境
test测试环境
prod生产环境。
如何保证指定环境启动时服务能正确读取到Nacos上相应环境的配置文件呢?

问题2:
一个大型分布式微服务系统会有很多微服务子项目,
每个微服务项目又都会有相应的开发环境、测试环境、预发环境、正式环境.
那怎么对这些微服务配置进行管理呢?

Namespace+Group+Data lD三者关系:

最外层的namespace是可以用于区分部署环境的,Group和DataID逻辑上区分两个目标对象。

默认情况:
Namespace=public,Group=DEFAULT_GROUP,默认Cluster是DEFAULT

Nacos默认的命名空间是public,Namespace主要用来实现隔离。
比方说我们现在有三个环境:开发、测试、生产环境,我们就可以创建三个Namespace,不同的Namespace之间是隔离的。

Group默认是DEFAULT_GROUP,Group可以把不同的微服务划分到同一个分组里面去

Service就是微服务;一个Service可以包含多个Cluster(集群),Nacos默认Cluster是DEFAULT,Cluster是对指定微服务的一个虚拟划分。比方说为了容灾,将Seryice微服务分别部署在了杭州机房和广州机房,
这时就可以给杭州机房的Service微服务起一个集群名称(HZ) ,
给广州机房的Service微服务起一个集群名称(GZ),还可以尽量让同一个机房的微服务互相调用,以提升性能。

最后是lnstance,就是微服务的实例。





## Nacos集群

默认Nacos使用嵌入式数据库实现数据的存储。所以,如果启动多个默认配置下的Nacos节点(Nacos集群),数据存储是存在一致性问题的。为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持mysql的存储。

参考文章:

集群部署:link

集群配置:link





Sentinel实现熔断和限流

和Hystrix的对比

下载地址:

Sentinel分为两个部分:

  • 核心库(Java客户端)不依赖任何框架/库,能够运行于所有Java运行时环境,同时对 Dubbo /Spring Cloud等框架也有较好的支持。
  • 控制台(Dashboard)基于Spring Boot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。

启动本地Sentinel后

搭建服务,并将服务入驻Sentinel控制台(Dashboard)

pom文件:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
<!--        后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</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>

yml文件:

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: localhost:8080 #配置Sentinel dashboard地址
        port: 8719
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: $spring.application.name
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

management:
  endpoints:
    web:
      exposure:
        include: '*'

测试controler:

@RestController
public class FlowLimitController 

    @RequestMapping("testA")
    public String testA()
        return "testA-------";
    

    @RequestMapping("testB")
    public String testB()
        return "testB-------";
    

启动服务,观察Sentinel控制台

注意:Sentinel是懒加载模式,需要被监控的服务有请求后,才会显示监控信息。

监控规则说明

用于对每一个接口进行配置,规定接口的访问限制,如果不符合条件则调用失败。相当于将Hystrix在代码注解中的配置,在控制界面进行。

解释说明:

控流模式

直接模式流控

如下图的配置表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误

关联模式流控

当关联的资源达到阈值时,就限流自己

比如当与A关联的资源B达到阀值后,就限流A自己。

上图的设置效果:

当关联资源/testB的qps阀值超过1时,就限流/testA的Rest访问地址,当关联资源到阈值后限制配置好的资源名

控流效果

快速失败

默认的流控效果,直接返回失败

Warm Up

Warm Up ( RuleConstant.cONTROL_BEHAVIOR_NARA_up)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动"”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。详细文档可以参考流星控制- Warm Up文档,具体的例子可以参见

公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

默认coldFactor为3,即请求QPS从(threshold / 3)开始,经多少预热时长才逐渐升至设定的QPS阈值。

案例:
阀值为10+预热时长设置5秒。系统初始化的阀值为10/3约等于3,即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10

应用场景:

如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。

排队等待

匀速排队,让请求以均匀的速度通过,阀值类型必须设成QPS,否则无效。
设置含义:/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒


应用场景:

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一次直接拒绝多余的请求。

降级规则

和Hystrix相似,只是Sentinel是在监控界面进行配置,不需要在代码中使用注解进行配置。

Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。

当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。

注意:Sentinel的断路器是没有半开状态的,和Hystrix区别开,只要在窗口时间内没有触发新的熔断,窗口事件过后就会恢复。

半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,
有异常则继续打开断路器不可用。具体可以参考Hystrix

RT(平均响应时间,秒级)降级策略

平均响应时间超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级窗口期过后关闭断路器
RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)


案例:


假如一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,
如果超过20O0毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了

异常比列(秒级)降级策略

QPS >= 5且异常比例(秒级统计)超过阈值时,触发险级;时间窗口结束后,关闭降级

异常比例( DEGRADE_GRADE_EXCEPTION_RATIo):当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值( DegradeRule中的count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule中的timewindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%到100%。


案例:

当一秒钟内访问量超过5,且调用失败的比例超多百分之20,则触发降级一秒钟,一秒钟后关闭降级。

异常数(分钟级)降级策略

异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级

时间窗口一定要大于等于60秒。

异常数(DEGRADE_GRADE_EXCEPTION_COUNT ):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若timewindow小于60s,则结束熔断状态后可能再进入熔断状态。

案例:


http://localhost:8401/testE,第一次访问绝对报错,因为除数不能为零,我们看到error窗口,但是达到5次报错后,进入熔断后降级。

上述三种规则的测试代码:

    @RequestMapping("testC")
    public String testC()
        try 
            TimeUnit.SECONDS.sleep(6);
         catch (InterruptedException e) 
            e.printStackTrace();
        
        return "testC 测试RT-------";
    

    @RequestMapping("testD")
    public String testD()
        System.out.println("testD 异常比例测试");
        int age = 10/0;
        return "testD-------";
    

    @RequestMapping("testE")
    public String testE()
        System.out.println("testD 异常s数--测试");
        int age = 10/0;
        return "testD-------";
    

热点key限流(热点规则)

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的Top K数据,并对其访问进行限制。比如:

  • 商品ID为参数,统计一段时间内最常购买的商品ID并进行限制
  • 用户ID为参数,针对一段时间内频繁访问的用户ID进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。


在1秒钟内,携带第一个参数的请求超过1一次,则进行服务降级,调用指定方法返回,没有指定则会返回错误页面

测试代码:

    @RequestMapping(&#

以上是关于Spring CouldAlibaba的主要内容,如果未能解决你的问题,请参考以下文章

Spring CouldAlibaba

Spring CouldAlibaba

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

Spring boot:thymeleaf 没有正确渲染片段

What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段