CloudAlibabaRocketMQ-合理化非同期-7

非同期な

对于一些比较耗时的操作.可以将他们 以 异步的方式实现. 完成后在通知调用者

春の非同期メソッドの実装

ここに画像を挿入説明

除了这三种.还有一种基于MQ消息队列的方式实现异步
这里的异步.可以使Service层实现异步. 也可以是Controller层实现异步

MQアーキテクチャ

ここに画像を挿入説明

MQアプリケーションシナリオ

1. 异步处理
2. 流量消峰填谷
3. 解耦微服务

MQの選択

ノート
ケース

ビルドMQ

注釈

モード

1. 单Master模式
2. 多Master模式
3. ... ...

リファレンスアドレス

RocketMQ 包含NameServer和Broker模式

ビルドRocketMQコンソール

基于SpringBoot的控制台

注釈

ロケット用語の概念

ここに画像を挿入説明

高度なロケット

适用Spring编程模型进行消息驱动的微服务.可以使用各种MQ.比如:kafka,ActiveMQ

RocketMQ開発ガイド

春のニュースプログラミングモデル - プロデューサー

1. ➕依赖
<dependency>
	<groupId>org.apache.rocketmq</groupId>
	<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
2. 写配置
rocketmq:
  name-server: 127.0.0.1:9876
  producer:
    # 小坑,必须指定group
  group: test-group
3. 适用RocketMQ
@Autowrited
private RocketMQTemplate rocketMQTemplate;
4. 发送消息到RocketMQ
rocketMQTemplate.convertAndSend(
	UserAddBoundMsgDTO.builder()
	.userId(share.getUserId())
	.bonus(50)
	.build(0);
)

ここに画像を挿入説明
总结:

想要使用 各种MQ在Spring中进行编程的话. 可以这么使用:SpringBoot整合了各种各样的MQ:

ここに画像を挿入説明

消費者の書き込みRocketMQ

1. 实现RocketMQListener<T>:T为消息体. 生产者传递的消息体
2. 实现 onMessage(T t):
	当有消息来临的时候 进行处理的逻辑
3. 在实现类上,添加@Service: 将此类交给Spring管理
	添加@RocketMessageListener(consumerGroup = "test-group", topic = "add-bonus")
	add-bonus: 此处的add-bonus需要和生产者的数据一致
	cnsumerGroup: 消费者的Group. 
	生产者Group配置在yml文件.  消费者Group配置在注解中

ここに画像を挿入説明

分散トランザクション01

问题:

在Service层添加 @Transaction(rollbackFor = Exception.class)
如果发生Exception异常.数据库操作就回滚.

ここに画像を挿入説明

但是,在第四步,将数据写入缓存中发生了异常. 这时,数据库操作会回滚. 而MQ消息已经发送了. 导致用户积分
还是会增加.

导致审核没有成功,用户却增加了积分的情况.

Transactionメッセージ

RocketMQ提供事务消息.

ここに画像を挿入説明

1. RocketMQ发送半消息	
2. 消息存储到MQServer内. 但是不能投递. 消费者不会接触阵容调休息.
3. 生产者执行本地事务. 
4. 生产者执行成果. 发送二次确认请求. 如果该请求将该请求标记为Commit. 消费者会接触到该请求
5. 如果接收到的是rollback,就将这条消息删除掉.
6. 如果长时间,半消息 为 未消费状态. 就去查询本地事务状态.
7. 生产者根据本地事务执行结果.

简单来说,就是一条消息由生产者发送.等待生产者执行本地事务. 如果本地事务执行成功的话.再消费这条消息

分散メッセージステータス

ここに画像を挿入説明

分散トランザクションのコーディング

1.送信メッセージの半分

新增表:

ここに画像を挿入説明

コール取引メッセージ方法

rocketMQTemplate.sendMessageTransaction()
... ...

sendMssageTransaction:源码:

public TransactionSendResult sendMessageInTransaction(String txProducerGroup, String destination, Message<?> message, Object arg) throws MessagingException {
        try {
            TransactionMQProducer txProducer = this.stageMQProducer(txProducerGroup);
            org.apache.rocketmq.common.message.Message rocketMsg = RocketMQUtil.convertToRocketMessage(this.objectMapper, this.charset, destination, message);
            return txProducer.sendMessageInTransaction(rocketMsg, arg);
        } catch (MQClientException var7) {
            throw RocketMQUtil.convert(var7);
        }
    }

ここに画像を挿入説明

消息体: 还可以设置头部信息.例如 Header中存储TransactionID ==> UUID.randomUUID().toString();

ここに画像を挿入説明

RocketMQLocalTransactionListenerを達成

@Slf4j
@RocketMQTransactionListener(txProducerGroup = "tx-add-bonus-group")
public class MyRocketTransaction implements RocketMQLocalTransactionListener {
    /**
     * 执行本地事务
     * @param message
     * @param o
     * @return
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
        return null;
    }

    /**
     * 本地事务检查方法
     * 检查本地事务是否执行成功
     * @param message
     * @return
     */
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
        return null;
    }
}
注解上的 txProducerGroup 的值,需要和 调用发送 事务型消息方法 中参数一致的值.

ここに画像を挿入説明
实现逻辑:

这里的逻辑大部分是 自己业务的逻辑. 需要调用的 RocketMQ 的API 的是,自己业务验证完毕.需要对事务型消息进行COMMIT或ROLLBACK.

