目錄
入門
啓動Redis服務: docker run --name redis-in-action -p 6379:6379 -d redis
redis-cli
EVAL "return {KEYS[1], KEYS[2], ARGV[1], ARGV[2]}" 2 1 2 3 4
1) "1"
2) "2"
3) "3"
4) "4"
echo "return { KEYS[1], KEYS[2], ARGV[1], ARGV[2] }" >> hello.lua
redis-cli --eval hello.lua 1 2 , 3 4
1) "1"
2) "2"
3) "3"
4) "4"
關於Lua更多介紹 參考Lua簡明教程
秒殺
高併發 - Redis內存
原子性 - Redis單線程
vim seckilling.lua
local n = tonumber(ARGV[1])
if not n or n == 0 then
return 0
end
local vals = redis.call("HMGET", KEYS[1], "Total", "Booked")
local total = tonumber(vals[1])
local blocked = tonumber(vals[2])
if not total or not blocked then
return 0
end
if blocked + n <= total then
redis.call("HINCRBY", KEYS[1], "Booked", n)
return n;
end
return 0
redis-cli script load "$(cat seckilling.lua)" # 58652c43df5e7752b7bb1f8e65e382299b5bd8b6
redis-cli
HMSET goodsId Total 100 Booked 0
HMGET goodsId Total Booked
1) "100"
2) "1"
SCRIPT EXISTS 58652c43df5e7752b7bb1f8e65e382299b5bd8b6
EVALSHA 58652c43df5e7752b7bb1f8e65e382299b5bd8b6 1 goodsId 1
HMGET goodsId Total Booked
1) "100"
2) "1"
關於Redis單線程模型的更多討論 可以參考爲什麼redis 是單線程的? & Redis單線程優勢 & Redis is single threaded. How can I exploit multiple CPU / cores?
隊列
發佈-訂閱 - Redis隊列
緩存 - 高速Redis + MySQL
vim seckilling.lua
local n = tonumber(ARGV[1])
if not n or n == 0 then
return 0
end
local vals = redis.call("HMGET", KEYS[1], "Total", "Booked")
local total = tonumber(vals[1])
local blocked = tonumber(vals[2])
if not total or not blocked then
return 0
end
if blocked + n <= total then
redis.call("HINCRBY", KEYS[1], "Booked", n)
redis.call("LPUSH", KEYS[2], "Booked "..n)
return n;
end
return 0
redis-cli script load "$(cat seckilling.lua)" # b191ffa49361dac8f9142f0eac552cecd0df2489
redis-cli
SCRIPT EXISTS b191ffa49361dac8f9142f0eac552cecd0df2489
EVALSHA b191ffa49361dac8f9142f0eac552cecd0df2489 2 goodsId orderList 1
HMGET goodsId Total Booked
1) "100"
2) "2"
BRPOP orderList 60
1) "orderList"
2) "Booked 1"
這裏只是將orderList的數據取出 實際項目中可以結合關係數據庫處理該訂單
服務
egg-init --type=simple server
cd server && cnpm i
cnpm i --save egg-redis
vim config/plugin.js
'use strict';
exports.redis = {
enable: true,
package: 'egg-redis',
};
vim config/config.default.js
'use strict';
module.exports = appInfo => {
const config = exports = {};
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1537341461009_7706';
// add your config here
config.middleware = [];
config.redis = {
client: {
host: '127.0.0.1',
port: 6379,
password: '',
db: '0',
}
};
return config;
};
vim app/controller/home.js
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
const { ctx, app } = this;
const code =
`
local n = tonumber(ARGV[1])
if not n or n == 0 then
return 0
end
local vals = redis.call("HMGET", KEYS[1], "Total", "Booked")
local total = tonumber(vals[1])
local blocked = tonumber(vals[2])
if not total or not blocked then
return 0
end
if blocked + n <= total then
redis.call("HINCRBY", KEYS[1], "Booked", n)
redis.call("LPUSH", KEYS[2], "Booked "..n)
return n;
end
return 0
`;
app.redis.defineCommand('seckilling', {
lua: code
});
ctx.body = await app.redis.seckilling(2, 'goodsId', 'orderList', '1');
}
}
module.exports = HomeController;
cnpm run dev # localhost:7001
測試
redis-cli
HMSET goodsId Total 100 Booked 0
DEL orderList
sudo apt update
sudo apt install -y apache2-utils
ulimit -n 10000
ab -n 50000 -c 5000 http://192.168.56.1:7001/
關於ab的更多介紹 可以參考超實用壓力測試工具-ab工具
redis-cli
HMGET goodsId Total Booked
1) "100"
2) "100"