2017-03-07 5 views
1

PHP로 복권 프로그램을 작성하고 있습니다.이 프로그램에 대한 대규모 동시 요청이 있기 때문에이 예에서는 각 상금의 수가 제한되어 있습니다. 나는 어떤 상금이 주식을 초과하는 것을보고 싶지 않다. 그래서 나는 전체 로직을 Redis 트랜잭션 (나는 PHP redis 클라이언트로 predis (https://github.com/nrk/predis) 사용)에 넣었지만이 프로그램에 대한 10 배 이상의 요청 후에 데이터베이스에서 10 개 이상의 레코드를 발견했다. 나는 이해할 수 없었다. 이유를 아는 사람은 누구입니까? 귀하의 설명에 매우 감사드립니다, 감사합니다!Redis의 트랜잭션에서 캐시 된 데이터를 가져올 수없는 이유는 무엇입니까?

$this->load->model('Lottery_model'); 
$money = $this->_get_lottery();//which prize do you get 
if($money > 0){ 
    $key = $this->_get_sum_key($money); 
    $dbmodel = $this->Lottery_model; 
    // Executes a transaction inside the given callable block: 
    $responses = $redis->transaction(function ($tx) use ($key, $money, $dbmodel){ 
     $qty = intval($tx->get($key)); 
     if($qty < 10){ 
      //not exceed the stock limit 
      $dbmodel->add($customer, $money); // insert record into db 
      $tx->incr($key); 
     }else{ 
      log_message('debug', $money . ' dollar exceed the limit'); 
     } 
    }); 
    }else{ 
     log_message('debug', 'you are fail'); 
    } 

레디 스의 거래에 대한 문서를 읽은 후, 나는 위의 코드의 사용이 완전히 잘못 알고

여기 내 PHP 코드입니다. 낙관적 인 잠금 및 체크 - 앤 - 세트를 사용하여 버전을 수정했습니다.

$options = array(
    'cas' => true,  // Initialize with support for CAS operations 
    'watch' => $key, // Key that needs to be WATCHed to detect changes 
    'retry' => 3,  
); 
try{ 
    $responses = $redis->transaction($options, function ($tx) use ($key, $money, $username, $dbmodel, &$qty){ 
    $qty = intval($tx->get($key)); 
    if($qty < 10){ 
     $tx->multi(); 
     $tx->incr($key); 
     $dbmodel->add($username, $money);// insert into mysql db 
    }else{ 
     log_message('debug', $money . ' dollar exceed the limit'); 
    } 
}); 
}catch(PredisException $e){ 
    log_message('debug', 'redis transaction failed'); 
} 

는 그러나 문제는 데이터베이스에있는 레코드의 수는 상품의 한계를 초과하고, 레디 스에 저장된 총 수는 없을 것입니다. 이런 종류의 문제를 해결하기위한 일반적인 해결책은 무엇입니까? 이 경우 INNodb 테이블을 잠글 수 있습니까?

답변

1

Redis 트랜잭션의 작동 방식을 이해해야합니다. 간단히 말해서 트랜잭션을 작성하는 모든 명령은 클라이언트 (사용자의 경우 predis)에 버퍼링 된 다음 한 번에 모두 서버로 실행됩니다. 트랜잭션이 실행되기 전에 코드가 읽기 요청 (get)의 결과를 사용하려고 시도합니다. https://redis.io/topics/transactions

어느 트랜잭션 외부 qty을 읽고, 경쟁 업데이트에 대한 보호, 또는 루아 스크립트 전체에서이 논리를 이동 WATCH를 사용 : 자세한 내용은 설명서를 참조하십시오.

+0

대단히 감사합니다! 내가 언급 한 문서를 읽었습니다. 지금 Redis 거래가 어떻게 작동하는지 알고 있습니다. 그래서 나는 CAS 솔루션으로 낙관적 인 잠금으로 코드를 변경 했으므로 이제 qty의 가치는 옳았습니다. 마침내 10에 도달했지만 데이터베이스의 레코드는 여전히 10을 훨씬 넘습니다. 왜 그런지 알고 있습니까? –

+0

죄송합니다. 질문을 이해할 수 없습니다. –

+0

죄송합니다. 원래 질문을 소스 코드의 두 번째 버전으로 업데이트했습니다. 새로운 질문이 거기에 있습니다. 고맙습니다! –