目录
一、rocketmq的使用
1、开启rocketmq
2、添加依赖
<!-- disruptor 高速队列 3.4.2-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
</dependency>
<!-- cpu亲和锁 3.1.7-->
<dependency>
<groupId>net.openhft</groupId>
<artifactId>affinity</artifactId>
<version>${affinity.version}</version>
</dependency>
<!-- spring-cloud-stream-rocketmq-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rocketmq</artifactId>
</dependency>
3、springboot整合disruptor
package com.dragonwu.disruptor;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "spring.disruptor")
public class DisruptorProperties {
/**
* 缓冲区的大小
*/
private Integer ringBufferSize = 1024 * 1024 ;
/**
* 是否支持多生产者
*/
private boolean isMultiProducer = false ;
}
异常处理:
package com.dragonwu.disruptor;
import com.lmax.disruptor.BatchEventProcessor;
import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.ExceptionHandler;
import com.lmax.disruptor.LifecycleAware;
import lombok.extern.slf4j.Slf4j;
/**
* DisruptorHandlerException 的异常处理
*/
@Slf4j
public class DisruptorHandlerException implements ExceptionHandler {
/**
* <p>Strategy for handling uncaught exceptions when processing an event.</p>
*
* <p>If the strategy wishes to terminate further processing by the {@link BatchEventProcessor}
* then it should throw a {@link RuntimeException}.</p>
*
* @param ex the exception that propagated from the {@link EventHandler}.
* @param sequence of the event which cause the exception.
* @param event being processed when the exception occurred. This can be null.
*/
@Override
public void handleEventException(Throwable ex, long sequence, Object event) {
log.info("handleEventException Exception===>{} , sequence==> {} ,event===>{}",ex.getMessage(),sequence,event);
}
/**
* Callback to notify of an exception during {@link LifecycleAware#onStart()}
*
* @param ex throw during the starting process.
*/
@Override
public void handleOnStartException(Throwable ex) {
log.info("OnStartHandler Exception===>{} ",ex.getMessage());
}
/**
* Callback to notify of an exception during {@link LifecycleAware#onShutdown()}
*
* @param ex throw during the shutdown process.
*/
@Override
public void handleOnShutdownException(Throwable ex) {
log.info("OnShutdownHandler Exception===>{} ",ex.getMessage());
}
}
处理器:
package com.dragonwu.disruptor;
import com.lmax.disruptor.EventTranslatorOneArg;
import com.lmax.disruptor.RingBuffer;
import com.dragonwu.model.Order;
/**
* 在boot里面使用它发送消息
*/
public class DisruptorTemplate {
private static final EventTranslatorOneArg<OrderEvent, Order> TRANSLATOR = new EventTranslatorOneArg<OrderEvent, Order>() {
public void translateTo(OrderEvent event, long sequence, Order input) {
event.setSource(input);
}
};
private final RingBuffer<OrderEvent> ringBuffer;
public DisruptorTemplate(RingBuffer<OrderEvent> ringBuffer) {
this.ringBuffer = ringBuffer;
}
/**
* 我们使用DisruptorTemplate 时,就使用它的onData方法
* @param input
*/
public void onData(Order input) {
ringBuffer.publishEvent(TRANSLATOR, input);
}
}
自动配置装配:
package com.dragonwu.disruptor;
import com.lmax.disruptor.*;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import net.openhft.affinity.AffinityThreadFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ThreadFactory;
@Configuration
@EnableConfigurationProperties(value = DisruptorProperties.class)
public class DisruptorAutoConfiguration {
public DisruptorProperties disruptorProperties;
public DisruptorAutoConfiguration(DisruptorProperties disruptorProperties) {
this.disruptorProperties = disruptorProperties;
}
@Bean
public EventFactory<OrderEvent> eventEventFactory() {
EventFactory<OrderEvent> orderEventEventFactory = new EventFactory<OrderEvent>() {
@Override
public OrderEvent newInstance() {
return new OrderEvent();
}
};
return orderEventEventFactory;
}
@Bean
public ThreadFactory threadFactory() {
return new AffinityThreadFactory("Match-Handler:") ;
}
/**
* 无锁高效的等待策略
*
* @return
*/
@Bean
public WaitStrategy waitStrategy() {
return new YieldingWaitStrategy();
}
/**
* 创建一个RingBuffer
* eventFactory: 事件工厂
* threadFactory: 我们执行者(消费者)的线程该怎么创建
* waitStrategy : 等待策略: 当我们ringBuffer 没有数据时,我们怎么等待
*/
@Bean
public RingBuffer<OrderEvent> ringBuffer(
EventFactory<OrderEvent> eventFactory,
ThreadFactory threadFactory,
WaitStrategy waitStrategy,
EventHandler<OrderEvent>[] eventHandlers
) {
/**
* 构建disruptor
*/
Disruptor<OrderEvent> disruptor = null;
ProducerType producerType = ProducerType.SINGLE;
if (disruptorProperties.isMultiProducer()) {
producerType = ProducerType.MULTI;
}
disruptor = new Disruptor<OrderEvent>(eventFactory, disruptorProperties.getRingBufferSize(), threadFactory, producerType, waitStrategy);
disruptor.setDefaultExceptionHandler(new DisruptorHandlerException());
// 设置消费者---我们的每个消费者代表我们的一个交易对,有多少个交易对,我们就有多少个eventHandlers ,事件来了后,多个eventHandlers 是并发执行的
disruptor.handleEventsWith(eventHandlers);
RingBuffer<OrderEvent> ringBuffer = disruptor.getRingBuffer();
disruptor.start();// 开始监听
final Disruptor<OrderEvent> disruptorShutdown = disruptor;
// 使用优雅的停机
Runtime.getRuntime().addShutdownHook(new Thread(
() -> {
disruptorShutdown.shutdown();
}, "DisruptorShutdownThread"
));
return ringBuffer;
}
/**
* 创建DisruptorTemplate
*
* @param ringBuffer
* @return
*/
@Bean
public DisruptorTemplate disruptorTemplate(RingBuffer<OrderEvent> ringBuffer) {
return new DisruptorTemplate(ringBuffer);
}
}
订单类:
package com.dragonwu.disruptor;
import lombok.Data;
import java.io.Serializable;
@Data
public class OrderEvent implements Serializable {
/**
* 时间戳
*/
private final long timestamp;
/**
* 事件携带的数据
*/
protected transient Object source;
public OrderEvent() {
this.timestamp = System.currentTimeMillis();
}
public OrderEvent(Object source) {
this.timestamp = System.currentTimeMillis();
this.source = source ;
}
}
事件处理器:
package com.dragonwu.disruptor;
import com.lmax.disruptor.EventHandler;
import com.dragonwu.match.MatchServiceFactory;
import com.dragonwu.match.MatchStrategy;
import com.dragonwu.model.Order;
import com.dragonwu.model.OrderBooks;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
* 该对象 有多个: 和Symbol的数据对应
* 针对某一个OrderEventHandler ,只会同一时间有一个线程来执行它
*/
@Data
@Slf4j
public class OrderEventHandler implements EventHandler<OrderEvent> {
private OrderBooks orderBooks;
private String symbol ;
public OrderEventHandler(OrderBooks orderBooks) {
this.orderBooks = orderBooks;
this.symbol = this.orderBooks.getSymbol() ;
}
/**
* 接收到了某个消息
*
* @param event
* @param sequence
* @param endOfBatch
* @throws Exception
*/
@Override
public void onEvent(OrderEvent event, long sequence, boolean endOfBatch) throws Exception {
// 从ringbuffer 里面接收了某个数据
Order order = (Order)event.getSource();
if(!order.getSymbol().equals(symbol)){ // 我们接收到了一个不属于我们处理的数据,我们不处理
return;
}
// log.info("开始接收订单事件============>{}", event);
MatchServiceFactory.getMatchService(MatchStrategy.LIMIT_PRICE).match(orderBooks ,order);
/// 处理逻辑是啥?
// log.info("处理完成我们的订单事件===================>{}", event);
}
}
4、集成SpringCloudStreamRocketmq
配置:
stream:
bindings:
order_in: {destination: order_in, content-type: application/plain, group: order-group, consumer.maxAttempts: 1}
trade_plate_out: {destination: trade_plate_out, content-type: application/plain}
completed_orders_out: {destination: completed_orders_out, content-type: application/plain}
exchange_trades_out: {destination: exchange_trades_out, content-type: application/plain}
cancel_order_out: {destination: cancel_order_out, content-type: application/plain}
rocketmq:
binder:
name-server: rocket-server:9876
1、添加数据收发接口
package com.dragonwu.rocket;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.MessageChannel;
public interface Sink {
@Input("order_in")
public MessageChannel messageChannel() ;
}
package com.dragonwu.rocket;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
public interface Source {
/**
* 盘口数据的输出
* @return
*/
@Output("trade_plate_out")
MessageChannel plateOut() ;
/**
* 完成订单数据的输出
* @return
*/
@Output("completed_orders_out")
MessageChannel completedOrdersOut() ;
/**
* 交易记录的输入
* @return
*/
@Output("exchange_trades_out")
MessageChannel exchangeTradesOut() ;
/**
* 取消单的输出
* @return
*/
@Output("cancel_order_out")
MessageChannel cancelOrderOut() ;
}
消息消费者:
package com.dragonwu.rocket;
import com.dragonwu.disruptor.DisruptorTemplate;
import com.dragonwu.domain.EntrustOrder;
import com.dragonwu.model.Order;
import com.dragonwu.util.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MessageConsumerListener {
@Autowired
private DisruptorTemplate disruptorTemplate;
@StreamListener("order_in")
public void handleMessage(EntrustOrder entrustOrder) {
Order order = null;
if (entrustOrder.getStatus() == 2) { // 该单需要取消
order = new Order();
order.setOrderId(entrustOrder.getId().toString());
order.setCancelOrder(true);
} else {
order = BeanUtils.entrustOrder2Order(entrustOrder);
}
log.info("接收到了委托单:{}", order);
disruptorTemplate.onData(order);
}
}
开启stream的开发:
package com.dragonwu.rocket;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.context.annotation.Configuration;
/**
* 开启我们的Stream的开发
*/
@Configuration
@EnableBinding(value = {Sink.class,Source.class}) //
public class RocketStreamConfig {
}
交易微服务里的数据发送:
spring:
cloud:
stream:
rocketmq:
binder:
name-server: rocket-server:9876 #/RocketMQ Message hasn't been sent
binders:
order_out: {consumer.orderly: true}
bindings:
order_out: {destination: order_in, content-type: application/plain}
cancel_order_in: {destination: cancel_order_out, content-type: application/plain, group: order-group, consumer.maxAttempts: 1}
exchange_trade_in: {destination: exchange_trades_out, content-type: application/plain, group: order-group, consumer.maxAttempts: 1}
1、收发接口
package com.dragonwu.config.rocket;
import com.dragonwu.enums.MessageChannel;
import org.springframework.cloud.stream.annotation.Input;
/**
* 数据的接收
*/
public interface Sink {
/**
* 交易数据的输入
* @return
*/
@Input("exchange_trade_in")
MessageChannel exchangeTradeIn() ;
/**
* 取消订单的输入
* @return
*/
@Input("cancel_order_in")
MessageChannel cancelOrderIn() ;
}
package com.dragonwu.config.rocket;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
public interface Source {
@Output("order_out")
MessageChannel outputMessage() ;
}
配置类:
package com.dragonwu.config.rocket;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBinding(value = Source.class)
public class RocketMQConfig {
}
服务消费者:
package com.dragonwu.config.rocket;
import com.dragonwu.domain.ExchangeTrade;
import com.dragonwu.service.EntrustOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.List;
/***
* 交易数据的监听
*/
@Component
@Slf4j
public class ExchangeTradeListener {
@Autowired
private EntrustOrderService entrustOrderService ;
@Transactional
@StreamListener("exchange_trade_in")
public void receiveExchangeTrade(List<ExchangeTrade> exchangeTrades){
if (CollectionUtils.isEmpty(exchangeTrades)){
return;
}
for (ExchangeTrade exchangeTrade : exchangeTrades) {
if (exchangeTrade != null) {
// 交易完成后,去更新我们的数据库
entrustOrderService.doMatch(exchangeTrade);
}
}
}
@Transactional
@StreamListener("cancel_order_in")
public void receiveCancelOrder(String orderId){
entrustOrderService.cancleEntrustOrderToDb(orderId);
}
}