ここに画像を挿入説明

这里的 RocketMQLocalTransactionState.COMMIT. 便是对 事务型消息提交. 确认,更改标记. 可被消费者消费
在catch中还有 ROLLBACK

春のクラウドストリーム

提供了更为通用操作MQ的方法. 用于构建消息驱动的微服务框架.

ここに画像を挿入説明

框架,Binder整合了Rocket,Rabbit各种MQ操作.

ストリームプログラミングモデル

ここに画像を挿入説明

1. Destination Binder: 目标绑定器.: 与消息中间件通信的组件
2. Destination Bindings: 目标绑定
	2.1 Binding是连接应用程序和消息中间件的桥梁.用于消息的消费和生产. 由binder创建
3. Message: 消息

上图:

微服务集成了 Stream. Stream的Application创建了俩个Binging. 左边的Binding连接了
RabbitMQ. 右边的Binding连接了Kafka.
左边的RabbitMQ是Input. 右边的Kafka是Output
Input:微服务接收消息.
Output:微服务发送消息
图中的细致代码:

ここに画像を挿入説明

ストリーム:プロデューサー

1. ➕依赖:

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>

2. 写注解:

@EnableBinding(Source.class)
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = UserCenterFeignConfiguration.class)
public class UserCenterApplication {

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

	@Bean
	@LoadBalanced
	public RestTemplate restTemplate(){
		return new RestTemplate();
	}

}
@EnableBinding(Source.class) :在启动类上添加此注解

3. 写配置:

spring:
	cloud:
		stream:
			rocketmq:
				binder:
					name-server: 127.0.0.1:9876
			bindings:
				output:
					# 用来指定topic
					destination: stream-test-topic

ストリームメッセージを送ります

@Autowired
private Source source;

@GetMapping("/test-stream")
public String sendStream(){
   source.output().send(
           MessageBuilder.
                   withPayload("消息体").
                   build()
   );
   return "success";
}

ストリーム:消費者

为用户中心整合Stream

1. ➕依赖
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
2. 写注解
@EnableBinding(Sink.class)
@SpringBootApplication
public class UserServiceApplication {

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

}
3. 写配置
spring:
	cloud:
		stream:
			rocketmq:
				binder:
					name-server: 127.0.0.1:9876
			bindings:
				output:
					# 用来指定topic
					destination: stream-test-topic
					# 一定要设置,要不应用不能启动.
					# 使用RocketMQ必须要设置.其他MQ可留空
					group: binder-group
4. 写代码
@Slf4j
@Service
public class TestStreamConsumer {

    @StreamListener(Sink.INPUT)
    public void receive(String messageBody){
        log.info("通过Stream收到消息了,收到的messageBody = 为:{}",messageBody);
    }

}

ストリーム:カスタムインターフェース - 生産メッセージ

public interface MySource {

    String MY_OUTPUT = "my-out-put";

    @Output(MY_OUTPUT)
    MessageChannel output();

}

使用:

@Autowired
    private MySource mySource;

    @GetMapping("/test-customer-interface")
    public void testCustomerInterface(){
        mySource.output().send(
          MessageBuilder
          .withPayload("自定义接口信息")
          .build()
        );
    }
使用起来跟之前的Source的使用方法一致
这里在学习时,mybatis报了一个错.原因是因为: mybatis将这个接口也扫描到了.但是这个接口并不是Mybatis的配置类
修改 mybatis扫描包即可

ストリーム:カスタムインターフェース - 消費者ニュース

1. 创建接口
public interface MySink {

    String MY_SINK = "my_input";

    @Input(MY_SINK)
    SubscribableChannel input();

}

自定义servier

@Slf4j
@Service
public class MyTestCustomerStream {

    @StreamListener(MySink.MY_SINK)
    public void receive(String messageBody){
        log.info("自定义接口消费:通过stream收到了消息:messageBody = {}",messageBody);
    }

}

ルックを超えました

ここに画像を挿入説明

Source,Sink Spring提供的接口.和我们写的自定义接口,MySource和MySink. 本质是一样的. 而 Processor接口是
能生产,能够消费的接口.
而yml文件的配置:其中有俩个属性和我们自定义的属性是一致的
cloud:
    stream:
      rocketmq:
        binder:
          name-server: 127.0.0.1:9876
        bindings:
          input:
            destination: stream-test-topic
            group: binder-group
          my-input:
            destination: stream-my-topic
            group: my-group
配置中的my-input和代码中的
public interface MySink {

    String MY_SINK = "my-input";

    @Input(MY_SINK)
    SubscribableChannel input();

}
是一致的.这是因为 Spring 使用IOC技术. 在启动类上书写 MySource.class 和 MySink.class .
会根据IOC创建 名为: my-input 和 my-output 的代理对象

メッセージのフィルタリング

注釈

消费者消费消息 某种条件消费. 

CloudStream監視

SpringBoo-actuator

以actuator进行监控.

ここに画像を挿入説明

CloudStream例外処理

注釈

错误处理:
	应用处理		系统处理

+ RocketMQ復興CloudStreamプロデューサー

// TODO 未学习

CloudStream + RocketMQ復興消費者

// TODO 未学习
公開された36元の記事 ウォンの賞賛1 ビュー50000 +

おすすめ

転載: blog.csdn.net/DXH9701/article/details/103956598