当用户下订单时,我们的业务系统直接与数据库通信,把订单保存到数据库中,当系统流量突然激增,大量的订单压力,会拖慢业务系统和数据库系统,我们需要应对流量峰值,让流量曲线变得平缓,如下图
订单存储的解耦
为了进行流量削峰,我们引入 rabbitmq 消息队列,当购物系统产生订单后,可以把订单数据发送到消息队列;而订单消费者应用从消息队列接收订单消息,并把订单保存到数据库
这样,当流量激增时,大量订单会暂存在rabbitmq中,而订单消费者可以从容地从消息队列慢慢接收订单,向数据库保存。
因为是事先写好的项目,所以直接导入就好。
2)将准备好的pom.xml文件直接拖入idea
3)在编辑器内右键 --> add as maven project
由于数据库过大,所以可事先增加MySQL缓存大小
set global max_allowed_packet=100000000;
set global net_buffer_length=100000;
SET GLOBAL interactive_timeout=28800000;
SET GLOBAL wait_timeout=28800000;
使用可视化工具导入即可
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
package com.pd;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@MapperScan("com.pd.mapper")
public class RunPdAPP{
public static void main(String[] args) {
SpringApplication.run(RunPdAPP.class, args);
}
/*
新建 Queue 实例,用来封装队列的参数,
Rabbitmq的自动配置类会自动发现 Queue 实例,
根据其中的参数,连接服务器创建队列
import org.springframework.amqp.core.Queue;
*/
@Bean
public Queue orderQueue() {
return new Queue("orderQueue",true,false,false);
}
}
在订单业务实现类中,取出原先提交订单的数据库操作,转换为将订单传送到RabbitMQ中
/*
在 RabbitAutoConfiguration 中自动创建了AmqpTemplate实例,
这里直接注入
*/
@Autowired
private AmqpTemplate t;
public String saveOrder(PdOrder pdOrder) throws Exception {
String orderId = generateId();
pdOrder.setOrderId(orderId); // orderId,addId,userId,itemIdList
// 转换并发送
// 自动把数据变成 byte[] 数组,再发送
t.convertAndSend("orderQueue", pdOrder);
return orderId;
}
1)在同目录下复制pd-web的项目取名pd-web-consumer作为消费者服务
2)修改pom.xml中artifactId
3)在xml中修改端口配置
在pd-web-consumer创建OrderConsumer
package com.pd;
import com.pd.pojo.PdOrder;
import com.pd.service.OrderService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 自动创建实例
* 自动注册成为消费者
* 自动将消息传递到 @RabbitHandler方法
*/
@Component
@RabbitListener(queues = "orderQueue")
public class OrderConsumer {
@Autowired
private OrderService orderService;
//配合@RabbitListener,用来指定处理消息的方法
//@RabbitHandler注解只能有一个,不能有多个
@RabbitHandler
public void receive(PdOrder pdOrder) throws Exception {
orderService.saveOrder(pdOrder);
System.out.println("----------------------------订单已保存");
}
}
在pd-web-consumer中订单业务实现类中将订单存入数据库
public String saveOrder(PdOrder pdOrder) throws Exception {
String orderId = pdOrder.getOrderId();
PdShipping pdShipping = pdShippingMapper.selectByPrimaryKey(pdOrder.getAddId());
pdOrder.setShippingName(pdShipping.getReceiverName());
pdOrder.setShippingCode(pdShipping.getReceiverAddress());
pdOrder.setStatus(1);//
pdOrder.setPaymentType(1);
pdOrder.setPostFee(10D);
pdOrder.setCreateTime(new Date());
double payment = 0;
List<ItemVO> itemVOs = selectCartItemByUseridAndItemIds(pdOrder.getUserId(), pdOrder.getItemIdList());
for (ItemVO itemVO : itemVOs) {
PdOrderItem pdOrderItem = new PdOrderItem();
String id = generateId();
//String id="2";
pdOrderItem.setId(id);
pdOrderItem.setOrderId(orderId);
pdOrderItem.setItemId("" + itemVO.getPdItem().getId());
pdOrderItem.setTitle(itemVO.getPdItem().getTitle());
pdOrderItem.setPrice(itemVO.getPdItem().getPrice());
pdOrderItem.setNum(itemVO.getPdCartItem().getNum());
payment = payment + itemVO.getPdCartItem().getNum() * itemVO.getPdItem().getPrice();
pdOrderItemMapper.insert(pdOrderItem);
}
pdOrder.setPayment(payment);
pdOrderMapper.insert(pdOrder);
return orderId;
}
我们首先在系统服务中,我们不是直接点击确定后,直接将订单存入数据库,当订单量大的时候,数据库一时肯定是吃不消的,所有我们在系统中将订单信息发送到消息队列中,这里使用的RabbitMQ;然后再创建一个消费者服务,专门进行订单存入数据库的操作,消息队列发送消息肯定是均衡,一次达到流量削峰的效果。