특정 수의 사용자를 보유한 일부 전자상거래 웹사이트의 경우 단순히 관계형 데이터베이스(예: 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 '连接正常<br>'; } //秒杀商品的库存key $key = 'secKill:'.$couponId.':stock'; $redis->watch($key); //获取库存 $stock = $redis->get($key); //秒杀未开始,表示库存为null if (!$stock && !is_numeric($stock)) { echo '秒杀未开始'; return false; } //判断库存,如果库存大于0,则减库存,将该成功秒杀用户加入哈希表,如果小于等于0,秒杀结束 if ($stock <= 0) { echo '秒杀已结束'; return false; } //用户已经成功秒杀过一次了,不允许再次参与秒杀 if ($redis->sIsMember('secKill:'.$couponId.':uid', $uid)) { echo '秒杀失败'; return false; } //代码走到这里,说明该用户是第一次参与秒杀,将库存减一,然后把这个人放到已抢到的集合表 $redisMulti = $redis->multi(); $redisMulti->decr($key); $redisMulti->sAdd('secKill:'.$couponId.':uid', $uid); $result = $redisMulti->exec(); if (empty($result)) {//事务被取消 echo '秒杀失败'; return false; } //抢券成功,将优惠券ID和UID放入到队列中,由一个单独的进程队列来消费队列里的数据,向用户推送抢到的优惠券 $redis->lPush('couponOrder', $couponId.'+'.$uid); return true; } $couponId = 11211; $uid = mt_rand(1, 100); secKill($couponId, $uid);
먼저 시뮬레이션했습니다. 쿠폰 ID가 11211인 쿠폰 인벤토리를 10으로 설정합니다.
그런 다음 ab 도구를 사용하여 1000개의 요청과 50개의 동시성을 테스트하여 시뮬레이션합니다
ab -n 1000 -c 50 www.test.com/
그런 다음 Redis Desktop Manager를 사용하여 일부 Redis 결과를 봅니다
couponOrder 대기열에 이미 10개의 사용자 정보가 있습니다
그리고 남은 쿠폰 개수도 0이 되어 더 이상 음수가 아닙니다
동시에 사용자 10명의 UID 정보도 사용자 쿠폰 컬렉션에 저장됩니다.
위 코드는 두 가지 문제를 해결합니다.
데이터베이스에 대한 많은 수의 즉각적인 쿼리 문제를 해결하여 데이터베이스에 많은 부담을 줍니다. 트래픽이 Redis 캐시 계층에서 차단됩니다.
과잉 재고로 인해 쿠폰이 급등하는 문제를 해결했습니다.
그러나 이 코드에도 특정 문제가 있습니다.
은 Redis 연결 풀을 사용하지 않으며 새 Redis를 자주 생성하면 성능에 특정 영향을 미칩니다
트랜잭션 사용으로 인해 각 동시 요청에서 한 명의 사용자만 쿠폰 획득에 성공합니다. 동시 요청의 다른 사용자는 실패하고 두 번째 동시 요청만 기다릴 수 있습니다.
또한 트랜잭션으로 인한 인벤토리 유산입니다. .제품 10개, 요청 1000개, 동시 200개 동시 요청이 5개이면 1000개 요청이 완료되지만, 후속 요청이 없으면 인벤토리에 5개 사본만 남게 됩니다.
위 내용은 높은 동시성에서 제품 과잉 판매 문제를 해결하기 위해 PHP+Redis를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!