-對于商品搶購等并發場景下,可能會出現超賣的現象,這時就需要解決并發所帶來的這些問題了.在PHP語言中并沒有原生的提供并發的解決方案,因此就需要借助其他方式來實現并發控制。
#######方案一:使用文件鎖排它鎖
flock函數用于獲取文件的鎖,這個鎖同時只能被一個線程獲取到,其它沒有獲取到鎖的線程要么阻塞,要么獲取失敗
在獲取到鎖的時候,先查詢庫存,如果庫存大于0,則進行下訂單操作,減庫存,然后釋放鎖
flock()函數鎖定或釋放文件 若成功,則返回 true。若失敗,則返回 false。
flock($fp,lock,block)
lock
共享鎖定(讀取) LOCK_SH
獨占鎖定(寫入) LOCK_EX
釋放鎖定LOCK_UN
block 若設置為true 則當進行鎖定時阻擋其他進程
注意
1.使用共享鎖LOCK_SH,如果是讀取,不需要等待,但如果是寫入,需要等待讀取完成。
2.使用獨占鎖LOCK_EX,無論寫入/讀取都需要等待。
3.LOCK_UN,無論使用共享/讀占鎖,使用完后需要解鎖。
4.LOCK_NB,當被鎖定時,不阻塞,而是提示鎖定。
穿透到數據庫,而使數據庫奔潰,這里可用文件鎖來解決
$data = $cache->get('key');
if(!$data){
$fp = fopen('lockfile');
if(flock($fp, LOCK_EX)){
$data = $cache->get('key');//拿到鎖后再次檢查緩存,這時可能已經有了
if(!$data){
$data = mysql->query($sql);
$cache->set('key', $data);
}
flock($fp, LOCK_UN);
}
fclose($fp);
}
#######方案二:使用MySQL數據庫提供的悲觀鎖
Innodb存儲引擎支持行級鎖,當某行數據被鎖定時,其他進程不能對這行數據進行操作
先查詢并鎖定行:
select stock_num from table where id=1 for update
if(stock_num > 0){
//下訂單
update table set stock_num=stock-1 where id=1
}
#######方案三:使用隊列
將用戶的下單請求依次存入一個隊列中,后臺用一個單獨的進程處理隊列中的下單請求
1.創建隊列數據表
2.把任務(比如 訂單創建)插入隊列表中
3.linux上做個定時任務,異步執行隊列表中的任務,一個一個排隊執行。
#######方案四:使用Redis/Memcached
redis的操作都是原子性的,可以將商品的庫存存入redis中,下單之前對庫存進行decr操作,如果返回的值大于等于0等可以下單,否則不能下單,這種方式效率較高
if(redis->get('stock_num') > 0){
stock_num = redis->decr('stock_num')
if(stock_num >= 0){
//下訂單
}else{
//庫存不足
}
}else{
//庫存不足
}
其他并發問題:
在現實應用中,很多情況下會把數據存入緩存,當緩存失效時,去數據庫取數據并重新設置緩存,如果這時并發量很大,會有很多進程同時去數據庫取數據,導致很多請求
說白了,要解決并發問題就必須要加鎖,各種方案的本質都是加鎖
注釋:
第一 首先,確認服務器硬件是否足夠支持當前的流量。
第二 其次,優化數據庫訪問。
前臺實現完全的靜態化當然最好,可以完全不用訪問數據庫,不過對于頻繁更新的網站,
靜態化往往不能滿足某些功能。
緩存技術就是另一個解決方案,就是將動態數據存儲到緩存文件中,動態網頁直接調用
這些文件,而不必再訪問數據庫,WordPress和Z-Blog都大量使用這種緩存技術。
如果確實無法避免對數據庫的訪問,那么可以嘗試優化數據庫的查詢SQL.避免使用
Select * from這樣的語句,每次查詢只返回自己需要的結果,避免短時間內的大
量SQL查詢。
第三,禁止外部的盜鏈。
外部網站的圖片或者文件盜鏈往往會帶來大量的負載壓力,因此應該嚴格限制外部對
于自身的圖片或者文件盜鏈,好在目前可以簡單地通過refer來控制盜鏈,Apache自
己就可以通過配置來禁止盜鏈,IIS也有一些第三方的ISAPI可以實現同樣的功能。當
然,偽造refer也可以通過代碼來實現盜鏈,不過目前蓄意偽造refer盜鏈的還不多,
可以先不去考慮,或者使用非技術手段來解決,比如在圖片上增加水印。
第四,控制大文件的下載。
大文件的下載會占用很大的流量,并且對于非SCSI硬盤來說,大量文件下載會消耗
CPU,使得網站響應能力下降。因此,盡量不要提供超過2M的大文件下載,如果需要
提供,建議將大文件放在另外一臺服務器上。
第五,使用不同主機分流主要流量
將文件放在不同的主機上,提供不同的鏡像供用戶下載。比如如果覺得RSS文件占用
流量大,那么使用FeedBurner或者FeedSky等服務將RSS輸出放在其他主機上,這
樣別人訪問的流量壓力就大多集中在FeedBurner的主機上,RSS就不占用太多資源了。
第六,使用流量分析統計軟件。
在網站上安裝一個流量分析統計軟件,可以即時知道哪些地方耗費了大量流量,哪些頁
面需要再進行優化,因此,解決流量問題還需要進行精確的統計分析才可以。我推薦使
用的流量分析統計軟件是Google Analytics(Google分析)。我使用過程中感覺其
效果非常不錯,稍后我將詳細介紹一下Google Analytics的一些使用常識和技巧。