Spring Cloud Alibaba学习笔记

发布时间 2023-06-14 23:03:15作者: AJun816

Spring Cloud Alibaba学习笔记

简介

Spring Cloud Alibaba 是一个分布式应用架构解决方案,它是基于 Spring Cloud 和阿里巴巴的一些组件构建的。而 Spring Cloud Alibaba 中包含了许多常用的中间件组件,下面是这些组件的用途和区别:

  1. Nacos: 用作服务注册与发现中心,包括服务的服务的注册、发现、配置等一系列的服务管理功能。与Consul/RabbitMQ/Zookeeper等功能类似,但更加轻量化,且提供了更加方便、易用的API。
  2. Sentinel: 用于熔断降级、限流请求等管理,防止底层服务层的不可控因素影响到了整个服务群体,是一个容错和健康监控的工具类。
  3. RocketMQ: 是一种分布式的、非阻塞式的消息队列服务,它主要解决异步处理和流量削峰的问题,是分布式异步消息通信的重要组件。
  4. Dubbo: 是一种高性能的服务框架,主要用于提供分布式应用中的各种RPC服务,特别是在高并发大数据处理中具有重要的作用。
  5. Seata: 是阿里巴巴开源的一种分布式事务解决方案,用于解决分布式事务的问题,保证了数据的一致性和事务的可靠性。
  6. Alibaba Cloud OSS: 是阿里云对象存储服务,用于存储不同类型的对象,包括文件、图片、视频等多种类型的数据。

服务间通信

seatra rockermq dubbo 的区别

Seata、RocketMQ和Dubbo都是一些用于服务间通信的中间件组件,但它们的主要作用和特点有所不同:

  1. Seata主要致力于解决业务应用中面临的分布式事务问题,能够保证数据的一致性和服务的可靠性。Seata依赖于底层数据存储,为整个分布式系统提供一个高效稳定的分布式的事务管理机制。
  2. RocketMQ是一种分布式消息服务,主要用于异步消息的传递和处理。RocketMQ具有高性能、高可用性、消息可靠性强等优点,可以在分布式环境下保证消息的及时处理和可靠性。
  3. Dubbo是一个高性能的服务框架,主要用于提供分布式应用中的各种RPC服务,因此采用的通信协议是基于TCP的。Dubbo的主要作用是提供分布式服务的注册、发现、负载均衡和容错等功能,主要解决的问题是分布式系统中的服务治理。

尽管这些中间件组件都被用于服务间通信,但是它们的定位和功能略有不同,可以根据实际应用场景选择相应的中间件来进行服务间通信。例如,如果应用领域中有大量的事务、需要长时间持续地交互、要求保证数据的一致性和可靠性,使用Seata是比较明智的;如果应用领域中有大量的消息处理需求、对消息的准确传递和处理有着较为严格的要求,使用RocketMQ是比较明智的;如果需要较高的性能、需要对集群的自动化管理、需要微服务系统中的服务治理等,使用Dubbo是比较明智的选择。

具体的使用场景和区别

Seata

Seata主要用于解决分布式业务场景中的事务问题,它可以提供类似于本地事务的方式来进行多个服务之间的事务处理,确保数据的一致性和服务的可靠性。建议在分布式事务处理方面使用Seata,例如金融、电商等需要依赖于大量事务处理的场景。

RocketMQ

RocketMQ主要用于异步消息的传递和处理,类似于消息中间件。它可以在分布式环境下保证消息的及时处理和可靠性,并且RocketMQ提供了多种消息传递模式,可以根据业务需求进行选择。建议在分布式异步消息处理方面使用RocketMQ,例如App推送、支付通知等需要异步消息处理的场景。

Dubbo

Dubbo是一种高性能的服务框架,主要用于提供分布式应用中的各种RPC服务。Dubbo提供了服务治理功能,例如服务的注册、发现、路由、负载均衡和容错等功能,可以提供高可用的分布式服务。建议在需要进行服务逻辑可拆分,或者存在很多交互的情况下使用Dubbo,例如电商网站会员、购物车等应用中需要RPC服务的场景。
综上所述,最终选择使用Seata、RocketMQ或Dubbo还是要根据具体的业务需求来进行决策。具体应用场景需要根据需求而定,比如需要强一致性,选择Seata;需要异步消息处理,选择RocketMQ;需要RPC服务和服务治理,选择Dubbo。当然,在实际应用中,也可以根据需要同时使用多种中间件组合来达到更好的效果。

技术选型

