2011-10-24 4 views
1

프로젝트에서 내가 대기중인 큐가 너무 커서 정상 메모리를 유지할 수 없습니다. 나는 전체 파일을 처음 몇 줄 (~ 100) 줄을 읽고, 처리 한 다음, 새 지침을 추가하고 오래된 명령을 제거하여 업데이트 된 큐를 다시 작성하는 간단한 파일로 구현했습니다. 그러나 큐가 너무 커서이 메모리를 유지할 수 없기 때문에 나는 다른 것을 필요로합니다. 가급적이면 누군가가 나머지 데이터를 보지 않고도 파일의 처음 몇 줄만 떼어내는 방법을 말해 줄 수 있습니다. 나는 데이터베이스 (정렬 된 타임 스탬프를 가진 MySQL)를 사용하는 것에 대해 생각해 봤지만, 부하 및 대역폭의 이유없이 (여러 서버가 모두 DB에서 많은 양의 데이터를 전송하고 수신해야 함)이를 수행하는 것을 선호했다. 제가 일하고있는 언어는 PHP지만, 정말로이 질문은 유닉스 파일에 대한 것입니다. 어떤 도움을 주시면 감사하겠습니다.PHP 큐 파일 구현

+3

"여러 서버가 모두 DB에서 많은 양의 데이터를 보내고 받아야합니다 *"- 정확히 설계된 (최적화 된) 데이터베이스 서버입니다. – qJake

+0

데이터베이스가 처리 할 수 ​​있다는 것을 알고 있지만,이 프로세스가 끊임없이 실행되고 모든 서버간에 데이터를 수집하는 데 필요한 대역폭이 더 걱정됩니다 ... MySQL의 방식은 최후의 수단이지만, 모든 데이터를 볼 필요없이 처음 몇 줄을 지우도록 파일을 업데이트하는 방법을 알고 있습니다. – hackartist

답변

1

파일의 첫 번째 줄을 빠져 나오기는 매우 쉽습니다 (fopen() 다음에 fgets()이옵니다). 완료된 작업을 제거하기 위해 파일을 다시 쓰는 것은 매우 고통 스럽습니다. 특히 여러 개의 동시 서버가 동일한 대기열 파일에서 작동하는 경우에는 더욱 그렇습니다.

한 가지 대안은 각 작업에 대해 별도의 파일을 사용하는 것입니다. 이러한 파일에 대해 증가하는 ID를 생성하는 동시성에 안전한 몇 가지 방법이있는 경우 가장 오래된 작업에 대해 가장 낮은 ID를 가진 파일을 선택하고 각각의 새 작업에 대해 새 ID를 생성하는 것은 간단합니다. 그러나 두 개의 서버가 같은 파일을 동시에 가져 오게하려면 파일 잠금을 알아 내야합니다.

+0

저는 실제로 잠금을 사용하고 있습니다. - 실제로 필요한 것은 이미 실행 된 행 위로 파일의 시작을 나타내는 포인터를 이동시키는 방법입니다. – hackartist

+0

당신은'ftell()'을 사용하여 큐 파일에서 '여기에서 시작'마커의 위치를 ​​얻고 그것을 별도의 파일에 저장할 수 있습니다. 작은 ~ 10byte 파일의 잠금/읽기/업데이트/쓰기/잠금 해제는 매우 빠르며 대기열의 관련 위치로 쉽게 스크롤 할 수 있습니다. –

+0

좋아, 내가 찾고있는 것보다 소리가 난다. 대기열 파일의 실제 크기가 계속 커지기 때문에 한 번에 하나의 메모리 크기의 청크를 비워야한다. – hackartist

0

enqueue/fs 전송 중에 작업하는 동안 동일한 문제가있었습니다. 파일을 구걸 할 때 메모리에 복사하고 다시 저장하지 않고 작은 부분을 수정하지 못했습니다. 대신 파일의 끝 부분에서이를 수행 할 수 있습니다. 부분을 ​​읽고 나서자를 수 있습니다. 그것은 실제로 대기열이 아니라 스택입니다. 따라서 메시지 순서에 의존한다면 이는 해결책이 아닙니다. 필자의 경우 파일에서 파일을 읽을 때 파일을 잠그면 잠금이 해제됩니다.

<?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; 
} 

내가 사용하는 것이 좋습니다하려는 잠금의 경우 :

<?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 

이 당신이 큐 파일에서 메시지를 읽을 수있는 방법입니다 :

는 큐 파일에 메시지를 쓸 수있는 방법입니다 Symfony LockHandler 또는 간단하게 enqueue/fs를 가져옵니다.