Spring Cloud Alibaba-(7)RocketMQ【分布式消息队列】

Spring Cloud Alibaba-(1)搭建项目环境

Spring Cloud Alibaba-(2)Nacos【服务注册与发现、配置管理】

Spring Cloud Alibaba-(3)OpenFeign【服务调用】

Spring Cloud Alibaba-(4)Sentinel【流控和降级】

Spring Cloud Alibaba-(5)Seata【分布式事务】

Spring Cloud Alibaba-(6)Spring Cloud Gateway【网关】

Spring Cloud Alibaba-(7)RocketMQ【分布式消息队列】

1.RocketMQ 官网-https://rocketmq.apache.org/zh/

RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。具有以下特点

(1)能够保证严格的消息顺序;

(2)提供丰富的消息拉取模式;

(3)高效的订阅者水平扩展能力;

(4)实时的消息订阅机制;

(5)亿级消息堆积能力。

2.RocketMQ 原理

3.RocketMQ 服务端

3.1 下载 (如果5.1.4版本报错,请下载最新版本

3.2 修改 runbroker.cmd 和 runserver.cmd

3.3 创建ROCKETMQ_HOME环境变量。然后再bin目录新建 startup.bat 文件运行 mqnamesrv.cmd 和 mqbroker.cmd,从而启动RocketMQ服务

@echo off
setlocal

# 获取当前脚本的目录
set "scriptDir=%~dp0"

# 启动 NameServer
echo Starting NameServer...
start "NameServer" "%scriptDir%mqnamesrv.cmd" start
echo NameServer has been started.

# 启动 Broker
# -n 表示 NameServer 地址
# autoCreateTopicEnable=true 表示 Broker开启自动创建Topic,否则报错 No route info of this topic
echo Starting Broker...
start "Broker" "%scriptDir%mqbroker.cmd" start -n localhost:9876 autoCreateTopicEnable=true
echo Broker has been started.

endlocal

4.RocketMQ 控制台

4.1 下载(apache/rocketmq-dashboard

4.2 IDEA 打开源码,跳过测试,然后打成 jar 包(源码使用jdk8

4.3 运行RocketMQ DashBoard(cmd 运行 java -Dserver.port=8899 -jar rocketmq-dashboard-1.0.1-SNAPSHOT.jar

4.4 访问RocketMQ控制台-http://localhost:8899/

5.项目中使用 RocketMQ

5.1 订单微服务生产并发送消息(生产者)

5.1.1 引入 Maven 依赖

<!-- rocketmq -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.3.1</version>
</dependency>

<!-- rocketmq-client -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>5.1.4</version>
</dependency>

5.1.2 bootstrap.yml 配置 rocketmq

server:
  port: 8000

spring:
  profiles:
    active: public
  application:
    name: order-service
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud2024
    username: root
    password: 123456
  cloud:
    nacos:
      discovery:
        server-addr: http://localhost:8848
      config:
        server-addr: http://localhost:8848
        file-extension: yaml
        namespace: public
        shared-configs:
          - data-id: order-service-default.yaml
            refresh: true
          - data-id: order-service-default-test.yaml
            refresh: true
    openfeign:
      httpclient:
        # 连接超时
        connection-timeout: 5000
    sentinel:
      transport:
        dashboard: http://localhost:8858
      datasource:
        flow-rule:
          nacos:
            server-addr: http://localhost:8848
            data-id: order-service-flow-rule
            rule-type: flow

# Openfeign 整合 sentinel
feign:
  sentinel:
    enabled: true

#
#logging:
#  level:
#    com.dragon.openfeign: debug

seata:
  registry:
    type: nacos
    nacos:
      server-addr: http://localhost:8848
      application: seata-server
      group: SEATA_GROUP
  config:
    type: nacos
    nacos:
      server-addr: http://localhost:8848
      group: SEATA_GROUP
  tx-service-group: default_tx_group


rocketmq:
  name-server: http://localhost:9876   # RocketMQ 服务地址
  producer:
    group: order  # 生产者组

5.1.3 订单微服务下单操作使用 RocketMQTemplate 发送消息

package com.dragon.service.impl;

import cn.dev33.satoken.util.SaResult;
import com.alibaba.fastjson.JSONObject;
import com.dragon.entity.Orders;
import com.dragon.entity.Product;
import com.dragon.mapper.OrdersMapper;
import com.dragon.openfeign.ProductServiceFeign;
import com.dragon.service.IOrdersService;
import com.github.yulichang.base.MPJBaseServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;


@Service
public class OrdersServiceImpl extends MPJBaseServiceImpl<OrdersMapper, Orders> implements IOrdersService {
    @Qualifier("com.dragon.openfeign.ProductServiceFeign")
    @Autowired
    private ProductServiceFeign productServiceFeign;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @GlobalTransactional
    @Override
    public synchronized SaResult add(String productId){
        Object obj = productServiceFeign.getById(productId).getData();

        // 将 Object 转为 JSONString
        String str = JSONObject.toJSONString(obj);
        // 将 JSONString 转为 .class
        Product product = JSONObject.parseObject(str, Product.class);

        product.setStock(product.getStock()-1);
        productServiceFeign.saveOrUpdate(product);

        Orders order=new Orders();
        order.setUserId("1");
        order.setProductId(productId);
        order.setAmount(1);
        order.setPrice(product.getSellPrice());
        order.setCreateTime(LocalDateTime.now());
        order.setTs(LocalDateTime.now());
        this.saveOrUpdate(order);

//        // 模拟出现异常
//        int i=1/0;

        // 向 RocketMQ 的 order-topic 主题发送消息
        rocketMQTemplate.convertAndSend("order-topic",order);

        return SaResult.ok();
    }
}

5.1.4 RocketMQ 控制台查看消息

5.2 用户微服务订阅并消费消息(消费者)

5.2.1 引入 Maven 依赖

<!-- nacos-discovery 服务注册与发现 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- rocketmq -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.3.1</version>
</dependency>

<!-- rocketmq-client -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>5.3.0</version>
</dependency>

5.2.2 bootstrap.yml 配置

server:
  port: 8300

spring:
  application:
    name: user-service
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud2024
    username: root
    password: 123456
  cloud:
    nacos:
      discovery:
        server-addr: http://localhost:8848

rocketmq:
  name-server: http://localhost:9876

5.2.3 用户微服务接收RocketMQ消息,并模拟发送一条短信

5.2.3.1 定义接口,接收消息
package com.dragon.service;

import com.dragon.entity.Orders;
import org.apache.rocketmq.spring.core.RocketMQListener;

// String 是 RocketMQ 消息的类型
public interface SmsService extends RocketMQListener<String> {
}
5.2.3.2 实现接口,消费消息
package com.dragon.service.impl;


import com.alibaba.fastjson2.JSON;
import com.dragon.entity.Orders;
import com.dragon.service.SmsService;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.springframework.stereotype.Service;

@Service
@RocketMQMessageListener(
        consumerGroup = "user-group",           // 消费者组
        topic = "order-topic",                  // 主题
        consumeMode = ConsumeMode.CONCURRENTLY, // 消费模式,CONCURRENTLY(同步消费,默认),ORDERLY(顺序消费)
        messageModel = MessageModel.CLUSTERING  // 消息模式,CLUSTERING(集群消息,默认),BROADCASTING(广播消息)
)
public class SmsServiceImpl implements SmsService {
    @Override
    public void onMessage(String msg) {
        // 将字符串转为对象类型
        Orders orders= JSON.parseObject(msg,Orders.class);
        System.out.println("订单消息,"+orders);
        System.out.println("接收到了一个订单信息,可以编写消费逻辑,发送一条短信");
    }
}

6.RocketMQ 消息类型

6.1 普通消息(Normal Message)

(1)描述:普通消息是最基本的消息类型,没有特殊的语义约束,消息之间也没有任何关联。

(2)特点:

  1. 生产者将消息发送到 Broker,消费者从 Broker 订阅并消费这些消息。
  2. 没有顺序约束,生产和消费都是并行进行的。
  3. 单机性能可以达到十万级别的 TPS(每秒事务处理量)。

(3)发送方式:

        1. 单向发送:生产者发送消息后不关心 Broker 是否接收,这种方式最快但可靠性最低。

        2. 异步发送:生产者发送消息后立即返回,不等待 Broker 确认,这种方式速度快但可靠性较差。

        3. 同步发送:生产者发送消息后等待 Broker 返回确认,这种方式最可靠但也最慢。

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    // 普通消息
    public void test() throws InterruptedException {
        // 普通消息:单向消息
        // 参数:主题,消息体
        rocketMQTemplate.sendOneWay("order-topic","单向消息");

        // 普通消息:同步消息
        // 参数:主题,消息体,超时时间
        rocketMQTemplate.syncSend("order-topic:tag","同步消息",5000);

        // 普通消息:异步消息
        // 参数:主题,消息体,回调
        rocketMQTemplate.asyncSend("order-topic:tag","异步消息",new SendCallback() {
            // 成功回调
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println(sendResult);
            }
            // 失败回调
            @Override
            public void onException(Throwable throwable) {
                System.out.println(throwable);
            }
        });

        // 休眠,保证异步消息可以回调
        Thread.sleep(900000000);
    }

6.2 顺序消息(Orderly Message)

(1)描述:顺序消息保证消息按照发送的顺序进行消费。

(2)类型

        1. 分区有序消息(Partition Orderly Message):消息在同一个队列(Queue)内按照顺序消费。

        2. 全局有序消息(Global Orderly Message):整个 Topic 内的消息按照顺序消费。

(3)实现机制

        1. 分区有序消息通过消息 Key 来实现,同一 Key 的消息会被分配到同一个队列中。

        2. 全局有序消息需要将消息发送到一个队列中,然后由消费者按照顺序消费。

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    // 顺序消息
    public void test1() throws InterruptedException {
        // 顺序消息:单向消息
        // 参数:主题,消息体,hashKey(同一个hashKey的消息会分配到同一个队列)
        rocketMQTemplate.sendOneWayOrderly("order-topic","单向消息","11");

        // 顺序消息:同步消息
        // 参数:主题,消息体,hashKey(同一个hashKey的消息会分配到同一个队列)
        rocketMQTemplate.syncSendOrderly("order-topic:tag","同步消息","22");

        // 顺序消息:异步消息
        // 参数:主题,消息体,hashKey(同一个hashKey的消息会分配到同一个队列),回调
        rocketMQTemplate.asyncSendOrderly("order-topic:tag","异步消息","33",new SendCallback() {
            // 成功回调
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println(sendResult);
            }
            // 失败回调
            @Override
            public void onException(Throwable throwable) {
                System.out.println(throwable);
            }
        });

        // 休眠,保证异步消息可以回调
        Thread.sleep(900000000);
    }

6.3 延时消息(Delay Message)

(1)描述:延时消息是指消息发送到 Broker 后,在指定的延迟时间之后才会被消费者消费。

(2)应用场景:常用于实现订单超时取消、定时任务等场景。

(3)实现机制:生产者发送消息时可以指定消息的延迟级别,Broker 根据级别计算延迟时间,并在延迟时间过后将消息发布给消费者。

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    // 延时消息
    public void test2(){
        // 参数:主题,消息体,延时时间
        rocketMQTemplate.syncSendDelayTimeSeconds("order-topic","单向消息",1);
    }

6.4 事务消息(Transaction Message)

(1)描述:事务消息主要用于解决分布式事务问题,保证消息的发送与本地事务的一致性。

(2)应用场景:当需要保证消息的发送与本地事务(如数据库操作)的一致性时使用。

(3)实现机制

        1. 生产者发送半消息(Half Message)到 Broker,不立即确认发送。

        2. 生产者根据本地事务的结果提交(Commit)或回滚(Rollback)事务消息。

        3. Broker 根据事务状态决定是否将消息发送给消费者。

`spring-cloud-alibaba-dependencies`是一个Maven BOM(Bill of Materials),包含了Spring Cloud Alibaba的所有依赖版本。通过引入`spring-cloud-alibaba-dependencies`,可以简化Spring Cloud Alibaba项目的依赖管理。它提供了以下依赖: - `spring-cloud-alibaba-dependencies`:Spring Cloud Alibaba版本管理器 - `spring-cloud-starter-alibaba-nacos-discovery`:Nacos服务发现 - `spring-cloud-starter-alibaba-nacos-config`:Nacos配置中心 - `spring-cloud-starter-alibaba-sentinel`:Sentinel限流熔断 - `spring-cloud-starter-alibaba-seata`:Seata分布式事务 - `spring-cloud-starter-alibaba-rocketmq`:RocketMQ消息队列 - `spring-cloud-starter-alibaba-dubbo`:Dubbo远程调用 使用`spring-cloud-alibaba-dependencies`需要在`pom.xml`文件中引入如下配置: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` 引入该依赖后,其他Spring Cloud Alibaba组件的依赖版本就可以省略了。例如,使用Nacos作为服务发现和配置中心,只需要引入以下依赖: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> ``` Spring Cloud Alibaba会自动使用`spring-cloud-alibaba-dependencies`中定义的版本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值