雙11來了,漫天飛的優惠券怎麼實現?javascript
因而咱們有了這樣一個需求:某商家發優惠券,扣門,就發 10 張,參與的用戶假設就 1000 人,假設有 50 人同時領取,那如何保證這個併發量下不會超領取呢?html
使用Redis
計數器,這只是其應用場景之一,其中將用到三個命令:java
exists
:判斷傳入的key是否存在setnx
:設置值incr
:實現計數功能代碼不是不少,建議本身動手實踐下,有註釋node
這裏用到的是ioredis
,地址github.com/luin/ioredi…,能夠進去瞅一瞅laravel
新建個文件夾就叫ioredis
吧,而後裏面新增兩個JS
文件,分別爲luck.js
和app.js
,上代碼git
// luck.js
// 引入Redis
// 這裏是要先npm安裝的 => npm i ioredis
const Redis = require('ioredis')
const redis = new Redis(6379, '127.0.0.1')
// 將日誌寫入指定文件,也就是抽中券的和沒抽中券的請求一個記錄
const fs = require('fs')
const { Console } = require('console')
const output = fs.createWriteStream('./stdout.log') // 抽中券的到這裏來
const errorOutput = fs.createWriteStream('./stderr.log') // 沒抽中券的到這裏來
const logger = new Console(output, errorOutput)
async function luck() {
const count = 10
const key = 'counter:luck'
const keyExists = await redis.exists(key) // 判斷key是否存在
// key不存在則初始化設置
if(!keyExists) {
await redis.setnx(key, 0)
}
// 每發送一次領取請求,採用 incr 命令進行自增,因爲 Redis 單線程的緣由,能夠保證原子性,不會出現超領。
const result = await redis.incr(key)
console.log(`result: ${result}`)
if(result > count) { //領取超限
logger.error('luck failure', result)
return
}
logger.info('luck success', result)
}
module.exports = luck
複製代碼
而後app.js
github
/* 起一個簡單的服務,使得瀏覽器能夠訪問127.0.0.1:8000/luck接口, 代替一個領取優惠券的操做 */
const luck = require('./luck')
const http = require('http')
const url = require('url')
const qs = require('querystring')
// 這個花裏胡哨的DATA徹底能夠不要的,由於咱們只須要起一個簡單的服務
const DATA = userId => ({
code: 0,
success: true,
data: {
userId,
name: '2oops',
descripttion: 'go ahead',
date: new Date()
}
})
// 其實這裏是一個比較標準的請求格式
http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/json; charset=utf-8');
const reqUrl = url.parse(req.url);
if(reqUrl.pathname === '/luck') {
const uid = qs.parse(reqUrl.query).userId;
const RESULT = JSON.stringify(DATA(uid));
luck() // 主要在這裏調用就闊以,其餘的都是耍流氓
res.end(RESULT)
} else {
res.writeHead(404);
res.end("Not Found")
}
}).listen(8000, () => {
console.log('listening at port: 8000')
})
複製代碼
接下來根目錄下運行node app
,這時候你應該會收到這樣一個報錯,是說沒有起Redis server
服務redis
這裏給出問題的解決方法,點這裏,再附上windows
環境啓動不了redis server
服務的解決方法,親測有效,windows下redis服務的安裝npm
接下來,咱們再運行app.js
,能夠在瀏覽器看到json
並且當咱們訪問這個地址的時候,incr
命令已經執行了一次計數操做
最後一步,使用apchebench
作一個併發壓力測試,安裝教程放這裏,(其實這裏碰見了一個註冊服務出現(OS 5)拒絕訪問的問題),按照教程配置好httpd.conf
文件後,bin
目錄下運行
.\httpd.exe -k install
.\httpd.exe -k start
ab -c 50 -n 100 http://127.0.0.1:8000/luck
(這裏放只100個請求數)最後咱們會看到這個
最終能夠看到stdout.log
和stderr.log
文件下分別寫入了10個抽中券的記錄和40個未抽中券的記錄。
Redis
的應用場景不少,這裏的計數器只是一種,除了緩存用的比較多以外,還能夠實現消息隊列,Session存儲,發佈訂閱等。
參考連接