1

这是我使用 Oracle 高级队列的第一步...

Szenario:我有一个正在运行的应用程序,其中有很多很多独立的进程向中央控制器报告以处理后续步骤。简化的进程是通过 cron 或刚刚完成的进程的回调启动的。回调来自远程主机通过 http -> php -> DB,基本上是远程主机上进程完成后的一个 http 调用。

完整的控制器逻辑是用 pl/sql 编写的,并考虑了单例概念,因此只有一个进程应该同时执行控制器逻辑。事实上,在 99% 的调用中,这不是必需的,但这不是我目前可以改变的事情(也不是一般的架构)。

为了确保这一点,实际上存在一个错误的互斥锁实现,伪代码


    $mutex = false;

    while( not $mutex )
    {
        $mutex = getMutex();

        if( $mutex )
            executeController();
        else
            sleep(5);
    }

其中互斥锁是一个字段表,其值为 0 (=> "free") 或 1 ( => "busy" )

这种“美丽”构造的结果是充满“嘿!没有互斥锁!等待......”的日志文件。而且等待的进程越多,它们等待的时间越长,无法控制下一个是谁。有时负载变得如此沉重以至于apache首先分叉并最终死掉......

解决方案

所以我的第一个“操作”是用 Oracle Advanced Queuing 替换互斥锁,控制器作为单一消费者。好处:apache层内不再“忙着等待”,严格先到先得。

(因为所有 DB-Action 都发生在同一个 oracle-schema 中,这可以通过标准对象、pl/sql-methods 来实现。但是,如果有 dbms-packages,为什么要重新发明轮子呢?)

据我所知,在这种情况下使用监听功能(轮询排队的项目)比注册功能(在消息到达时安排动作)要好得多。

基本上一切正常,我设法:

  • 创建消息类型
  • 创建队列表
  • 创建队列
  • 开始排队
  • 将 USER 添加为订阅者
  • 创建入队过程
  • 创建处理和出队的过程
  • 创建一个用于侦听队列并在消息到达时调用“process & dequeue”函数的过程。

当然,监听器应该 24/7 都处于活动状态,所以我没有指定“等待”时间。一般来说,根据一天中的时间,他至少每隔几分钟就会有“要做的事情”,更有可能每隔几秒钟,有时甚至更多。

现在这是我的问题(如果它确实是一个问题),我只是根据我目前找到的示例编写它:


    CREATE OR REPLACE PROCEDURE demo_aq_listener IS
            qlist       dbms_aq.aq$_agent_list_t;
            agent_w_msg sys.aq$_agent;
        BEGIN
            qlist(0) := sys.aq$_agent(USER, 'demo_aq_queue', NULL);
        LOOP
            dbms_aq.listen(agent_list => qlist, agent => agent_w_msg);                  
            DEMO_AQ_DEQUEUE();--process & dequeue
        END LOOP;
    END;
    /

调用该过程基本上符合我的预期:它保持“启动”并处理排队的消息。

但这是做到这一点的方法吗?如果没有排队的消息,它会做什么?dbms_aq.listen -routine中的“睡眠”或“尽可能快地循环”,这样我就实现了另一种“忙于等待”的方式?可能有一个超时(可能在 oss 级别或其他地方)我只是没有达到?

这是队列定义等的完整代码:demo_dbms_aq_with_listener.sql

更新

通过进一步的测试,我才意识到,我似乎比我希望的更缺乏理解:(

在“执行级别”根本不使用侦听器,只是循环出队函数具有相同的效果:它等待第一条/下一条消息


    CREATE OR REPLACE PROCEDURE demo_aq_listener IS
    BEGIN
    LOOP
        DEMO_AQ_DEQUEUE();
    END LOOP;
END; /

至少这更容易测试,只调用


    BEGIN
        DEMO_AQ_DEQUEUE();
    END;
    /

也只是等待第一条消息。这让我完全困惑我是否需要听众,如果我正在做的事情确实有任何意义:(

结论

我根本不需要监听器,因为我有一个消费者可以以同样的方式处理所有消息。

但是关键/核心问题保持不变:是否可以将 DBMS_AQ.DEQUEUE 保持在“可能处于活动状态”的循环中,知道它会在很短的时间间隔内整天收到消息

(你会在上面链接的 sql 文件中找到 DEMO_AQ_DEQUEUE())

4

1 回答 1

0

迟到总比没有好,一切都好,就是闲着等待:

1)虽然DEQUEUE处于睡眠模式(WAIT FOREVER),我可以看到会话正在等待事件-“Streams AQ:等待队列中的消息”,这是一个空闲等待类,实际上不消耗任何资源,正确的 ?

正确的。这类似于等待表上的行锁。你只是“坐在那里”

https://asktom.oracle.com/pls/apex/asktom.search?tag=writing-a-stand-alone-application-to-continuously-monitor-a-database-queue-aq

于 2019-05-15T22:21:22.397 回答