Spring Cloud–Sleuth+Zipkin 链路跟踪/订单的流量削峰

Sleuth

  • 产生链路跟踪日志
  • A –> B –> C
    A的id会被当做整条链路的id
    默认只有10%的日志会发到Zipkin
A, USFHSAJFGVDMJ, USFHSAJFGVDMJ ,true
B, USFHSAJFGVDMJ ,FGRJEGNTHYJN5 ,false
C, USFHSAJFGVDMJ ,GJREG98GEWU87 ,false

使用Sleuth

  • 添加Sleuth依赖
  • 修改2,3,4,6,有自动配置类
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

链路日志发送到Zipkin处理

两种方式

1.直接连接,向Zipkin提交日志
2.通过消息服务转发日志
解耦、流量削峰

通过消息服务实现步骤

1. 添加Zipkin client依赖至2.3.4.6

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

2. 在06项目添加rabiitmq依赖

(2.3.4已经加过了)

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>

3. 四个模块中,配置发送方式

  • rabbit(还有activemq、kafka、web发送方式)
  • 在config目录修改,再推送到远程仓库
    06
    在这里插入图片描述
    02.03.04
    在这里插入图片描述
    在这里插入图片描述

5.下载jar文件

在这里插入图片描述

6. 启动zipkin服务器

  • 在jar包地址cmd
java -jar z.jar --zipkin.collector.rabbitmq.uri=amqp://admin:admin@192.168.64.140:5672

在这里插入图片描述
在这里插入图片描述
访问http://localhost:3001/order-service/u56uy454y
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Rabbitmq 订单流量削峰案例

1.导入商城项目
2.修改pom.xml拖拽到idea 把springboot版本改成2.3.2RELEASE
3.右键pom.xml编辑器
4.导入sql脚本
5.yml配置查看
在这里插入图片描述

订单发送到rabbitmq

  1. 添加 rabbitmq依赖连接配置
<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
server:
  port: 80

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/pd_store?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    username: root
    password: root
  rabbitmq:
    host: 192.168.64.140
    port: 5672
    username: admin
    password: admin
    virtual-host: /
