Docker安装
docker run -d --restart=always --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.10-management
界面地址: 地址:15672
默认登录账户和密码 guest
交换机类型
- Direct Exchange
直连型交换机,根据消息携带的路由键将消息投递给对应队列。
列绑定到一个直连交换机上,同时赋予一个路由键 routing key
- Fanout Exchange
扇型(广播)交换机,这个交换机没有路由键概念,就算你绑了路由键也是无视的。 这个交换机在接收到消息后,会直接转发到绑定到它上面的所有队列。
- Topic Exchange
主题交换机,这个交换机其实跟直连交换机流程差不多,但是它的特点就是在它的路由键支持通配符
- (星号) 用来表示一个单词 (必须出现的)
- #(井号) 用来表示任意数量(零个或多个)单词
SpringBoot整合RabbitMq
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置yml
#====== rabbitmq配置 ======
spring:
rabbitmq:
host: 192.168.183.139
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
acknowledge-mode: auto
retry:
enabled: true
max-attempts: 3
配置文件
@Configuration
public class RabbitMQConfig {
@Bean
public MessageConverter messageConverter(){
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.registerModule(new JavaTimeModule());
return new Jackson2JsonMessageConverter(mapper);
}
}
DirectExchange
消费者
@Configuration
public class DirectConsumer {
//注册一个队列
@Bean //启动多次为什么不报错?启动的时候,它会根据这个名称Direct_Q01先去查找有没有这个队列,如果有什么都不做,如果没有创建一个新的
public Queue queue(){
return QueueBuilder.durable("Direct_Q01").maxLength(100).build();
}
//注册交换机
@Bean
public DirectExchange exchange(){
//1.启动的时候,它会根据这个名称Direct_E01先去查找有没有这个交换机,如果有什么都不做,如果没有创建一个新的
return ExchangeBuilder.directExchange("Direct_E01").build();
}
//绑定交换机与队列关系
@Bean
public Binding binding(Queue queue,DirectExchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("RK01");
}
//启动一个消费者
@RabbitListener(queues = "Direct_Q01")
public void receiveMessage(String msg){
System.out.println("收到消息:"+msg);
}
}
生产者
@Service
public class DirectProvider {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(Object message) {
rabbitTemplate.convertAndSend("Direct_E01", "RK01", message);
}
}
FanoutExchange
消费者
@Configuration
public class FanoutConsumer {
@Bean
public Queue fanoutQueue() {
return QueueBuilder.durable("Fanout_Queue").build();
}
@Bean
public FanoutExchange fanoutExchange() {
return ExchangeBuilder.fanoutExchange("Fanout_Exchange").build();
}
@Bean
public Binding binding(Queue fanoutQueue, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(fanoutQueue).to(fanoutExchange);
}
//启动一个消费者
@RabbitListener(queues = "Fanout_Queue")
public void receiveMessage(String msg){
System.out.println("收到消息:"+msg);
}
}
生产者
@Service
@Slf4j
public class FanoutProvider {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(Object msg) {
rabbitTemplate.convertAndSend("Fanout_Exchange","",msg);
}
}
TopicExchange
消费者
//@Configuration
public class TopicConsumer {
@Bean
public TopicExchange topicExchange(){
return ExchangeBuilder.topicExchange("Topic_E01").build();
}
@Bean
public Queue topicQueue1(){
return QueueBuilder.durable("小龙").build();
}
@Bean
public Queue topicQueue2(){
return QueueBuilder.durable("海洋").build();
}
@Bean
public Queue topicQueue3(){
return QueueBuilder.durable("文超").build();
}
@Bean //交换机与队列关系
public Binding TopicBinding1(Queue topicQueue1,TopicExchange topicExchange){
return BindingBuilder.bind(topicQueue1).to(topicExchange).with("#");
}
@Bean //交换机与队列关系
public Binding TopicBinding2(Queue topicQueue2,TopicExchange topicExchange){
return BindingBuilder.bind(topicQueue2).to(topicExchange).with("1.6.*");
}
@Bean //交换机与队列关系
public Binding TopicBinding3(Queue topicQueue3,TopicExchange topicExchange){
return BindingBuilder.bind(topicQueue3).to(topicExchange).with("1.8.*");
}
@RabbitListener(queues = "小龙")
public void receiveMessage(OrderingOk msg){
System.out.println("小龙 收到消息:"+msg);
}
@RabbitListener(queues = "海洋")
public void receiveMessage2(OrderingOk msg){
System.out.println("海洋 收到消息:"+msg);
}
@RabbitListener(queues = "文超")
public void receiveMessage3(OrderingOk msg){
System.out.println("文超 收到消息:"+msg);
}
}
生产者
@Service
public class TopicProvider {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(Girl girl) {
rabbitTemplate.convertAndSend("Topic_E01",girl.getHeight(), girl);
}
}
死信队列
Configuration
@Slf4j
public class OrderingOkDelayConsumer {
@Autowired
private OrderingService orderService;
//死信交换机
@Bean
public FanoutExchange orderingOkDeadExchange(){
return ExchangeBuilder.fanoutExchange(RabbitMQConstant.ORDERING_OK_DEAD_EXCHANGE).build();
}
//死信队列
@Bean
public Queue overDeadQueue(){
return QueueBuilder.durable(RabbitMQConstant.ORDERING_OK_OVERTIME_DEAD_QUEUE).build();
}
//死信交换机与死信队列的绑定
@Bean
public Binding deadBinding1(Queue overDeadQueue,FanoutExchange orderingOkDeadExchange){
return BindingBuilder.bind(overDeadQueue).to(orderingOkDeadExchange);
}
@Bean
public Queue overtimeQueue() {
return QueueBuilder
.durable(RabbitMQConstant.ORDERING_OK_OVERTIME_QUEUE)
.deadLetterExchange(RabbitMQConstant.ORDERING_OK_DEAD_EXCHANGE)
.deadLetterRoutingKey(RabbitMQConstant.ORDERING_OK_OVERTIME_DEAD_QUEUE)
.ttl(1000 * 60 * 2) //该属性是队列的属性,设置消息的过期时间,消息在队列里面停留时间n毫秒后,就会把这个消息投递到死信交换机,针对的是所有的消息
//.maxLength(20) //设置队列存放消息的最大个数,x-max-length属性值,当队列里面消息超过20,会把队列之前的消息依次放进死信队列
.build();
}
@Bean
public FanoutExchange orderingOkExchange() {
return ExchangeBuilder.fanoutExchange(RabbitMQConstant.ORDERING_OK_EXCHANGE).build();
}
@Bean
public Binding binding(Queue overtimeQueue, FanoutExchange orderingOkExchange) {
return BindingBuilder.bind(overtimeQueue).to(orderingOkExchange);
}
@RabbitListener(queues = RabbitMQConstant.ORDERING_OK_OVERTIME_DEAD_QUEUE)
public void receiveMessage(OrderingOk orderingOk) {
log.debug("下单成功延迟收到查看订单状态消费者收到消息,用户id ==> {}, 订单号 ==> {}", orderingOk.getMemberId(), orderingOk.getOrderId());
orderService.checkOrderStatus(orderingOk);
}
}
延迟队列
创建具有超时功能且绑定死信交换机的消息队列
@Bean
public Queue directQueueLong(){
return QueueBuilder.durable("业务队列名称")
.deadLetterExchange("死信交换机名称")
.deadLetterRoutingKey("死信队列 RoutingKey")
.ttl(20000) // 消息停留时间
//.maxLength(500)
.build();
}
创建通用延时消息
rabbitTemplate.convertAndSend("交换机名称", "RoutingKey","对象",
message => {
message.getMessageProperties().setExpiration(String.valueOf(5000))
return message;
}
);
使用mq的延迟插件
- 下载3.10.0版本的延迟插件
- 安装插件并启用
docker cp /rabbitmq_delayed_message_exchange-3.10.0.ez rabbitmq:/plugins
- 进入 Docker 容器
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
- 退出容器重启 RabbitMQ
docker restart rabbitmq
- 创建交换机时直接指定
canal使用
mysql配置
- 修改my.cnf
[mysql]
default-character-set=utf8
[mysqld]
character-set-server=utf8
default-storage-engine=INNODB
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
log-bin=mysql-bin #开启 binlog
binlog-format=ROW #选择 ROW 模式
server_id=1 #指定当前服务的id,必须指定,否则会报错
log-output=FILE
general-log=1
general_log_file="D:\mysql-5.7.24-winx64\mysql.log"
#慢日志查询
slow-query-log=1
slow_query_log_file="D:\mysql-5.7.24-winx64\mysql_slow.log"
long_query_time=2
- 校验是否开启成功
show variables like 'log_%';
show variables like 'binlog_format';
show variables like 'server_id';
--查看所有日志
show binlog events;
--查看最新的日志
show master status
-- 查询指定的binlog日志
show binlog events in 'XTZJ-20221008CY-bin.000020'
--清空所有的 binlog 日志文件
reset master