2013-09-23 2 views
4

나는 내 사이트의 일부를 관계형 데이터베이스에서 Redis로 옮기고 있으며 짧은 시간 내에 수십억 개의 키를 삽입해야합니다.phpredis 파이프 라인은 대량 삽입 프로토콜을 사용하는 것과 같은가요?

필자의 경우 데이터는 MySQL에서 먼저 가져 와서 PHP로 준비한 다음 해당 정렬 된 집합에 추가해야합니다 (시간은 점수 + ID 값으로 사용). 현재 Redis::PIPELINE 매개 변수를 사용하여 phpredis 멀티 메소드의 모험을하고 있습니다. 눈에 띄는 속도 향상에도 불구하고 가져 오기를 수행하는 동안 읽기를 차단하고로드 시간을 늦추는 것으로 나타났습니다.

은 phpredis에서 파이프 라인을 사용하고 있습니다.http://redis.io/topics/mass-insert에 설명되어 있습니다.

<?php 

// All necessary requires etc. 
$client = Redis::getClient();  

$client->multi(Redis::PIPELINE); // OR $client->pipeline(); 
$client->zAdd('key', 1, 2); 
... 
$client->zAdd('key', 1000, 2000); 
$client->exec(); 
  • redis.io에서 프로토콜대 :

    cat data.txt | redis-cli --pipe 
    
    • 방법을 phpredis : 여기

      은 예입니다

    답변

    7

    나는 phpredis의 공헌자 중 한 명입니다. 짧은 대답은 그것이 동일하지 않다는 것이지만 좀 더 자세하게 설명 할 것입니다.

    phpredis를 Redis::PIPELINE 모드로 전환하면 호출 될 때 명령을 보내는 대신 "보내질"명령 목록에 넣습니다. 그런 다음 exec()을 호출하면 커맨드가 모두 포함 된 커다란 커맨드 버퍼가 작성되어 Redis로 전송됩니다.

    명령이 모두 전송 된 후 phpredis는 각 답장을 읽고 각 명령 사양에 따라 결과를 패키징합니다 (예 : HMGET 호출이 연관 배열 등으로 돌아옴).


    phpredis의 파이프 라이닝 성능은 실제로 매우 우수하며 거의 모든 유스 케이스에 충분합니다. 즉, PHP를 통해 모든 명령을 처리하고 있으므로 모든 명령에 대해 phpredis 확장 자체를 호출하여 함수 호출 오버 헤드를 지불해야합니다. 또한 phpredis는 각 회신을 처리하고 서식을 지정하는 데 시간을 할애 할 것입니다.

    대용량 데이터를 Redis로 가져와야하는 경우, 특히 각 답장을 처리 할 필요가없고 (모든 명령이 처리되었음을 알고 싶을뿐 아니라) 대용량 가져 오기 방법이 잘 했어.

    은 실제로 여기에이 작업을 수행 할 프로젝트를 만들었습니다 https://github.com/michael-grunder/redismi

    이 확장 뒤에 아이디어는 당신이 당신의 명령을 호출 한 다음 날 레디 스에있을 것입니다 디스크에 버퍼를 저장한다는 것입니다 프로토콜 및 cat buffer.txt | redis-cli --pipe 스타일 삽입과 호환됩니다.

    한가지주의해야 할 점은 현재 주어진 phpredis 호출을 RedisMI 객체 호출로 대체 할 수 없다는 것입니다. 명령은 hiredis와 같은 가변 인자 호출로 처리되기 때문에 대부분은 작동하지만 그렇지 않습니다. 모든 phpredis 명령.

    <?php 
    $obj_mi = new RedisMI(); 
    
    // Some context we can pass around in RedisMI for whatever we want 
    $obj_context = new StdClass(); 
    $obj_context->session_id = "some-session-id"; 
    
    // Attach this context to the RedisMI object 
    $obj_mi->SetInfo($obj_context); 
    
    // Set a callback when a buffer is saved 
    $obj_mi->SaveCallback(
        function($obj_mi, $str_filename, $i_cmd_count) { 
         // Output our context info we attached 
         $obj_context = $obj_mi->GetInfo(); 
         echo "session id: " . $obj_context->session_id . "\n"; 
    
         // Output the filename and how many commands were sent 
         echo "buffer file: " . $str_filename . "\n"; 
         echo "commands : " . $i_cmd_count . "\n"; 
        } 
    ); 
    
    // A thousand SADD commands, adding three members each time 
    for($i=0;$i<1000;$i++) { 
        $obj_mi->sadd('some-set', "$i-one", "$i-two", "$i-three"); 
    } 
    
    // A thousand ZADD commands 
    for($i=0;$i<1000;$i++) { 
        $obj_mi->zadd('some-zset', $i, "member-$i"); 
    } 
    
    // Save the buffer 
    $obj_mi->SaveBuffer('test.buf'); 
    ?> 
    

    그런 다음이 같은 작업을 수행 할 수 있습니다 :

    ➜ tredismi php mi.php 
    session id: some-session-id 
    buffer file: test.buf 
    commands : 2000 
    ➜ tredismi cat test.buf|redis-cli --pipe 
    All data transferred. Waiting for the last reply... 
    Last reply received from server. 
    errors: 0, replies: 2000 
    

    건배

    여기 당신이 그것을 사용하는 방법의 간단한 예입니다!

    +0

    답변 해 주셔서 감사합니다. DB에서 2 천만 행을 처리하고 트랜잭션을 사용하여 약 2,5M 키를 저장합니다. 그러나 redis는 단순히 놀랍고 스택에 큰 차이를 만들었으므로 앞으로는 확실히 솔루션을 시험해 보겠습니다. – pwkc

    관련 문제