当前位置:网站首页>Redis queue realizes second kill
Redis queue realizes second kill
2022-07-29 02:43:00 【Chenqing Nuo language】
Features of seckill system
1、 The number of people snapping up is far more than the inventory , Read write concurrency is huge .
2、 The stock is low , Write less effectively .
3、 Writing needs strong consistency , Goods cannot be sold beyond .
4、 Reading consistency is not high .
5、 Stability is difficult : High and low , A small dependency may directly cause an avalanche 、 It is difficult to predict the flow accurately , Too high also causes avalanches . Distributed cluster , There are many machines , The probability of failure is high .
6、 Accuracy is difficult : stock 、 Number of successful rush purchases , Create consistency between the number of orders .
7、 High performance difficult : We need to achieve extreme performance at limited cost .
Seckill system —— Principles of Architecture
1、 stability : Reduce third-party dependence , At the same time, its own service deployment also needs to be isolated . Pressure measurement 、 Downgrade 、 Current limiting scheme 、 Ensure that core services are available . Health detection mechanism is needed , The whole link avoids single point .
2、 High performance : Shorten the single request access path , Reduce IO. Reduce the number of interfaces , Reduce data throughput , Fewer requests .
Seckill service core implementation
1、 How to design seckill service : Meet basic needs , Achieve the ultimate performance of single service . Request link traffic optimization , Optimize every layer from client to server . Stability building .
2、 Basic needs : Inventory deduction 、 Check inventory 、 Queue progress .( Achieve the ultimate performance of single service ). Check the order details 、 Create order , Payment order .( The number of people who rush to buy is far more than inventory , Read write concurrency is high )
Basic needs —— Inventory deduction scheme
1、 Order less stock ?
Concurrent request ——> Create order ——> Inventory deduction ——> payment This process will not oversold , But the problem is that if someone places an order maliciously and doesn't pay , Occupy inventory .
2、 Pay less inventory ?
Concurrent request ——> Create order ——> payment ——> Inventory deduction This process is to pay for one-time deduction of inventory , If the user has finished buying the goods , Other users cannot place orders or orders are oversold .
3、 Withholding stock ?
Concurrent request ——> Inventory deduction ——> Create order ——> payment ——>10 Cancel the order without payment within minutes , Add inventory .
It is better to adopt the withholding inventory scheme .
wxml
<view>
<l-countdown time-type="second" time="{
{expire_time}}" bind:linend="changeBtn"/>
<view><image src="{
{Detail.image}}" bindtap="image"></image></view>
<view>{
{Detail.store_product.store_name}}</view>
<view>{
{Detail.price}}</view>
<view>
<l-button disabled="{
{ disabled }}" bind:lintap="buyGoods" type="error" data-id="{
{Detail.id}}"> Kill immediately </l-button>
</view>
</view>js
// pages/Detail/Detail.js
Page({
/**
* Initial data of the page
*/
data: {
expire_time:0,
disabled:false,
expire_time:'',
},
/**
* Life cycle function -- Monitor page loading
*/
onLoad(options) {
let that = this
let sid = options.id
wx.request({
url: 'http://www.wej.com/index.php/api/seckill/goodsDetail', // Just for the sample , Not a real interface address
data: {
sid
},
header: {
'content-type': 'application/json' // The default value is
},
success (res) {
console.log(res.data)
let newdate = Math.round(new Date().getTime() / 1000).toString()
let expire_time = res.data.data.start_time - newdate
console.log(expire_time)
that.setData({
Detail:res.data.data,
expire_time:expire_time
})
if(expire_time > 0){
that.setData({
disabled:true
})
}else{
that.setData({
disabled:false
})
}
}
})
},
buyGoods(c){
clearTimeout(this.TimeID);
this.TimeID = setTimeout(() => {
let goods_id = c.currentTarget.dataset.id
wx.request({
url: 'http://www.wej.com/index.php/api/seckill/snap_up', // Just for the sample , Not a real interface address
data: {
goods_id
},
header: {
'content-type': 'application/json' // The default value is
},
success (res) {
console.log(res.data)
}
})
}, 1000);
},
changeBtn(){
console.log(' The second kill begins ')
this.setData({
disabled:false
})
},
image(c){
wx.previewImage({
current: this.data.Detail.image, // The http link
urls: [this.data.Detail.image] // Pictures that need to be previewed http Link list
})
},
})json
{
"usingComponents": {
"l-countdown":"/dist/countdown",
"l-button":"/dist/button"
}
}<?php
namespace App\Http\Controllers;
use App\Models\AddressInfo;
use App\Models\StoreOrder;
use App\Server\Snowflake;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
class Seckill extends Controller
{
/**
* Data preheating
* @return \Illuminate\Http\JsonResponse
*/
public function activity()
{
$result = \App\Models\Seckill::with('StoreProduct')
->get()->toArray();
foreach ($result as $val){
// Generate the corresponding commodity inventory queue
$goods = "activity_goods_".$val['product_id'];
for ($i=0; $i < $val['stock']; $i++) {
Redis::lpush($goods,1);
}
}
return response()->json(['code' => 20000, 'msg' => ' The query is successful ', 'data' => $result]);
}
/**、
* Second kill list
* @return \Illuminate\Http\JsonResponse
*/
public function activityList()
{
$result = \App\Models\Seckill::with('StoreProduct')
->get()->toArray();
return response()->json(['code' => 20000, 'msg' => ' The query is successful ', 'data' => $result]);
}
/**
* Second kill product details
* @return \Illuminate\Http\JsonResponse
*/
public function goodsDetail()
{
$goods_id = request()->get('sid');
$result = \App\Models\Seckill::with(['StoreProduct'])
->where('product_id',$goods_id)
->first();
return response()->json(['code' => 20000, 'data' => $result, 'msg' => ' The query is successful ']);
}
/**
* Verify inventory
* @return \Illuminate\Http\JsonResponse
*/
public function snap_up(){
// user ID
$userID = 1;
// goods ID
$goodsID = request()->get('goods_id');
// Corresponding commodity inventory queue
$goods = "activity_goods_".$goodsID;
// Set of users who have successfully snapped up corresponding products {1,3,4}
$robSuccessUser = "success_user".$goodsID;
// Judge whether the current user is in the queue of successful robbery
$result = Redis::sismember($robSuccessUser,$userID);
// If you're in here , It's over
if ($result) {
// If the rush is successful Return status code , Place an order
return response()->json(['code' => 20000, 'data' => '', 'msg' => ' It has been snapped up ']);
}
// Reduce inventory , Turn the data in the queue from the left head
$count = Redis::lpop($goods);
if (!$count) {
// If the rush is successful Return status code , Place an order
return response()->json(['code' => 20001, 'data' => '', 'msg' => ' It's all gone ']);
}
// Put the current spike uid Store it in the queue of successful rush purchase set
$success = Redis::sadd($robSuccessUser, $userID);
if(!$success){
// Already in the success queue , Add back inventory , To prevent concurrent requests from the same user
Redis::lpush($goods, 1);
// If the rush is successful Return status code , Place an order
return response()->json(['code' => 20002, 'data' => '', 'msg' => ' It has been snapped up ']);
}
// If the rush is successful Return status code , Place an order
return response()->json(['code' => 20000, 'data' => '', 'msg' => ' Seckill success ']);
}
/**
* Generate order
* @return false|\Illuminate\Http\JsonResponse|string
*/
public function createOrder(){
// user ID
$userID = request()->get('userID');
// goods ID
$goodsID = request()->get('goods_id');
// Address ID
$address_id = request()->get('address_id');
// Set of users who have successfully snapped up corresponding products
$robSuccessUser = "success_user".$goodsID;
// Judge whether the current user is in the queue of successful robbery
$result = Redis::sismember($robSuccessUser,$userID);
// If you're in here , It's over
if (!$result) {
// If the rush is successful Return status code , Place an order
return response()->json(['code' => 20003, 'data' => '', 'msg' => ' Hands slow !']);
}
DB::beginTransaction();
try{
// Reduce inventory
$shopData = \App\Models\Seckill::with('StoreProduct')
->where('product_id',$goodsID)
->first()->toArray();
$shopStock = \App\Models\Seckill::where('product_id',$goodsID)->update(['stock' => $shopData['stock'] - 1]);
if (!$shopStock) return json_encode(['code' => 50000,'msg' => ' Order failure ','data' => []]);
// Address
$address_info = AddressInfo::find($address_id)->toArray();
// Generate order
Snowflake::machineId($userID);
$order_id = substr(date('Ymd'),2).'-'.Snowflake::createOnlyId();
$data = [
'order_id' => $order_id,
'uid' => $userID,
'real_name' => $address_info['real_name'],
'user_phone' => $address_info['phone'],
'user_address' => $address_info['detail'],
'pay_price' => $shopData['store_product']['price'],
'pay_time' => time()
];
$orderAdd = StoreOrder::insert($data);
if (!$orderAdd) return json_encode(['code' => 50000,'msg' => ' Order failure ','data' => []]);
DB::commit();
// checkout success , Jump to the payment page
return response()->json(['code' => 20000, 'data' => '', 'msg' => ' checkout success !']);
}catch (\Exception $e){
DB::rollBack();
return response()->json(['code' => 50000, 'data' => '', 'msg' => $e->getMessage()]);
}
}
}
边栏推荐
猜你喜欢

where、having、group by、order by,is null,not in,子查询,delete,日期函数

Workflow of wireless vibrating wire acquisition system

Time pit in MySQL driver

一文理解分布式开发中的服务治理

Read the recent trends of okaleido tiger and tap the value and potential behind it

MQTT例程

Three implementation methods of Servlet

Qt编写物联网管理平台48-特色功能设计

以科技传递温度,vivo亮相数字中国建设峰会

Redis master-slave mode, sentinel cluster, fragment cluster
随机推荐
0728~ sorting out interview questions
深度剖析 —— 预处理
NVIDIA-VPI(Vision Programming Interface)
QT屏幕自适应自动布局,拖动窗口自动变大变小(一)
KBxxxxxx不一定是补丁,也可能是某个问题解决方案的描述
Mqtt routine
4年测试经验,好不容易进了阿里,两个月后我选择了裸辞...
How does the Devops team defend against API attacks?
XSS靶场(二)xss.haozi
主从复制及其原理
redis为什么快,消息队列,单线程
详解异步任务:任务的状态及生命周期管理
云开发口袋工具箱微信小程序源码
C language to achieve the three chess game
一文搞懂 Redis 架构演化之路
FPGA skimming memory (Verilog implementation of ram and FIFO)
平凡的快乐
【无标题】
网络基础概论
优炫软件任命黄志军为公司总经理