SpringCloudAlibaba
作者:mmseoamin日期:2024-03-20

一.SpringCloudAlibaba介绍

什么是SpringCloudAlibaba?

Spring Cloud Alibaba旨在为微服务开发提供一站式解决方案。该项目包括开发分布式应用程序和服务所需的组件,以便开发人员可以使用Spring Cloud编程模型轻松开发分布式应用程序。使用Spring Cloud Alibaba,您只需要添加一些注释和配置,就可以为您的应用程序使用Alibaba的分布式解决方案,并使用Alibaba中间件构建自己的分布式系统。

Spring Cloud Alibaba其实是阿里的微服务解决方案,是阿里巴巴结合自身微服务实践,开源的微服务全家桶,在Spring Cloud项目中孵化成为Spring Cloud的子项目。第一代的Spring Cloud标准中很多组件已经停更,如:Eureak,zuul等。所以Spring Cloud Alibaba很有可能成为Spring Cloud第二代的标准实现,所以许多组件在业界逐渐开始使用,已有很多成功案例。

值得一提的是Spring Cloud Alibaba对Dubbo做了很好的兼容,同时也提供了一些强大的功能,如 Sentinel 流控 ,Seata 分布式事务,Nacos 服务发现与注册等等。

Spring Cloud Alibaba的功能