Spring Cloud Stream、RabbitMQ、RocketMQ、Seata 均为微服务的相关框架或工具,但每个工具的使用场景和特点不同,需要根据具体情况进行选择。下面是它们的区别和选择建议:

  1. Spring Cloud Stream:
    • Spring Cloud Stream 是 Spring Cloud 的一部分,它提供一种用于构建消息驱动型微服务的框架,可以让开发者不用关心细节,只需关心数据处理,将数据处理和消息转换解耦。
    • Spring Cloud Stream 可以使用多个消息中间件系统来传递消息,包括 RabbitMQ、Kafka、Apache RocketMQ 等等。
    • 使用 Spring Cloud Stream 可以方便的配置消息通道,同时支持云原生场景下的流式处理和事件驱动架构。
    • 建议在 Spring Cloud 环境下,或需要快速搭建消息通道的业务场景中使用 Spring Cloud Stream。
  2. RabbitMQ:
    • RabbitMQ 是一款开源的基于 AMQP(高级消息队列协议)的消息中间件,支持广泛的编程语言和运行环境。
    • RabbitMQ 提供了可靠的消息传递机制、灵活的路由策略、丰富的插件机制、高效的消息持久化等特点。
    • RabbitMQ 的使用比较简单,可以提供多种编程语言的客户端支持。
    • 建议在需要高性能和高可靠性的业务场景中使用 RabbitMQ。
  3. Apache RocketMQ:
    • Apache RocketMQ 是阿里巴巴开源的一款分布式消息中间件,具有高性能、高吞吐量、可靠性强等特点。
    • RocketMQ 延迟消息、事务消息、批量消息等特性较为突出。
    • RocketMQ 已经被广泛应用于阿里集团各大 BU 系统中,并且被大量企业作为可靠的消息中间件进行部署。
    • 建议在以阿里系产品为主要技术栈或希望使用开源的消息中间件中使用 RocketMQ。
  4. Seata:
    • Seata 是一款开源的分布式事务解决方案,提供高性能和高可靠性。
    • Seata 可以与 Spring Cloud、Dubbo、RocketMQ 等多个场景进行良好的兼容。
    • Seata 提供了全局事务管理、幂等性等机制,可以很好的保证分布式事务的数据一致性。
    • 建议在需要保证分布式事务一致性的业务场景中使用 Seata。

至于为什么没有使用 Spring Cloud Alibaba 自带的 RocketMQ 是因为,虽然 Spring Cloud Alibaba 对 RocketMQ 进行了深度集成,但是在使用过程中会有一定的限制。比如默认情况下只能使用集群模式,不能使用广播模式;配置也比较复杂,需要在多个配置文件中进行配置。因此,针对具体的业务场景和需求,选择合适的消息中间件或事务解决方案是比较重要的。

示例1

场景描述:500部手机,安装一个gpsApp,这个app只有一个功能就是获取用户当前的gps位置信息,每30秒向服务器发送一次请求,服务器接收到以后将其保存在mongodb数据库中。

  1. 首先使用 Spring Cloud Alibaba 提供的 Nacos 作为服务发现和注册中心、使用 Spring Data MongoDB 作为数据库,同时使用 Spring Scheduling 创建定时任务来实现手机 GPS 位置信息的收集。具体实现步骤如下:

    1. 在应用中使用 Spring Cloud Alibaba Nacos 客户端,将手机 GPS 位置信息作为一个 POST 请求发送到指定的服务中心。

    2. 在服务端接收到手机 GPS 位置信息之后,使用 Spring Data MongoDB 将其保存到 MongoDB 数据库中。具体的流程如下:

      • 创建 MongoDB 配置类,配置数据库信息、操作模式(单机或者集群)、数据库集合名称等信息。
      javaCopy code@Configuration
      public class MongoConfig {
          // mongodb 连接的相关配置信息
          @Value("${spring.data.mongodb.host}")
          private String host;
          @Value("${spring.data.mongodb.port}")
          private Integer port;
          @Value("${spring.data.mongodb.database}")
          private String database;
          @Value("${spring.data.mongodb.uri}")
          private String uri;
          // 使用 URI 创建 MongoClient 连接数据库
          @Bean
          public MongoClient mongo() {
              return new MongoClient(new MongoClientURI(uri));
          }
          // 创建具体的 MongoTemplate 模板对象,用来对数据库进行操作
          @Bean
          public MongoTemplate mongoTemplate() {
              return new MongoTemplate(mongo(), database);
          }
      }
      
      • 在服务端接口中使用 @PostMapping 注解来接收手机 GPS 位置信息,并将其保存到 MongoDB 数据库中。
      javaCopy code@RestController
      public class GpsDataController {
          @Autowired
          private MongoTemplate mongoTemplate;
          // 接收手机 GPS 位置信息,并将其保存到 MongoDB 数据库中
          @PostMapping("/gpsData")
          public void saveGpsData(@RequestBody GpsData gpsData) {
              mongoTemplate.save(gpsData);
          }
      }
      
    3. 在应用中使用 Spring Scheduling 创建一个后台任务,每30秒钟向服务端发送一次手机 GPS 位置信息。具体流程如下:

      • 创建一个定时任务类,在该类中使用 RestTemplate 发送 POST 请求来接收客户端发送的手机 GPS 位置信息。
      javaCopy code@Component
      public class GpsDataSender {
          @Value("${server.url}")
          private String serverUrl; // 服务端的 URL
          @Scheduled(fixedDelay = 30000)
          public void sendGpsData() {
              // 构造请求体
              GpsData gpsData = new GpsData();
              // 获取手机 GPS 位置信息
              // ...
              // 发送 POST 请求
              RestTemplate restTemplate = new RestTemplate();
              String result = restTemplate.postForObject(serverUrl + "/gpsData",
                      gpsData, String.class);
              System.out.println(result);
          }
      }
      
      • 创建一个 GpsData 类来保存手机 GPS 位置信息,该类需要实现 Serializable 接口。
      javaCopy code// GpsData 类用来保存手机 GPS 位置信息
      public class GpsData implements Serializable {
          private String userId;
          private Double longitude;
          private Double latitude;
          private Date createTime;
          // getter 和 setter 方法
          // ...
      }
      
      • 在服务端配置文件中,设置 MongoDB 数据库的相关信息、Spring Boot 的监听端口等信息。
      yamlCopy code# MongoDB 数据库的配置
      spring:
        data:
          mongodb:
            host: 127.0.0.1
            port: 27017
            database: test
            uri: mongodb://127.0.0.1:27017/test
      # 配置服务端口号
      server:
        port: 8080
      

    在上面的实现过程中,需要将客户端和服务端的 URL 通过配置文件统一管理,这样方便在不同环境中部署服务时进行配置。

