封装disruptor高性能并发框架

1.需求场景:

封装基于JVM内存的高性能并发框架Disruptor,优化项目之前邮件发送、ftp文件输送功能,实现并行发送,提升发送效率。

2.直接上封装代码

定义生产者发布消息

package com.icon.disruptor.producer;

import com.icon.config.ThreadPoolMonitor;
import com.icon.disruptor.eventHandler.DisEventHandler;
import com.icon.disruptor.entity.DisEvent;
import com.icon.disruptor.exception.EventExceptionHandler;
import com.icon.disruptor.factory.DisEventFactory;
import com.icon.entity.common.LookCupDO;
import com.icon.repository.common.LookCupRepository;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.SleepingWaitStrategy;
import com.lmax.disruptor.WorkerPool;
import com.lmax.disruptor.dsl.ProducerType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

/**
 * describe
 *
 * @author 晴日朗
 * @date 2022年10月13日14:14
 */
public abstract class DisPublishBuilder {

    private static final Logger LOGGER = LoggerFactory.getLogger(DisPublishBuilder.class);

    @Autowired
    private LookCupRepository lookCupRepository;

    /**
     * 发布环境构建
     *
     * @param jsonParamList 要发布的数据 支持批量
     * @param className     类名大写
     * @throws Exception 异常
     */
    public void disPublishData(List<Map<String, Object>> jsonParamList, String className) throws Exception {
        LOGGER.info("DisPublishBuilder.className={},jsonParamList={}", className, jsonParamList);
        if (CollectionUtils.isEmpty(jsonParamList) || StringUtils.isEmpty(className)) return;

        ExecutorService executor = null;
        WorkerPool<DisEvent> workerPool = null;
        try {
            // 1.创建可以复用的线程池,提供给consumer
            List<LookCupDO> lookCupDOS = lookCupRepository.findAllDataByType("EMAIL_CONSUMERS");
            int consumersCounts = CollectionUtils.isEmpty(lookCupDOS) ? 6 : StringUtils.isEmpty(lookCupDOS.get(0).getColumn1()) ? 6 : Integer.parseInt(lookCupDOS.get(0).getColumn1());
            BlockingDeque<Runnable> blockingDeque = new LinkedBlockingDeque<>(10);
            executor = new ThreadPoolMonitor(consumersCounts, 10, 1, TimeUnit.SECONDS, blockingDeque, "disruptorPool");

            // 2.创建event工厂
            DisEventFactory eventFactory = new DisEventFactory();

            // 3.定义ringBuffer数组大小,设置为2的N次方,位运算,效率高
            int ringBufferSize = 1024 * 1024;

            // 4.创建ringBuffer
            RingBuffer<DisEvent> ringBuffer = RingBuffer.create(ProducerType.MULTI, eventFactory, ringBufferSize, new SleepingWaitStrategy());
            SequenceBarrier barriers = ringBuffer.newBarrier();

            // 5.注册消费者,可注册多个,分摊消费模式  消费者实现的是WorkHandle接口

            DisEventHandler[] consumers = new DisEventHandler[consumersCounts];
            for (int i = 0; i < consumers.length; i++) {
                consumers[i] = new DisEventHandler();
            }

            workerPool = new WorkerPool<DisEvent>(ringBuffer, barriers,
                    new EventExceptionHandler(), consumers);

            ringBuffer.addGatingSequences(workerPool.getWorkerSequences());
            workerPool.start(executor);

            // 6.创建生产者
            DisEventProducer producer = new DisEventProducer(ringBuffer);

            // 7.业务参数投递
            for (Map<String, Object> map : jsonParamList) {
                // 逐条发布,多线程并发处理
                producer.onData(map, className);
            }
        } catch (ParseException e) {
            throw new Exception(e);
        } finally {
            if (null != workerPool) {
                LOGGER.info("workerPool.running={}", workerPool.isRunning());
                workerPool.drainAndHalt();
                LOGGER.info("workerPool.drainAndHalt,running={}", workerPool.isRunning());
            }
            if (null != executor) {
                executor.shutdown();
                LOGGER.info("executor.shutdown");
            }
        }

    }
}

生产者发布消息

package com.icon.disruptor.producer;

import com.icon.disruptor.entity.DisEvent;
import com.lmax.disruptor.RingBuffer;

import java.util.Map;

/**
 * describe 生产者-定义如何将邮件的业务信息通过事件发布到环形队列
 *
 * @author 晴日朗
 * @date 2022年03月17日17:22
 */
public class DisEventProducer {
    // 存储数据的环形队列
    private final RingBuffer<DisEvent> ringBuffer;

    public DisEventProducer(RingBuffer<DisEvent> ringBuffer) {
        this.ringBuffer = ringBuffer;
    }

    public void onData(Map<String, Object> map, String className) throws Exception {
        // ringBuffer是个队列,其next方法返回的是下一条记录之后的位置,这是个可用位置
        long sequence = ringBuffer.next();
        try {
            // sequence位置取出事件
            DisEvent event = ringBuffer.get(sequence);
            // 添加到消费端信息
            event.setObjectMap(map);
            event.setClassName(className);
        } catch (Exception e) {
            throw new Exception("EmailEventProducer.onData.error={}", e);
        } finally {
            // 发布
            ringBuffer.publish(sequence);
        }
    }
}