Spring Cloud Alibaba是阿里巴巴结合自身的微服务实践开源的微服务全家桶,我个人觉得其组件比Spring Cloud 中的组件更加好用和强大。并且对的Spring Cloud组件做了很好的兼容。比如在Spirng Cloud Alibaba中依然可以使用Feign作为服务调用方式,使用Eureak做服务注册发现等等。Spring Cloud Alibaba主要的功能如下:

  • 流控制和服务降级:支持WebServlet,WebFlux,OpenFeign,RestTemplate,Dubbo访问限制和降级流的功能。它可以在运行时通过控制台实时修改限制和降级流的规则,并且还支持监视限制和降级度量标准。

  • 服务注册和发现:可以注册服务,并且客户可以使用Spring托管的bean(自动集成功能区)发现实例。

  • 分布式配置:支持分布式系统中的外部配置,配置更改时自动刷新。

  • Rpc服务:扩展Spring Cloud客户端RestTemplate和OpenFeign以支持调用Dubbo RPC服务。

  • 事件驱动:支持构建与共享消息系统连接的高度可扩展的事件驱动微服务。

  • 分布式事务:支持高性能且易于使用的分布式事务解决方案。

  • 阿里云对象存储:大规模,安全,低成本,高度可靠的云存储服务。支持随时随地在任何应用程序中存储和访问任何类型的数据。

  • 阿里云SchedulerX:准确,高度可靠,高可用性的计划作业调度服务,响应时间在几秒钟内。

  • 阿里云短信:阿里云短信服务覆盖全球,提供便捷,高效,智能的通信功能,帮助企业快速联系客户。

    二.Nacos服务注册与发现

    1.Nacos认识与安装

    1.什么是Nacos

    Nacos和Eureka有着相同的能力,甚至更为强大,作为Dubbo 生态系统中重要的注册中心实现。官方对它有如下定义:

    Nacos致力于帮助您发现,配置和管理微服务。它提供了一组简单有用的功能,使您能够实现动态服务发现,服务配置,服务元数据和流量管理。 Nacos使构建,交付和管理微服务平台变得更容易,更快捷。它是通过微服务或云原生方法支持以服务为中心的现代应用程序体系结构的基础架构。

    这里我们看到Nacos不仅是服务发现组件,同时也是一个配置管理组件,也就是说它不仅可以用来取代Eureak作为注册中心, 也可以用来取代Spring Cloud Config 做配置统一管理。本篇文章意在探讨Nacos的服务注册与发现功能。

    2.Nacos服务安装

    官方提供了Nacos的服务端供我们下载使用,我们启动Nacos后将我们的微服务注册进入Nacos即可。

    下载地址:https://github.com/alibaba/nacos/releases

    启动Nacos:解压后,

    • windows执行bin目录下的startup命令 :startup.cmd -m standalone

    • linux 执行 :sh startup.sh -m standalone

      访问Nacos,端口8848:http://127.0.0.1:8848/nacos/index.html ,用户名和密码都是:nacos

      SpringCloudAlibaba,第1张

      SpringCloudAlibaba,第2张

      2.项目结构搭建

      2.1.服务调用流程

      我们这里要演示的案例是两个服务的通信,用户服务(user-server)作为服务提供者需要编写接口返回User实体对象,订单服务(order-server)作为消费者需要调用用户服务获取User实体对象,浏览器调用订单服务,订单服务调用用户服务或到User实体后返回给容器,用户和订单都注册到Nacos中,如下:

      SpringCloudAlibaba,第3张

      2.2.项目结构搭建

      父工程搭建 搭建父工程springcloudalibaba-parent并管理相关依赖,Spring boot版本为2.1.3.RELEASE,Spring Cloud 版本为Greenwich.SR1,Alibaba版本为2.1.0.RELEASE ,父工程的pom如下:

      
          
              UTF-8
              UTF-8
              1.8
              
          
         
          
               org.springframework.boot
              spring-boot-starter-parent
              2.2.5.RELEASE
          
          
          
              
                  
                      com.alibaba.cloud
                      spring-cloud-alibaba-dependencies
                      2.2.1.RELEASE
                      pom
                      import
                  
                  
                      org.springframework.cloud
                      spring-cloud-dependencies
                      Hoxton.SR3
                      pom
                      import
                  
              
          
          
              
                  junit
                  junit
                  4.12
              
          

      3.服务注册到Nacos

      3.1.导入依赖

      修改springcloudalibaba-service-user-1100导入服务发现依赖

       
           com.alibaba.cloud 
           spring-cloud-starter-alibaba-nacos-discovery
      
      
        
            org.springframework.boot
            spring-boot-starter-web
      
      3.2.主配置类

      创建配置类加上@EnableDiscoveryClient注解开启服务发现功能,代码如下

      //服务注册与发现
      @SpringBootApplication
      @EnableDiscoveryClient
      public class UserServerApplication1010 {
          public static void main(String[] args) {
              SpringApplication.run(UserServerApplication1010.class) ;
          }
      }
      3.3.配置文件

      配置文件主要配置端口,服务名,已经nacos注册中心地址

      server:
        port: 1010
      spring:
        application:
          name: user-server
        cloud:
          nacos:
            discovery:
              server-addr: 127.0.0.1:8848	#注册中心地址
      3.4.启动测试

      启动服务提供者,观察Nacos服务列表 , user-server已经注册进去了

      SpringCloudAlibaba,第4张

      4.服务通信

      服务通信可以使用Ribbon,OpenFeign,甚至Dubbo,使用方式和在SpirngCloudNetflix中没有任何区别。

      三.Nacos配置管理

      1.Nacos配置中心

      1.1.概述

      Nacos作为Spring Cloud Alibaba的一个重要组件,它不仅可以用作服务注册与发现,也可以用来替代Spring Cloud Config作为统一配置文件管理,而且他的使用更为简单和人性化。

      1.2.Nacos添加配置

      第一步:打开Nacos监控面板 - 进入配置列表 -点击 “+” 图标添加配置 如下:

      SpringCloudAlibaba,第5张

      第二步:填写Data ID,选择YAML,编辑配置文件内容

      SpringCloudAlibaba,第6张

      这里定义了一个名字为application-user-dev.yaml的配置,使用的是YAML格式。

      • Data ID : 非常重要,可以看做是配置的文件的名字,在程序中拉取配置文件的时候需要指定Data ID。

      • Group : 分组,默认是 DEFAULT_GROUP , 可以针对不同的项目指定不同的配置组。

        2.客户端接入配置中心

        2.1.导入依赖

        修改工程 springcloudalibaba-service-user-1100 ,添加配置中心依赖nacos-config,完整pom.xml如下。

         
         
                
                    com.alibaba.cloud
                    spring-cloud-starter-alibaba-nacos-config
                
                
                
                
                    com.alibaba.cloud 
                    spring-cloud-starter-alibaba-nacos-discovery
                
                
                    org.springframework.boot
                    spring-boot-starter-web
                
                
                    org.example
                    springcloudalibaba-user-common
                    1.0-SNAPSHOT
                
            
        2.2.编写Controller

        下面的Controller用来做配置刷新测试,temp.notify对应了配置文件中的配置项目。@RefreshScope注解是用来做配置自动刷新。那么当我们修改了Nacos中的配置文件,Controller中读取到的配置temp.notify将会自动变化。

        @RefreshScope  //刷新配置
        @RestController
        public class UserController {
            @Value("${temp.notify}")
            private String notify;
            @GetMapping("/user/{id}")
            public User getById(@PathVariable Long id){
                System.out.println("测试配置notify="notify);
                return new User(id,"zs:"+id, "我是zs");
            }
        }
        
        2.3.修改yml配置

        注意,将原来的配置文件修改成bootstrap.yml,然后增加如下内容:

        server:
          port: 1010
        spring:
          profiles:
            active: dev
          application:
            name: service-user
          cloud:
            nacos:
              discovery:
                server-addr: localhost:8848 #注册中心
              config:
                server-addr: localhost:8848 #配置中心
                file-extension: yaml #配置文件格式
                prefix: application-user #配置前缀 ,默认使用sring.application.name
                group: DEFAULT_GROUP #默认分组
            
        #如何查找配置文件:application-user + dev + yaml=application-user-dev.yaml 正好和Nacos配置的DataId一致
        2.4.测试

        启动Nacos,启动 springcloudalibaba-service-user 工程 , 修改Nacos中的配置文件内容,然后访问 http://localhost:1100/user/11 ,观察控制台打印的 “notify”的值会发生变化。

        四.Sentienl限流

        1.Sentinel和Hystrix

        1.1.限流和熔断

        限流 , 限制流量,这里的流量我们可以理解成请求数量,其实就是限制服务器的请求并发数量,为什么要这么做?如果不做限流,那么在大量并发请求下我们的服务器会慢慢的变慢然后顶不住压力而挂掉(类似堵车)。并不是说并发越大越好,有的时候我们的项目规模和业务决定了我们不需要那么大的并发性,当大量的并发请求访问到服务器时我们需要把部分请求拒绝在外,这个是流量限制 - 限流。

        熔断机制在在《Spring Cloud 极简入门》中有详细的解释,熔断机制是对服务调用链路的保护机制,如果链路上的某个服务不可访问,调用超时,发生异常等,服务会进行发熔断,触发降级返回托底数据。简单理解就是当服务器不可访问,可以返回一些预先准备好的兜底数据给用户,比如友好的提示信息,不至于直接向客户抛出异常。

        1.2.Hystrix的熔断和资源隔离

        Hystrix相比Sentinel来说它的线程池隔离(限流)会造成线程上下切换对资源的消耗比较大;Hystrix使用的信号量进行资源的隔离效果不错,但是无法对慢调用进行自动降级。

        1.3.Sentinel介绍

        Sentinel诞生于阿里巴巴,其主要目标是流量控制和服务熔断,2018年,Sentinel演变为一个开源项目现如今成为了Spring Cloud Alibaba的一个子项目。Sentinel是通过限制并发线程的数量来减少不稳定资源的影响,而不是使用线程池,省去了线程切换的性能开销。

        当资源的响应时间变长时,线程将开始被占用。当线程数累积到一定数量时,新的传入请求将被拒绝。反之亦然,当资源恢复并变得稳定时,占用的线程也将被释放,新请求将被接受。

        除了限制并发性外,Sentinel可以根据响应时间降级不稳定资源也是保证可靠性的有效方法。当资源的响应时间太大时,将在指定的时间窗口中拒绝所有对该资源的访问。-- 熔断机制

        此外,Sentinel支持的熔断降级维度更多,可对多种指标进行流控、熔断,且提供了实时监控和控制面板,功能更为强大。

        2.Sentinel限流实战

        2.1.Sentinel Server服务端

        Sentinel 提供了现成的服务端供我们使用,点我下载地址,下载之后通过命令行启动

        java -jar -Dserver.port=1111 sentinel-dashboard-1.6.0.jar

        访问:http://127.0.0.1:1111 进入控制台,使用 sentinel/sentinel登录。 SpringCloudAlibaba,第7张

        2.2.Sentinel 客户端接入
        1.导入依赖

        修改用户服务 springcloudalibaba-service-user ,加入sentinel依赖

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        
        2.配置Sentinel

        修改yml配置,添加senticel服务控制台地址

        spring:
          cloud:
            sentinel:
              transport:
                dashboard: localhost:1111
        3.资源限流

        Sentinel为我们提供了 @SentinelResource 注解标记需要限流的资源。 修改UserController,代码如下:

         @GetMapping("/user/{id}")
            //限流降级
            @SentinelResource(value="user",blockHandler="exceptionHandler")
            public User getById(@PathVariable Long id){
                System.out.println(notify);
                return new User(id,"zs:"+id, "我是zs");
            }
              // 限流与阻塞处理 : 参数要和 被降级的方法参数一样
            public User exceptionHandler(@PathVariable Long id, BlockException ex) {
                ex.printStackTrace();
                System.out.println("限流了...");
                return new User(-1L,"限流了","限流了");
            }

        当然,也可以通过 blockHandlerClass 属性把降级方法写在一个专门的类中,如:

        @SentinelResource(value="user",blockHandler="exceptionHandler"
        ,blockHandlerClass=ExceptionUtil.Class)

        降级类

        public final class ExceptionUtil {
            public static User exceptionHandler(Long id ,lockException ex) {
               //...
            }
        }
        2.3.Sentinel设置限流策略

        启动应用 springcloudalibaba-service-user-1100,然后通过浏览器访问 http://localhost:1100/user/11 ,然后登录Sentinel控制台,在“实时监控”列表中可以看到资源的相关监控信息的

        SpringCloudAlibaba,第8张

        在 “族点链路” 列表中可以看到资源的调用链 ,并且可以通过“流控”按钮设置流控规则

        SpringCloudAlibaba,第9张

        也可以在“流量控制”菜单中我们可以针对资源进行限流规则的设置。如下:

        SpringCloudAlibaba,第10张

        这里我添加了一个流控规则,资源名对应客户端 @SentinelResource(value="user".. 注解的资源,通过QPS限流(每秒请求数量),阈值是 1 ,意思是“user”这个资源每秒只能有1个请求进来,多余的请求会触发限流,返回降级数据。

        2.4.限流测试

        通过浏览器频发访问 “user”资源,当QPS大于1就会触发限流,效果如下:

        SpringCloudAlibaba,第11张

        3.Gateway使用Sentinel限流

        Spring Cloud Gateway 作为微服务的网关,它是微服务的访问入口,当请求的流量洪峰到来我们可以在Gateway网关层通过Sentinel对请求进行流控,把好第一道关。

        3.1.导入依赖
        
        
           com.alibaba.cloud
           spring-cloud-alibaba-sentinel-gateway
         
         	
           com.alibaba.cloud
           spring-cloud-starter-alibaba-sentinel
         
        3.2.配置Sentinel地址
        spring:
        	cloud:
              sentinel:
                  transport:
                    dashboard: localhost:1111
        3.3配置限流规则

        启动Gateway,登录sentinel控制台,对url资源进行流控限制,配置方式和前面的配置方式一样

        3.4.限流降级
        @Configuration
        public class SentinelConfig {
            public SentinelConfig(){
                GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
                    @Override
                    public Mono handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                        return ServerResponse.ok().body(Mono.just("限流啦,请求太频繁"),String.class);
                    }
                });
            }
        }

        4.Nacos存储限流规则

        在前两章节我们学习了通过Sentinel的限流和熔断机制来保护微服务,提高系统的可用性,但是有一个问题,我们在Sentinel配置了限流,熔断策略,默认情况下Sentinel的数据是基于内存存储,当客户端断开,或者Sentinel重启数据就会丢失,这不是我们愿意看到的。所有我们需要的Sentinel做数据持久。 Sentinel 中支持5种持久化的方式:file、redis、nacos、zk和apollo,本片文章针对于Nacos进行持久化配置。

        4.1.整合Nacos持久化限流规则

        第一步:导入基础依赖,springcloudalibaba-service-user-1100为例子,修改pom增加Sentinel和Nacos持久化配置依赖 sentinel-datasource-nacos ,如下:

        
            
                org.springframework.boot
                spring-boot-starter-web
            
            
                org.springframework.cloud
                spring-cloud-starter-alibaba-sentinel
            
            
            
                com.alibaba.csp
                sentinel-datasource-nacos
                1.5.2
             
        

        第二步:配置持久化nacos地址

        spring:
          application:
            name: user-server
          cloud:
            nacos:
              config: #配置中心
                server-addr: localhost:8848
                file-extension: yaml
                prefix: application-user
            sentinel:	#限流服务器sentinel配置
              transport:
                dashboard: localhost:1111
        #====================持久化配置=================================        
              datasource:
                flow:
                  nacos: #限流持久配置
                    server-addr: localhost:8848	#使用nacos的持久
                    dataId: application-user-dev	#获取限流的数据源的dataId
                    groupId: DEFAULT_GROUP
                    rule-type: flow #类型:限流
        #=====================================================            
          profiles:
            active: dev
        

        第三步:编写测试用的Controller这个controller我们待会用来做限流测试

        @RestController
           public class TempController {
              @GetMapping("/hello")
              public String hello() {
                  return "测试数据";
              }
          }
        4.2.Nacos持久化Sentinel限流规则

        第一步:在配置列表增加配置如下:

        [
            {
                "resource": "/hello",
                "limitApp": "default",
                "grade": 1,
                "count": 10,
                "strategy": 0,
                "controlBehavior": 0,
                "clusterMode": false
            }
        ]
        • resource:对那个资源进行限流

        • limitApp:这个是流控的调用者,default 代表不区分调用者

        • grade:限流方式0是根据并发数量限流,1是表根据QPS来限流

        • count:限流阈值,达到这个阈值就被限流,触发降级。

        • strategy:基于调用链的流控制策略。0 直接,1 关联 2 链路

        • controlBehavior:流控效果,0 直接拒绝,1是Warm Up,2是匀速排队

        • clusterMode:是否为集群

          上面的配置项目对应了 com.alibaba.csp.sentinel.slots.block.flow.FlowRule 限流规则类。程序启动,Sentinel通过 NacosDataSource 从Nacos中查找配置。具体效果如:

          SpringCloudAlibaba,第12张

          第二步:启动测试 ,启动springcloudalibaba-service-user-1100 ,向 /hello 资源发起访问,然后观察Sentinel控制台流控规则是否有了一条限流策略。

          SpringCloudAlibaba,第13张

          4.3.Nacos持久化Sentinel降级规则

          第一步:在Nacos配置列表增加文件 如:application-user-degrade-dev ,内容如下

          [
              {
                  "resource": "GetUserByID",
                  "grade": 0,
                  "count": 10,
                  "timeWindow": 5
              }
          ]
          • resources : 资源名

          • grade : 慢调用比例 0 ;异常比例 1 ;异常数 2;

          • count : 最大RT,最大平均响应时间

          • timeWindow :时间窗口,即熔断时长

            SpringCloudAlibaba,第14张

            第二步:项目中增加配置

            spring:
              application:
                name: service-user
              cloud:
                sentinel:
                  datasource:
                    flow: #限流的配置
                      nacos: #限流持久配置
                        server-addr: 127.0.0.1:8848	#使用nacos的持久
                        dataId: application-user-sentinal-dev	#获取限流的数据源的dataId
                        groupId: DEFAULT_GROUP
                        rule-type: flow #类型:限流
            ##==================================================================            
                    degrade: #降级的配置
                      nacos:
                        server-addr: 127.0.0.1:8848
                        dataId: application-user-degrade-dev
                        groupId: DEFAULT_GROUP
                        rule-type: degrade

            第三步:启动测试,观察sentinel的熔断规则列表

            SpringCloudAlibaba,第15张

            五.Sentinel熔断

            1.概述

            1.1.什么是熔断

            在上一章节我们探讨了Sentinel的流控(限流)功能,Sentinel除了流控还提供了服务熔断和降级机制,服务之间的调用关系错综复杂,微服务的调用链上的某些服务资源不稳定(宕机,异常,超时)可能会导致可能请求的失败和请求的堆积,调用链产生连锁反应可能会导致整个微服务架构瘫痪。服务熔断降级机制是保障高可用的重要措施之一。

            1.2.Sentinel熔断

            Sentinel的服务熔断机制会对调用链上的某个不稳定(宕机,异常,超时)的资源,做出请求限制,快速失败,避免影响到其它的服务而导致级联错误。资源熔断后,在后续的一定时间(时间窗口)之内,对该服务的请求都自动熔断,抛出 DegradeException异常。

            Sentinel拥有比Hystrix更强大和丰富的功能,能满足我们的各种应用场景,并且经历过淘宝双十一的考验,是微服务架构中熔断机制的不二选择。

            2.Sentnel熔断实战

            2.1.资源熔断降级
              	// 限流降级
                public User exceptionHandler(@PathVariable Long id, BlockException ex) {
                    ex.printStackTrace();
                    System.out.println("限流了...");
                    return new User(-1L,"限流了","限流了");
                }
                // 熔断降级,参数和返回值与源方法一致
               public User getByIdfallback(@PathVariable Long id){
                    System.out.println(notify);
                    return new User(id,"zs:"+id, "熔断托底了");
                }
                
                @GetMapping("/user/{id}")
                //限流降级
                @SentinelResource(value="user",blockHandler="exceptionHandler",fallback = "getByIdfallback")
                public User getById(@PathVariable Long id){
                    int i = 1 / 0;	//方法异常,触发熔断
                    return new User(id,"zs:"+id, "我是zs");
                }
            
            2.2.配置降级策略

            在Sentinel控制台,在族点链路菜单中找到“user”资源,然后点击“降级”按钮添加降级策略,如下:

            SpringCloudAlibaba,第16张

            2.3.测试熔断

            启动springcloudalibaba-service-user-1100工程,访问 http://localhost:1100/user/2 ,浏览器返回:

            SpringCloudAlibaba,第17张

            3.Feign整合Sentinel熔断

            Spring Cloud Alibaba是Spring Cloud的一个子项目,OpenFeign是Spring Cloud的客户端负载均衡器,使用Spring Cloud Alibaba依然可以很方便的集成OpenFeign,如果要使用OpenFeign作为服务客户端负载均衡,那么我们需要考虑OpenFeign开启Sentinel进行服务熔断降级。

            3.1.开启Sentinel

            OpenFeign与Sentinel组件集成除了引入sentinel-starter依赖关系之外,还需要在属性文件中启用Sentinel支持:feign.sentinel.enabled=true

            feign:
              sentinel:
                enabled: true #熔断
            3.2.给Feign接口降级

            这里跟Feign开启Hystrix降级一样,还是可以使用fallback属性

            @FeignClient(value = "user-server",fallback = UserClientFallback.class)
            public interface UserClient {
                @GetMapping("/user/{id}")
                User getById(@PathVariable Long id);
            }
            3.3.编写降级类
            @Component
            public class UserClientFallback implements UserClient {    
            	@Override    
            	public User getById(Long id) {        
            		return new User(-1L,"无此用户","无此用户");    
            	}
            }