最近群裡聊起秒殺和限流,我自己沒有做過類似應用,但是工作中遇到過更大的資料和併發。
於是提出了乙個簡單的模型:
var count = rds.inc(key);
if(count > 1000) throw "已搶光!"
借助redis單執行緒模型,它的inc是安全的,確保每次加一,然後返回加一後的結果。如果原來是234,加一了就是235,返回的一定是235,在此中間,不會有別的請求來打斷從而導致返回236或者其它。
其實我們可以理解為inc的業務就是佔坑排隊,每人佔乙個坑,拿到排隊小票後看看是不是超額了,再從業務層面輸出秒殺結果,甚至做一些更加複雜的業務。
六條提到限流,可能基於某種考慮,希望把key對應的count給限制在1000附近,可以接受1%偏差。
於是有了改進模型:
var count = rds.inc(key);
if(count > 1000){
rds.dec(key);
throw "超出限額!" }
就加了一句,超出限額後,把小票給減回去^_^
採用redis有乙個好處,比如支援很多應用伺服器一起搶……
當然,對於很大量的秒殺,這個模型也不一定合理,比如要槍10萬部手機,然後來了300萬使用者,瞬間擠上來。
這裡有個變通方法可以試一下,那就是準備10個redis例項,每個放1萬。使用者請求過來的時候,可以隨機數或者雜湊取模,找對應例項來進行搶購。
同理可以直接更多使用者的場景。總的來說,在資料較大的時候,隨機和雜湊就具有一定統計學意義,相對來說是比較均衡的。
上面是大量秒殺的簡單場景,那麼小資料場景呢?比如就只有幾萬併發的場景。
小資料場景,單應用例項,可以考慮把redis都給省了。
初級模型:
interlocked.increase(ref count);
if(count >= 1000) throw "搶光啦!"
中級模型:
private volatile int32 count;
var old = 0;
do while(interlocked.compareexchange(ref count, old + 1, old) != old);
這個cas原子操作可是好東西,在x86指令集下有專門指令cmpxchg來處理,在處理器級別確保比較和交換資料的原子性。大多數系統想要邁過10萬tps的門檻向100萬tps靠齊,就必須得實現無鎖操作lock-free,其中cas是最為簡單易懂,儘管有時候有aba問題,但我們可以找到許多解決辦法。
在實際使用場景中,可能有更複雜的需求,那就另當別論,這裡只能班門弄斧幾個簡單易用的模型。
秒殺和限流 redis
redis是單執行緒的,所以在redis中所有命令都是原子操作。而當要多條redis命令同時執行而不被打斷時,則需要使用redis的事務了。商品放到redis上面,每一次都在redis裡面執行操作,操作之前先watch key watch的作用就是檢測這個key,如果這key的事務被修改則不會執行,...
Redis事務和秒殺業務設計
redis事務是乙個單獨的隔離操作 事務中的所有命令都會序列化 按順序地執行。事務在執行的過程中,不會被其他客戶端傳送來的命令請求所打斷,redis事務的主要作用就是串聯多個命令防止別的命令插隊 multi 用於標記事務塊的開始。redis會將後續的命令逐個放入佇列中,然後才能使用exec命令原子化...
PHP 通過redis和mysql實現秒殺業務
db mysqldb getinstance info db fetchrow select from goods where goods id 1 判斷是否還有庫存 if info stock 0 減少庫存,num 只是乙個記錄修改資料的次數,可以判斷是否存在超賣現象 result db upda...