示例2

使用 Spring Cloud Alibaba 提供的 Nacos 作为服务发现和注册中心、使用 Spring Data MongoDB 作为数据库,同时使用 Spring Cloud Stream 将微服务之间的数据同步。具体实现步骤如下:

  1. 在应用中使用 Spring Cloud Alibaba Nacos 客户端,将微服务注册到指定服务中心。

  2. 在微服务中使用 Spring Cloud Stream 将数据同步到人员管理业务微服务中,具体流程如下:

    • 添加 spring-cloud-starter-stream-rabbit 依赖。
    xmlCopy code<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
    </dependency>
    
    • application.yml 文件中添加 RabbitMQ 的配置。
    yamlCopy codespring:
      cloud:
        stream:
          rabbit:
            bindings:
              发送消息到人员管理业务微服务的微服务名称-binding:
                destination: 发送消息到人员管理业务微服务的微服务名称
    
    • 在需要同步数据的微服务中,使用 @EnableBinding 注解来绑定消息通道,并通过 @Output 注解来指定输出通道。
    javaCopy code@EnableBinding(Source.class)
    public class ProjectService {
        private final MessageChannel output;
        public ProjectService(Source source) {
            this.output = source.output();
        }
        // 将更新的数据通过 output 输出通道发送到人员管理业务微服务
        public void updateProject(Project project) {
            output.send(MessageBuilder.withPayload(project).build());
        }
    }
    
    • 在人员管理业务微服务中,使用 @EnableBinding 注解来绑定消息通道,并通过 @Input 注解来指定输入通道。使用 @StreamListener 注解将接收到的数据存入 MongoDB 数据库。
    javaCopy code@EnableBinding(Sink.class)
    public class PersonnelService {
        private final MongoTemplate mongoTemplate;
        public PersonnelService(MongoTemplate mongoTemplate) {
            this.mongoTemplate = mongoTemplate;
        }
        @StreamListener(Sink.INPUT)
        public void saveProject(Project project) {
            mongoTemplate.save(project);
            // 进行聚合查询...
        }
    }
    
  3. 在数据实体类上使用 @Document 注解来指定 MongoDB 的集合名称、使用 @Id 注解指定主键,具体流程如下:

    javaCopy code@Document(collection = "project")   // 指定 MongoDB 的集合名称
    public class Project {
        @Id
        private String projectId;   // 指定主键
        private String projectName;
        private String projectManager;
        private String projectAddress;
        // getter 和 setter 方法
        // ...
    }
    
  4. 在人员管理业务微服务中,使用 Spring Data MongoDB 进行数据的聚合查询。

    javaCopy codepublic List<Project> getProjectListByProjectManager(String projectManager) {
        MatchOperation match = Aggregation.match(Criteria.where("projectManager").is(projectManager));
        GroupOperation group = Aggregation.group("projectId").first("projectId").as("projectId")
                                       .first("projectName").as("projectName")
                                       .first("projectManager").as("projectManager")
                                       .first("projectAddress").as("projectAddress");
        Aggregation aggregation = Aggregation.newAggregation(match, group);
        return mongoTemplate.aggregate(aggregation, "project", Project.class).getMappedResults();
    }
    

在上面的实现过程中,需要将各微服务的 RabbitMQ 配置和 MongoDB 的配置通过配置文件统一管理,这样可以方便在不同环境中部署服务时进行配置,同时也方便维护。