PHP队列文件实现

时间:2011-10-24 19:28:03

标签: php file unix memory queue

对于我正在进行的项目,我需要一个太大而无法保存在正常内存中的队列。我一直在将它实现为一个简单的文件,它将读取整个文件的前几行(~100),处理它们,然后写回更新的队列,添加新的指令并删除旧的指令。但是,由于队列变得太大而无法保存在内存中,我需要一些不同的东西。有人可以告诉我一种方法,只需要剥离文件的前几行,而不必查看其余的数据。我曾考虑过使用数据库(MySQL可能带有已排序的插入时间戳)但我更倾向于在没有负载和带宽原因的情况下这样做(多个服务器都必须从数据库发送和接收大量数据)。我正在使用的语言是PHP,但实际上这个问题更多的是关于我认为的unix文件。任何帮助,将不胜感激。

2 个答案:

答案 0 :(得分:1)

取出文件的第一行非常简单(fopen()后跟fgets())。重写文件以删除已完成的作业将非常痛苦,特别是如果您有多个并发服务器在同一队列文件中工作。

一种替代方法是为每个作业使用单独的文件。如果您有一些为这些文件生成递增ID的并发安全方法,那么选择具有最旧作业的最低ID的文件并为每个新作业生成新ID将是一件简单的事情。但是,你必须弄清楚一些文件锁定,以保持两个+服务器同时抓取同一个文件。

答案 1 :(得分:0)

我在enqueue/fs运输工作时遇到了同样的问题。我没有在文件的乞讨中修改一小部分而没有将其复制到内存并保存。相反,但是可以在文件末尾执行此操作。您可以读取一部分然后截断它。那不是一个队列,而是一个堆栈。因此,如果您依赖于消息排序,这将不是一个解决方案。在我的情况下,我从文件中读取文件后锁定文件,锁定被释放。

这是您可以将消息写入队列文件的方法:

<?php
$rawMessage = 'this your message to put to the queue as a string';

$queueFile = fopen('/path/to/queue/file', '+a');

// here it may add some spaces so the message length is multiples of modular.
// that make it easier to read messages from a file.

// lock file

$rawMessage = str_repeat(' ', 64 - (strlen($rawMessage) % 64)).$rawMessage;
fwrite($queueFile, $rawMessage);

// release lock

这是您从队列文件中读取消息的方法:

<?php

$queueFile = fopen('/path/to/queue/file', '+c');

// lock file

$frame = readFrame($file, 1);
ftruncate($file, fstat($file)['size'] - strlen($frame));
rewind($file);
$rawMessage = substr(trim($frame), 1);

// release lock


function readFrame($file, $frameNumber)
{
    $frameSize = 64;
    $offset = $frameNumber * $frameSize;
    fseek($file, -$offset, SEEK_END);
    $frame = fread($file, $frameSize);
    if ('' == $frame) {
        return '';
    }
    if (false !== strpos($frame, '|{')) {
        return $frame;
    }
    return readFrame($file, $frameNumber + 1).$frame;
}

对于锁定,我建议使用Symfony LockHandler或简单地使用enqueue / fs。