想用队列?但我一个中间件都不想引入:PGMQ 超简单使用

0 阅读3分钟

想用队列?但我一个中间件都不想引入:PGMQ 超简单使用

你有没有这种精神洁癖:
想要“消息队列”的快乐,但不想再引入一个“队列中间件”来占内存、占运维、占你周末?

这时候,PGMQ 就像你家楼下那位“热心但不多话的快递柜”:
你把包裹(消息)放进去,它负责存着;你来取,它负责按规则给你。
不搞花活,不拉群,不开会——主打一个“我在 PostgreSQL 里把队列给你安排了”。

3e3a7cf6d2f668a125054533e48cd589.png

本文基于 PGMQ 的二开开源项目:

并且所有示例代码严格来自该项目 README:

你要的核心卖点:@PgMqListener 一把梭,两种消费模式

这套用法里,最爽的就是:你几乎不用写“队列消费框架代码”。
你只要用 @PgMqListener 标记方法,它就能让你在两种订阅模式里随便切换:

模式subscribeType一句话人话
广播模式BROADCASTING所有消费者都能收到同一条消息(像班级群发通知)
集群模式CLUSTERING一条消息只会分配给一个消费者(像排队取号,谁叫到谁办)

b9ebd4e6-9186-45fb-b4a9-c751664096ee.png

接下来我用“拟人比喻”给你讲清楚:

  • 广播模式:消息像“八卦”,传出去后大家都得知道
  • 集群模式:消息像“外卖订单”,只需要一个人去送,别来一堆骑手围观

广播模式:消息是“全员通知”,每个消费者都要读一遍

想象一下:你在公司群里发了一句“今晚团建自愿参加”。
然后两个同事(listener1、listener2)都看到了——这就是广播。

下面代码严格来自 README(原样照抄):

@Slf4j
@Component
@RequiredArgsConstructor
public class DemoBroadcastingHandler {

    @PgMqListener(subscribeType = SubscribeType.BROADCASTING, bindMsgDto = DemoMsgDto.class)
    public void listener1(DemoMsgDto msg) {
        log.info("广播.listener1: {}", msg);
    }

    @PgMqListener(subscribeType = SubscribeType.BROADCASTING, bindMsgDto = DemoMsgDto.class)
    public void listener2(DemoMsgDto msg) {
        log.info("广播.listener2: {}", msg);
    }
}

看点就三个字:都能收

  • 同一个队列/同一类消息
  • 两个方法都用 @PgMqListener 订阅
  • subscribeType = SubscribeType.BROADCASTING
    结果就是:两位“打工人消费者”都会处理到消息

集群模式:消息是“派单任务”,只要一个消费者处理就行

再想象一下:你点了份外卖。
平台派单时不会把同一单同时派给两个骑手,不然你会收到两份外卖,然后你钱包当场去世。

下面代码同样严格来自 README(原样照抄):

@Slf4j
@Component
@RequiredArgsConstructor
public class DemoClusteringHandler {

    @PgMqListener(subscribeType = SubscribeType.CLUSTERING, bindMsgDto = DemoMsgDto.class)
    public void listener1(DemoMsgDto msg) {
        log.info("集群.listener1: {}", msg);
    }

    @PgMqListener(subscribeType = SubscribeType.CLUSTERING, bindMsgDto = DemoMsgDto.class)
    public void listener2(DemoMsgDto msg) {
        log.info("集群.listener2: {}", msg);
    }
}

这段的精髓也很直白:只给一个人

  • 两个消费者都在“候场”
  • subscribeType = SubscribeType.CLUSTERING 会让消息只分配给其中一个
    结果就是:不会重复消费(至少从模式设计上,就是奔着避免“群殴同一条消息”去的)

你可能会问:我到底该选哪个?

按“人类社会运作方式”来选就行:

  • 选 BROADCASTING:像“发公告”

    • 缓存更新通知
    • 多系统都要同步处理的事件
    • “大家都要知道”的消息
  • 选 CLUSTERING:像“派工单”

    • 发短信/发券这类“发一次就行”的任务
    • 订单处理、异步任务
    • “只要有人做完就行”的消息

(可选)配合 Postgres 镜像启用扩展:把“快递柜”先装上

如果你用的是 supernpc/pgsql:18 这种集成镜像,首次创建数据库需要手动启用扩展(同样来自 README):

CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
CREATE EXTENSION IF NOT EXISTS postgis CASCADE;
CREATE EXTENSION IF NOT EXISTS postgis_topology CASCADE;
CREATE EXTENSION IF NOT EXISTS pg_cron;
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS plpython3u;
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pgmq;

总结:这套玩法为什么很适合懒人(我)

因为你想要的核心其实是:我能不能用最少的心智,把消息消费跑起来?

而这里的答案是:可以。
你只要记住一件事:@PgMqListener + subscribeType

  • BROADCASTING:消息像八卦,大家都要听到
  • CLUSTERING:消息像派单,只给一个人干活

剩下的,就交给 PostgreSQL 和这套二开生态去忙。