java嵌入式持久化消息队列SMQ,改造自FQueue

一、说明


之前项目中一直使用ConcurrentLinkedQueue做为缓冲队列(主要是单个项目内,单条改批量的场景,多个项目间使用的是rocketmq),虽然用着方便但是是纯内存的,

如果项目发生异常崩溃内存队列中的数据就会全部丢失(只能从日志中恢复)。所以一直想找一个简单高效支持持久化的嵌入式消息队列。中间用过activemq的嵌入模式,

虽然是支持持久化了,但是配置起来很繁琐,用起来也不简单,性能相比来说也不太行。后来偶然发现了FQueue

看了看项目源码,纯java编写,总共没几个类。完全可以改造成我想要的 简单高效支持持久化的嵌入式消息队列。目前SMQ的性能禁用内存队列的情况下大概在50w每秒。

二、改造


  1、因为是要做成嵌入式的,所以memcached协议相关的代码都删除了。

  2、预创建文件删除了,还有一些零零碎碎的改动。(好几年了,记不清了)。

  3、相较于原代码,改动最大的就是锁的部分,FQueue 读和写使用的是同一把锁,

我改成了读和写使用不同的锁,只在文件切换的时候使用同一把锁。性能大概提示了百分之20左右(本来就很快,锦上添花)。

  4、添加了内存队列,这个主要解决同一个机器创建了大量队列(上千)时,队列消息消费较快,因为使用了内存映射磁盘(每隔10ms就会调用force()同步磁盘),

频繁操作磁盘导致磁盘io过高的问题。默认情况下队列大小超过50时才会写入持久化队列。可以在项目启动时调用SMQ.setting(String dbPath, int logSize, int memoryQueueSize)

进行设置。

三、使用


1、说明


  目前是集成在我个人的工具类项目中的,已发布到中央仓库。该项目强依赖hutool,算是个人对hutool的个性化的扩展。如果不想依赖该项目,只想单纯的使用SMQ,可以将源码中 cn.sanenen.queue包复制出来,单独使用。

2、maven引用


<!-- https://mvnrepository.com/artifact/cn.sanenen/sun-utils --><dependency><groupId>cn.sanenen</groupId><artifactId>sun-utils</artifactId><version>2.3.1</version></dependency>

3、调用


  SMQ使用时只有三个方法,向队列放入数据、从队列取出数据、获取队列大小(一般只在监控队列是否积压时使用,判断队列是否有数据,使用获取队列数据是否为null进行判断)。

  我一般是写一个单独的类,通过静态方法调用。

/**
 * 本地持久化内存队列
 */publicclass MsgQueue {
    privatestaticfinal String testDataTopic = "testData";

    /**
     * 向队列放入数据,支持多线程。
     */publicstaticvoid putTestData(TestData msg) {
        SMQ.push(testDataTopic, JSON.toJSONString(msg));
    }

    /**
     * 从队列取出数据,支持多线程。
     */publicstatic TestData getTestData() {
        String poll = SMQ.pop(testDataTopic);
        if (StrUtil.isNotBlank(poll)) {
            return JSON.parseObject(poll, TestData.class);
        }
        returnnull;
    }

    /**
     * 获取队列大小
     */publicstaticlong getTestDataSize(){
        return SMQ.size(testDataTopic);
    }
}

四、注意事项


  1、默认会在项目目录下生成一个smq的文件夹用来存放队列数据。同一个smq的文件夹同时只可被一个项目使用。

  2、SMQ.setting(String dbPath, int logSize, int memoryQueueSize)

    dbPath文件存储目录,默认是smq(相对路径,也可以使用绝对路径),会在项目目录下创建一个smq的目录。

    logSize数据文件大小,单位是M,最大不可超过2048M,默认是50M。使用过程中最好不要改变该值。

    memoryQueueSize是内存队列大小,默认是50,内存队列数据积压超过memoryQueueSize后才会写入持久化队列。小于0时禁用内存队列。

  3、最好使用在不是要求百分百消息不丢失的场景。(在项目异常停止、服务器停电关机时,有概率丢失消息。)

  4、项目使用了addShutdownHook,会在项目关闭时将内存队列消息写入持久化队列。结束项目时最好使用kill -15 不要用 -9。否则有可能造成消息丢失。同步磁盘时间是10ms。

5、目前已经在生产环境使用两年多。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盈梓的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值