mybatis:
  mapperLocations: classpath:com.pd.mapper/*.xml

logging:
  level:
    cn.tedu.ssm.mapper: debug
resources: # 指定静态资源的路径
  static-locations: classpath:/
  cache-period: 0


  1. 在启动类(或者自定义自动配置类)中设置队列的参数:orderQueue,true,false,false
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);
	}
	//新建SpringQueue实例 用来封装队列的参数
	//rabbitmq的自动配置类会自动发现这个queue实例 根据参数创建队列
	@Bean
	public Queue orderQueue(){
		//持久 非独占 不自动删除
		return new Queue("orderQueue",true,false,false);
	}
}

  1. 修改OrderserviceImpl

注入对象:AmqpTemplate 用来封装消息发送的API工具
发送消息

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

订单的消费者
1.rabbitmq基础配置,准备队列参数
2.新建消费者类:OrderConsumer
3.用注解配置接收消息
4.收到的订单通过原来的业务代码,存储到数据库

package com.pd.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.pd.mapper.PdCartItemMapper;
import com.pd.mapper.PdItemMapper;
import com.pd.mapper.PdItemParamItemMapper;
import com.pd.mapper.PdOrderItemMapper;
import com.pd.mapper.PdOrderMapper;
import com.pd.mapper.PdShippingMapper;
import com.pd.pojo.PdCartItem;
import com.pd.pojo.PdCartItemExample;
import com.pd.pojo.PdItem;
import com.pd.pojo.PdItemParamItem;
import com.pd.pojo.PdItemParamItemExample;
import com.pd.pojo.PdOrder;
import com.pd.pojo.PdOrderExample;
import com.pd.pojo.PdOrderItem;
import com.pd.pojo.PdOrderItemExample;
import com.pd.pojo.PdShipping;
import com.pd.pojo.ItemVO;
import com.pd.pojo.OrderVO;
import com.pd.pojo.paramData.PdItemParamData;
import com.pd.pojo.paramData.Params;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.pd.common.utils.JsonUtils;
import com.pd.service.OrderService;

@Service
public class OrderServiceImpl implements OrderService {
	@Autowired
	PdOrderMapper pdOrderMapper;

	@Autowired
	PdCartItemMapper pdCartItemMapper;

	@Autowired
	PdItemMapper pdItemMapper;

	@Autowired
	PdItemParamItemMapper pdItemParamItemMapper;

	@Autowired
	PdShippingMapper pdShippingMapper;

	@Autowired
	PdOrderItemMapper pdOrderItemMapper;

//	@Autowired
//	private AmqpTemplate amqpTemplate;

	
	public String saveOrder(PdOrder pdOrder) throws Exception {
//		String orderId = generateId();//生成订单id
//		pdOrder.setOrderId(orderId);//订单id放入订单对象

//		//转换并发送 先把数据转成byte数组在发送
//		amqpTemplate.convertAndSend("orderQueue",pdOrder);








		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;
	}

	public synchronized String generateId() {
		Random random = new Random();
		int number = random.nextInt(9000000) + 1000000;
		return "" + System.currentTimeMillis() + number;
	}
	public List<ItemVO> selectCartItemByUseridAndItemIds(Long userId, List<Long> itemIds) throws Exception {
		PdCartItemExample cartItemExample = new PdCartItemExample();
		PdCartItemExample.Criteria criteria = cartItemExample.or();
		criteria.andUserIdEqualTo(userId);
		criteria.andItemIdIn(itemIds);
		criteria.andStatusEqualTo(1);

		List<PdCartItem> cartItems = pdCartItemMapper.selectByExample(cartItemExample);
		List<ItemVO> itemVOs = new ArrayList<>();
		for (PdCartItem pdCartItem : cartItems) {
			Long itemId = pdCartItem.getItemId();
			PdItem pdItem = pdItemMapper.selectByPrimaryKey(itemId);
			PdItemParamItemExample paramExample = new PdItemParamItemExample();
			PdItemParamItemExample.Criteria paramCriteria = paramExample.or();
			paramCriteria.andItemIdEqualTo(itemId);
			List<PdItemParamItem> items = pdItemParamItemMapper.selectByExampleWithBLOBs(paramExample);
			List<Params> paramsList = new ArrayList<>();
			if (items != null && items.size() >= 1) {
				PdItemParamItem item = items.get(0);
				String paramData = item.getParamData();
				List<PdItemParamData> list = JsonUtils.jsonToList(paramData, PdItemParamData.class);
				paramsList = list.get(0).getParams();
			}
			ItemVO itemVO = new ItemVO();
			itemVO.setPdCartItem(pdCartItem);
			itemVO.setPdItem(pdItem);
			itemVO.setParamsList(paramsList);
			itemVOs.add(itemVO);
		}
		return itemVOs;
	}

	
	public PdOrder selectById(String orderId) throws Exception {
		PdOrder pdOrder = pdOrderMapper.selectByPrimaryKey(orderId);
		return pdOrder;
	}

	
	public List<OrderVO> selectByUserIdAndStatus
	(Long userId, int status) throws Exception {
		//where user_id=14 and status!=9 order by create_time desc
		PdOrderExample orderExample=new PdOrderExample();
		PdOrderExample.Criteria criteria=orderExample.or();
		criteria.andUserIdEqualTo(userId);
		criteria.andStatusNotEqualTo(9);//9閿熸枻鎷风ず閿熸枻鎷烽敓鏂ゆ嫹閿熺獤鎾呮嫹鍒犻敓鏂ゆ嫹
		if (status!=0)
		{
			criteria.andStatusEqualTo(status);
		}
		orderExample.setOrderByClause("create_time desc");
		List<PdOrder> orders=pdOrderMapper
				.selectByExample(orderExample);
		
		List<OrderVO> orderVOs=new ArrayList<>();
		for (PdOrder pdOrder:orders)
		{
			//from pd_order_item where order_id=30;
			PdOrderItemExample itemExample=new PdOrderItemExample();
			PdOrderItemExample.Criteria itemCriteria=itemExample.or();
			itemCriteria.andOrderIdEqualTo(pdOrder.getOrderId());
			List<PdOrderItem> orderItems=
					pdOrderItemMapper
					.selectByExample(itemExample);
			for (PdOrderItem pdOrderItem:orderItems)
			{
				
			//3.3.1 example,criteria
				PdItemParamItemExample example=
						new PdItemParamItemExample();
				PdItemParamItemExample.Criteria paramCriteria=
						example.or();
				long itemId=Long.parseLong(pdOrderItem
						.getItemId());
				paramCriteria.andItemIdEqualTo(itemId);
				
				List<PdItemParamItem> paramItemList=pdItemParamItemMapper
						.selectByExampleWithBLOBs(example);
				List<Params> paramsList=new ArrayList<>();
				if (paramItemList.size()>=1)
				{
			//3.3.3 鍙杙aram_data
					PdItemParamItem pdItemParamItem=
							paramItemList.get(0);
					String paramData=pdItemParamItem
							.getParamData();					
					List<PdItemParamData> paramDataList=JsonUtils
							.jsonToList(paramData, 
									PdItemParamData.class);
					paramsList=paramDataList.get(0).getParams();
				}
			pdOrderItem.setParamsList(paramsList);	
			}
			OrderVO orderVO=new OrderVO();
			orderVO.setPdOrder(pdOrder);
			orderVO.setPdOrderItems(orderItems);
			
			orderVOs.add(orderVO);
		}
		return orderVOs;
	}

	
	

	
	public PdOrder findOrderByOrderid(String orderId) throws Exception {
PdOrder pdOrder=pdOrderMapper
.selectByPrimaryKey(orderId);
		return pdOrder;
	}

	@Override
	public int updateOrderStatus(String orderId, int status) throws Exception {
//update pd_order set status=8 where orderId=100
		PdOrder pdOrder=new PdOrder();
		pdOrder.setStatus(status);
		
		PdOrderExample example=new PdOrderExample();
		PdOrderExample.Criteria criteria=example.or();
		criteria.andOrderIdEqualTo(orderId);
		
		int row=pdOrderMapper
				.updateByExampleSelective
				(pdOrder, example); 
		return row;
	}

}

在这里插入图片描述

  • 订单的流量削峰解释:购物系统产生的定展,不直接存储到数据库,而是发送到rabbitmq
    后台消费者模块接收订单,再向数据库存储,短时间瞬间产生大量订单并发送存储,变成顺序存储
    使用模式为简单模式,可以该称工作模式

版权声明:本文为weixin_55740233原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。