>  기사  >  백엔드 개발  >  Redis Flash Sale 이용시 제품 슈퍼 현상을 해결하는 방법은 무엇입니까?

Redis Flash Sale 이용시 제품 슈퍼 현상을 해결하는 방법은 무엇입니까?

WBOY
WBOY원래의
2016-10-17 09:30:081169검색

최근 플래시세일 이벤트를 진행했는데, 성능과 응답속도를 위해 redis를 사용했습니다. 글을 쓸 때 초자연적인 현상을 방지하는 데 특별한 주의를 기울였습니다. Redis 이론을 기반으로 하는 cas(check and set) 낙관적 잠금을 사용하면 이 문제를 해결할 수 있을 것이라고 생각했지만 여전히 매우 혼란스럽습니다. 구체적인 코드는 대략 다음과 같습니다.

<code><?php  
header("content-type:text/html;charset=utf-8");  
$redis = new redis();  
$result = $redis->connect('10.10.10.119', 6379);  
$mywatchkey = $redis->get("mywatchkey");  
$rob_total = 100;   //抢购数量  
if($mywatchkey<$rob_total){  
    $redis->watch("mywatchkey");  
    $redis->multi();  
      
    //设置延迟,方便测试效果。  
    sleep(5);  
    //插入抢购数据  
    $redis->hSet("mywatchlist","user_id_".mt_rand(1, 9999),time());  
    $redis->set("mywatchkey",$mywatchkey+1);  
    $rob_result = $redis->exec();  
    if($rob_result){  
        $mywatchlist = $redis->hGetAll("mywatchlist");  
        echo "抢购成功!<br/>";  
        echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>";  
        echo "用户列表:<pre class="brush:php;toolbar:false">";  
        var_dump($mywatchlist);  
    }else{  
        echo "手气不好,再抢购!";exit;  
    }  
}  
?>  
</code>

답글 내용:

최근 플래시세일 이벤트를 진행했는데, 성능과 응답속도를 위해 redis를 사용했습니다. 글을 쓸 때 초자연적인 현상을 방지하는 데 특별한 주의를 기울였습니다. Redis 이론을 기반으로 하는 cas(check and set) 낙관적 잠금을 사용하면 이 문제를 해결할 수 있을 것이라고 생각했지만 여전히 매우 혼란스럽습니다. 구체적인 코드는 대략 다음과 같습니다.

<code><?php  
header("content-type:text/html;charset=utf-8");  
$redis = new redis();  
$result = $redis->connect('10.10.10.119', 6379);  
$mywatchkey = $redis->get("mywatchkey");  
$rob_total = 100;   //抢购数量  
if($mywatchkey<$rob_total){  
    $redis->watch("mywatchkey");  
    $redis->multi();  
      
    //设置延迟,方便测试效果。  
    sleep(5);  
    //插入抢购数据  
    $redis->hSet("mywatchlist","user_id_".mt_rand(1, 9999),time());  
    $redis->set("mywatchkey",$mywatchkey+1);  
    $rob_result = $redis->exec();  
    if($rob_result){  
        $mywatchlist = $redis->hGetAll("mywatchlist");  
        echo "抢购成功!<br/>";  
        echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>";  
        echo "用户列表:<pre class="brush:php;toolbar:false">";  
        var_dump($mywatchlist);  
    }else{  
        echo "手气不好,再抢购!";exit;  
    }  
}  
?>  
</code>

이 코드는 높은 동시성 조건에서는 여전히 과매도될 것이라고 생각합니다. 상금이 1개만 남았을 때 세 사람이 동시에 $redis->watch("mywatchkey")을 실행하여 얻은 데이터가 99라면 과매도 현상이 발생한다고 가정해 보겠습니다.

redis은 단일 스레드 읽기이므로 가장 간단한 대기열 구현을 사용해 보겠습니다.

  1. 추첨 전 redisqueueaward:100에 경품 개수를 적습니다. // 길이가 100인 목록, 값은 경품 당첨 여부에만 사용됩니다

  2. 동시추첨

<code>$award = $redis->lpop('award:100'); // 由于队列只有100个值,可以确保只有100个人中奖
if(!$award){
    echo "手气不好,再抢购!";exit;  
}

// 剩下就是中奖操作的事情了</code>

sleep(5);
귀사에서는 아직도 인력을 수용하나요?

이런 상황을 생각해 보세요.
mywatchkey=99
사용자 A가 mywatchkey를 요청하고 99를 받았습니다.
사용자 B가 mywatchkey를 요청하고 99를 받았습니다.
A와 B의 요청이 완료되면 mywatchkey는 무엇이어야 합니까? . 101인가요, 100인가요?

이것은 전형적인 확인 후 실행 오류입니다

먼저 이 코드의 "과매도" 결과가 $mywatchkey > 100인지(불가능하다고 생각합니다)
아니면 $mywatchkey =100일 때 동시에 두 페이지가 나오는지 여쭤보겠습니다. "구매 성공!"
이 코드는 테스트해보지 않았으며 다음과 같을지 추측만 했습니다.

1.세션 A: mywatchkey 확인을 수행합니다. 이때 mywatchkey = 99

2.Session B: mywatchkey를 처리한 후 현재 mywatchkey=100이지만 Session A의 후속 작업에는 영향을 미치지 않습니다

두 개의 연결을 더 추가하고 살펴보겠습니다. 뭔가 얻을 수 있습니다

redis의 트랜잭션 및 감시 명령문
redis-watch-multi-exec-by-one-client

이 문제를 근본적으로 해결하고 싶다면 먼저 공부해보세요.

1. 잠금.

2. 기존 데이터베이스 트랜잭션.

그런 다음 Redis와 기존 데이터베이스의 차이점을 알아보세요.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:SQL 다중 조건 쿼리다음 기사:SQL 다중 조건 쿼리