Gunakan senarai terpaut redis untuk melakukannya, kerana operasi pop adalah atom, walaupun ramai pengguna tiba pada masa yang sama, mereka akan dilaksanakan mengikut turutan, jadi adalah disyorkan.
Langkah pertama ialah meletakkan inventori produk ke dalam baris gilir
/** * 添加商品数量到商品队列 * @param int $couponId 优惠券ID */ function addCoupons($couponId) { //1.初始化Redis连接 $redis = new Redis(); if (!$redis->connect('127.0.0.1', 6379)) { trigger_error('Redis连接出错!!!', E_USER_ERROR); } else { echo '连接正常<br>'; } //根据优惠券ID从数据库中查询该优惠券的库存量 //$sql = "select id, stock from coupon where id = {$couponId}"; $stock = 10; //假设10就是我们从数据库中查询出的该优惠券在数据库中的库存量 //我们现在将这10个库存放入到以该商品ID为key的redis链表中,有几件库存,就存入多少次1,链表长度代表商品库存数 for($i = 0; $i < $stock; $i++) { $redis->lPush("secKill:".$couponId.":stock", 1); } $redis->close(); } $couponId = 11211; addCoupons($couponId);
Kami memanggil kaedah ini, dan kemudian semak redis, 10 elemen telah ditambahkan pada senarai terpaut
Langkah kedua ialah memulakan jualan tergesa-gesa dan menetapkan kitaran cache inventori
Langkah ini ditentukan mengikut perniagaan anda sendiri. Jika perniagaan menetapkan, kupon ini akan dikeluarkan 2 minit untuk direbut oleh pengguna, kemudian gunakan kaedah expire()
untuk menetapkan tempoh sah untuk senarai pautan Walaupun tidak habis dijual dalam tempoh sah dan masih ada stok , pengguna tidak akan dibenarkan untuk merebutnya (memandangkan perniagaan syarikat kami tidak menetapkan tempoh sah untuk merebut kupon, jadi ini saya tidak perlu melakukan langkah ini)
//设置链表有效期是两分钟 $redis->expire('key', 120);
Langkah ketiga ialah melaksanakan operasi snap-up segera pada klien
/** * 抢优惠券(秒杀) * @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>'; } //将已经成功抢购的用户添加到该以该商品ID为key的集合(set)中 //如果用户已经在集合中,说明用户已经成功秒杀过一次了,不允许再次参与秒杀 if ($redis->sIsMember('secKill:'.$couponId.':uid', $uid)) { echo '秒杀失败'; return false; } //秒杀商品的库存key $key = 'secKill:'.$couponId.':stock'; //从以该优惠券ID为key的链表中弹出一个值,如果有值,证明优惠券还有库存 $isSockNotEmpty = $redis->lPop($key); //判断库存,如果库存大于0,则减库存,将该成功秒杀用户加入哈希表,如果小于等于0,秒杀结束 if ($isSockNotEmpty != 1) { echo '秒杀已结束'; return false; } //抢券成功,将优惠券ID和UID放入到队列中,由一个单独的进程队列来消费队列里的数据,向用户推送抢到的优惠券 $redis->lPush('couponOrder', $couponId.'+'.$uid); //将成功抢券的用户记录到集合中,防止被已抢过的用户再次秒杀 $redis->sAdd('secKill:'.$couponId.':uid', $uid); $redis->close(); return true; } $couponId = 11211; $uid = mt_rand(1, 100); secKill($couponId, $uid);
Langkah keempat ialah memasukkan pengguna pembunuhan segera yang berjaya ke dalam pangkalan data untuk mengekalkan data Jumlah konkurensi tidak terlalu tinggi tulis maklumat ke pangkalan data selepas pembelian yang berjaya dalam langkah ketiga Untuk konkurensi yang besar, kami boleh memasukkannya ke dalam baris gilir mesej RabbitMQ untuk penggunaan (adalah disyorkan untuk menggunakan baris gilir RabbitMQ dan bukannya redis kerana RabbitMQ boleh menjamin penghantaran mesej 100%. . digunakan, dan redis agak kurang stabil dan boleh dipercayai)
//此处代码省略 //根据自己的业务场景看看是入数据库还是放入rabbitMQ消息队列中消费
Sekarang kami menggunakan alat ab untuk mensimulasikan tingkah laku merebut kupon di bawah konkurensi tinggi (2000 permintaan, 100 serentak)
ab -n 2000 -c 100 www.test.com/
Kemudian kami menggunakan Redis Desktop Manager untuk melihat keputusan Redis
Begitu juga, sudah ada 10 maklumat yang mengandungi uid pengguna dan id kupon dalam baris gilir couponOrder, yang boleh digunakan oleh baris gilir.
Pada masa yang sama, maklumat UID 10 pengguna juga disimpan dalam koleksi kupon pengguna.
Atas ialah kandungan terperinci Cara menggunakan senarai pautan Redis untuk menyelesaikan masalah produk terlebih jual dengan konkurensi yang tinggi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!