定义工厂

package com.icon.disruptor.factory;

import com.icon.disruptor.entity.DisEvent;
import com.lmax.disruptor.EventFactory;

/**
 * describe 声明一个Factory来实例化DisEvent
 *
 * @author 晴日朗
 * @date 2022年03月17日17:25
 */
public class DisEventFactory implements EventFactory<DisEvent> {
    @Override
    public DisEvent newInstance() {
        return new DisEvent();
    }
}

异常处理

package com.icon.disruptor.exception;

import com.lmax.disruptor.ExceptionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * disruptor框架异常抛出日志打印
 */
public class EventExceptionHandler implements ExceptionHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(EventExceptionHandler.class);

    @Override
    public void handleEventException(Throwable ex, long sequence, Object event) {
        LOGGER.error("handleEventException={}", ex);
    }

    @Override
    public void handleOnShutdownException(Throwable ex) {
        LOGGER.error("handleOnShutdownException={}", ex);
    }

    @Override
    public void handleOnStartException(Throwable ex) {
        LOGGER.error("handleOnStartException={}", ex);
    }

}

消息体-传输数据

package com.icon.disruptor.entity;

import java.util.Map;

/**
 * describe 生产者和消费者传递数据消息体
 *
 * @author 一叶孤舟
 * @date 2022年03月17日17:25
 */
public class DisEvent {
    // 消息数据
    private Map<String,Object> objectMap;
    private String className;

    public Map<String, Object> getObjectMap() {
        return objectMap;
    }

    public void setObjectMap(Map<String, Object> objectMap) {
        this.objectMap = objectMap;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }
}

消费者处理器

package com.icon.disruptor.eventHandler;

import com.icon.disruptor.entity.DisEvent;
import com.icon.enums.EventHandlerEnum;
import com.lmax.disruptor.WorkHandler;

/**
 * describe 消费者服务
 *
 * @author 晴日朗
 * @date 2022年03月17日17:41
 */
public class DisEventHandler implements WorkHandler<DisEvent> {
    @Override
    public void onEvent(DisEvent event) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String valueByClassName = EventHandlerEnum.getValueByClassName(event.getClassName());
        Class<?> aClass = Class.forName(valueByClassName);
        DisConsumerService disConsumerService = (DisConsumerService) aClass.newInstance();
        disConsumerService.consume(event.getObjectMap());
    }
}

定义消费者映射关系

package com.icon.enums;

/**
 * describe 消费者映射关系
 *
 * @author 晴日朗
 * @date 2022年10月17日14:22
 */
public enum EventHandlerEnum {
    EMAIL_EVENT_HANDLER("EmailConsumerService", "com.icon.disruptor.consumer.EmailConsumerService");

    private String className;

    private String classFullName;

    EventHandlerEnum() {
        throw new RuntimeException();
    }

    EventHandlerEnum(String className, String classFullName) {
        this.className = className;
        this.classFullName = classFullName;
    }

    public static String getValueByClassName(String className) {
        for (EventHandlerEnum eventHandlerEnum : EventHandlerEnum.values()) {
            if (className.equals(eventHandlerEnum.getClassName())) {
                return eventHandlerEnum.getClassFullName();
            }
        }
        return null;
    }

    public String getClassName() {
        return className;
    }

    public String getClassFullName() {
        return classFullName;
    }
}

消费者统一入口

package com.icon.disruptor.eventHandler;

import java.util.Map;

/**
 * describe 消费者统一入口
 *
 * @author 一叶孤舟
 * @date 2022年10月17日15:42
 */
public interface DisConsumerService {
    void consume(Map<String, Object> eventMap);
}

以上disruptor框架封装完毕,接下来是使用步骤:

1.自定义消费者,实现DisConsumerService接口,重写consume(…)方法

2.配置消费者映射关系EventHandlerEnum

3.定义disruptor生产者,继承DisPublishBuilder抽象类,执行super.disPublishData(…)方法,发布消息

自定义消费者李子:


/**
 * describe 具体的消费者
 *
 * @author 晴日朗
 * @date 2022年10月17日15:42
 */
public class EmailConsumerService implements DisConsumerService {
    private static final Logger LOGGER = LoggerFactory.getLogger(EmailConsumerService.class);
    @Override
    public void consume(Map<String, Object> objectMap) {
        LOGGER.info("EmailConsumerService.consume.data={}", JSON.toJSONString(objectMap));
    }
}

小结:封装了disruptor框架,达到了复用效果。害,第一次实操封装,感觉有点别扭,实力不允许啊,哈哈。disruptor并发处理任务,并发处理性能相当高,具体的我在项目中作了测试,由之前的串行到并行,大大提升了效率,大家可以试试或者可以试试其他的并行框架或者实现并发处理,对比一下效果。当然,在封装过程中也遇到了很多问题,我都一一记录在了另一篇文章【首次使用disruptor框架遇到的问题】。慢慢完善吧。加油啊,奥利给。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值