>  기사  >  데이터 베이스  >  높은 동시성에서 제품 과잉 판매 문제를 해결하기 위해 PHP+Redis를 사용하는 방법

높은 동시성에서 제품 과잉 판매 문제를 해결하기 위해 PHP+Redis를 사용하는 방법

WBOY
WBOY앞으로
2023-05-26 15:31:061749검색

특정 수의 사용자를 보유한 일부 전자상거래 웹사이트의 경우 단순히 관계형 데이터베이스(예: MySQL, Oracle)를 사용하여 급하게 구매하는 경우 데이터베이스에 대한 부담이 매우 클 것이며 데이터베이스 잠금 메커니즘을 사용하지 않는 경우 글쎄요, 그러면 과매도된 상품이나 쿠폰의 문제도 발생할 것입니다. 저희 회사에서도 같은 문제가 발생했는데, 쿠폰을 과다 구매했을 때 문제가 발생했는데, 문제가 발생한 후 해결 방법을 고민하기 시작했습니다. 저는 Redis를 많이 사용하기 때문에 이 문제를 해결하기 위해 Redis를 사용할 예정입니다. . Redis의 고성능 및 트랜잭션 기능을 사용하여 과잉 재고로 인해 온라인 쿠폰이 급등하는 문제를 해결합니다. 아래에서는 일부 세부 정보를 제거하고 이 문제를 일시적으로 해결한 의사 코드의 첫 번째 버전을 제공합니다.

/**
 * 抢优惠券(秒杀)
 * @param int $couponId 商品ID
 * @param int $uid 用户ID
 * @return bool
 */
function secKill($couponId, $uid)
{
    //1.初始化Redis连接
    $redis = new Redis();
    if (!$redis->connect('127.0.0.1', 6379)) {
        trigger_error('Redis连接出错!!!', E_USER_ERROR);
    } else {
        echo &#39;连接正常<br>&#39;;
    }

    //秒杀商品的库存key
    $key = &#39;secKill:&#39;.$couponId.&#39;:stock&#39;;
    $redis->watch($key);

    //获取库存
    $stock = $redis->get($key);

    //秒杀未开始,表示库存为null
    if (!$stock && !is_numeric($stock)) {
        echo &#39;秒杀未开始&#39;;
        return false;
    }

    //判断库存,如果库存大于0,则减库存,将该成功秒杀用户加入哈希表,如果小于等于0,秒杀结束
    if ($stock <= 0) {
        echo &#39;秒杀已结束&#39;;
        return false;
    }

    //用户已经成功秒杀过一次了,不允许再次参与秒杀
    if ($redis->sIsMember(&#39;secKill:&#39;.$couponId.&#39;:uid&#39;, $uid)) {
        echo &#39;秒杀失败&#39;;
        return false;
    }

    //代码走到这里,说明该用户是第一次参与秒杀,将库存减一,然后把这个人放到已抢到的集合表
    $redisMulti = $redis->multi();
    $redisMulti->decr($key);
    $redisMulti->sAdd(&#39;secKill:&#39;.$couponId.&#39;:uid&#39;, $uid);
    $result = $redisMulti->exec();

    if (empty($result)) {//事务被取消
        echo &#39;秒杀失败&#39;;
        return false;
    }

    //抢券成功,将优惠券ID和UID放入到队列中,由一个单独的进程队列来消费队列里的数据,向用户推送抢到的优惠券
    $redis->lPush(&#39;couponOrder&#39;, $couponId.&#39;+&#39;.$uid);

    return true;
}

$couponId = 11211;
$uid      = mt_rand(1, 100);
secKill($couponId, $uid);

먼저 시뮬레이션했습니다. 쿠폰 ID가 11211인 쿠폰 인벤토리를 10으로 설정합니다.

높은 동시성에서 제품 과잉 판매 문제를 해결하기 위해 PHP+Redis를 사용하는 방법

그런 다음 ab 도구를 사용하여 1000개의 요청과 50개의 동시성을 테스트하여 시뮬레이션합니다

ab -n 1000 -c 50 www.test.com/

그런 다음 Redis Desktop Manager를 사용하여 일부 Redis 결과를 봅니다

couponOrder 대기열에 이미 10개의 사용자 정보가 있습니다

높은 동시성에서 제품 과잉 판매 문제를 해결하기 위해 PHP+Redis를 사용하는 방법

그리고 남은 쿠폰 개수도 0이 되어 더 이상 음수가 아닙니다

높은 동시성에서 제품 과잉 판매 문제를 해결하기 위해 PHP+Redis를 사용하는 방법

동시에 사용자 10명의 UID 정보도 사용자 쿠폰 컬렉션에 저장됩니다.

높은 동시성에서 제품 과잉 판매 문제를 해결하기 위해 PHP+Redis를 사용하는 방법

위 코드는 두 가지 문제를 해결합니다.

  • 데이터베이스에 대한 많은 수의 즉각적인 쿼리 문제를 해결하여 데이터베이스에 많은 부담을 줍니다. 트래픽이 Redis 캐시 계층에서 차단됩니다.

  • 과잉 재고로 인해 쿠폰이 급등하는 문제를 해결했습니다.

그러나 이 코드에도 특정 문제가 있습니다.

  1. 은 Redis 연결 풀을 사용하지 않으며 새 Redis를 자주 생성하면 성능에 특정 영향을 미칩니다

  2. 트랜잭션 사용으로 인해 각 동시 요청에서 한 명의 사용자만 쿠폰 획득에 성공합니다. 동시 요청의 다른 사용자는 실패하고 두 번째 동시 요청만 기다릴 수 있습니다.

  3. 또한 트랜잭션으로 인한 인벤토리 유산입니다. .제품 10개, 요청 1000개, 동시 200개 동시 요청이 5개이면 1000개 요청이 완료되지만, 후속 요청이 없으면 인벤토리에 5개 사본만 남게 됩니다.

  4. 팁: 소비 대기열에서 쿠폰이 발급되지 않으면 즉시 기록하고 문자 메시지를 통해 운영 관리자에게 알리고 백그라운드를 통해 사용자에게 다시 보내거나 수동으로 푸시할 수 있는지 확인하세요.

위 내용은 높은 동시성에서 제품 과잉 판매 문제를 해결하기 위해 PHP+Redis를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제