自适应分组多级并发框架

一、问题背景

关于自适应的问题和细节可以参考 文章 :Kafka消息消费之性能提升实践

多级并发含义是指针对批量数据的处理,不能完全并发,但是有条件可以分组进行并发处理,简单举例来说,针对数据集A、B、C、D、E、F、G,其中由于业务关系,其中ABC和DE和FG三组,组与为组间无法并发,但组内数据可以并发处理。

所以针对上述应用场景,需要开发相对应的技术框架,分离业务和技术关注点,降低业务复杂度。

要完成上述框架功能,分析需要解决的技术难点有:

  • 首先需要一个自适应的消息采集框架,可以根据生产者的压力灵活调整批消息组中消息数量。(后序加入AI后,可以将批消息组中消息数量、处理时间、队列中存量消息数量进行学习)
  • 其次批消息组间的处理要分级,需要一个分级处理的框架策略
  • 最后,批消息组内的消息要可以并发(最好不产生饥饿情况)

一、框架原理图

在这里插入图片描述

二、自适应的消息采集框架

目前自适应框架相对来说已经够用,后序考虑加上AI的功能,将关键的自适应batchSize参数,进行更智能的调整。

详细参考文章:Kafka消息消费之性能提升实践

三、分级处理框架

分级处理框架中首先要抽象出分级策略,如下:

public interface MlcStrategy<T> {
   
    Function<T, Integer> shardKey();
    default Function<T, Boolean> shouldProcess() {
   
        return t -> true;
    }
    Consumer<T> dataProcess();
}
  • T:泛型参数对应待处理的消息类型
  • shardKey:表示消息组织分片键,一般指定成消息的唯一标识;该标识仅在组内处理时生效
  • shouldProcess:这里理解成在该组策略中如何判定若干消息归为一组
  • dataProcess:数据的真正处理逻辑

使用多组策略,完成消息处理,核心逻辑如下:

	/**
     * @param datas 待处理的数据集
     * @param level	分级处理标识
     */
   private void datasProcess(List<T> datas, int level) {
   
   		//当未配置该分级策略时,直接不进行处理,分级策略要对于数据封闭
        if (mlcStrategies.size() < (level + 1)) {
   
           throw new RuntimeException("Make sure mlc strategy is data sealed.");
        }
        final MlcStrategy<T> tMlcStrategy = mlcStrategies.get(level);
        //将该组数据中属于分级策略指定的消息分离出
        final List<T> needProcessDatas = datas.stream().filter(p -> tMlcStrategy.shouldProcess().apply(p))
                .collect(Collectors.toList());
 		//并发处理,同时增加栅栏
        CountDownLatch latch = new CountDownLatch(needProcessDatas.size());
        SERIAL_THREAD_EXECUTOR.setLatch(latch);
        for (T data : needProcessDatas) {
   
            final Integer shardKey = tMlcStrategy.shardKey().apply(data);
            System.out.println("shard key:" + shardKey);
            SERIAL_THREAD_EXECUTOR.execute(String.valueOf(shardKey), () -> {
   
                tMlcStrategy.dataProcess().accept(data);
            });
        }
        //保证上组消息全部完(剩余消息串行进行下一轮分组处理)
        SERIAL_THREAD_EXECUTOR.await();
        datas.removeAll(needProcessDatas);
        if (!datas.isEmpty()) {
   
            level += 1;
            datasProcess(datas, level);
        }
    }

如上代码,很明显用到了递归,支持无限分级。

四、保序并发处理

针对批量消息的单纯并发处理,使用线程程即可。但如上的每组消息中并发依旧也是有条件的,举个实际例子,如一组链路消息,要求同一条正反链路是严格串行的,所以不能单独地针对这组消息进行并发。这里可以采用hash的方法,将链路的源宿端口求和后进行hashcode,这样保证正反链路进到同一个队列,背后使用单线程,则可以保序。如下红框标识的示意图:
在这里插入图片描述
但上述实现,需要自己创建线程,并进行线程的管理,能否复用现有的JDK线程池框架?从上面的实现中看到了SERIAL_THREAD_EXECUTOR变量,类型BalanceSerialThreadExecutor

	final SerialThreadExecutor<String> SERIAL_THREAD_EXECUTOR = buildSerialThreadExecutor();
    private SerialThreadExecutor<String> buildSerialThreadExecutor() {
   
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("xlevel-%d"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值