server.js
var express = require("express");
var app = express();
var db_count = 50; // mysql中的持久化数据
var remain_num = 0; // 内存数据
var sync_num_arr = [];
async function sync_data_to_mysql() {
setTimeout(async function () {
if (sync_num_arr.length > 0) {
var final_num = sync_num_arr[sync_num_arr.length - 1]; // 以最后一次的数据为准,同步到数据库
sync_num_arr = [];
await set_remain_num(final_num);
}
await sync_data_to_mysql();
console.log("----------剩余个数", db_count);
}, 2000);
}
// 初始状态,从数据库获取剩余数目
async function get_remain_num_from_db() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(db_count);
}, Math.random() * 1000)
});
}
// 设置数据库中剩余数目
async function set_remain_num(num) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
db_count = num;
resolve();
}, Math.random() * 1000)
});
}
//
async function random_sleep() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, Math.random() * 1000)
});
}
async function init() {
// 从数据库得到剩余数目存储为内存变量
remain_num = await get_remain_num_from_db();
app.get("/rob", async function (req, res) {
if (remain_num > 0) {
remain_num = remain_num - 1;
sync_num_arr.push(remain_num);
console.log("remain_num=", remain_num);
res.send(req.query.name + " 抢到一个剩余 " + remain_num);
} else {
res.send("商品售罄,秒杀失败!!!");
}
});
app.get("/remain", async function (req, res) {
res.send("剩余数量=" + db_count);
});
app.listen(3000);
// 定时同步到数据库
await sync_data_to_mysql();
}
init();
client.js
var http = require("http");
function start_rob(user_name) {
var url = "http://localhost:3000/rob?name=" + user_name;
http.get(url, function (incoming_msg) {
incoming_msg.on("data", function (data) {
if (incoming_msg.statusCode == 200) {
console.log(data.toString());
} else {
console.log("ERROR");
}
})
});
}
// 模拟秒杀100次
var num = parseInt(Math.random() * 5000);
// num = 60;
console.log("模拟秒杀人数num", num);
async function random_sleep() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, Math.random() * 5000)
});
}
async function main() {
for (var i = 0; i < num; i++) {
await random_sleep();
console.log("<<<<开抢用户=guest_" + i);
start_rob("guest_" + i);
}
}
main();
思路
秒杀活动
服务器开启后,客户端模拟并发请求
同步策略为: 先读取数据库数据到内存中,然后当客户端请求秒杀到后,如果还有剩余,则修改剩余数量,加入同步列表
定时把同步列表最后一次的数据同步到mysql数据库
参考doc中的结果
1)服务器
node server.js
2)客户端
node client.js