文章每週持續更新,各位的「三連」是對我最大的確定。能夠微信搜索公衆號「 後端技術學堂 」第一時間閱讀(通常比博客早更新一到兩篇)
今年春節響應國家號召在家宅着抵抗疫情,拜年也改用微信紅包,春節發了不少也搶了不少微信紅包,也算支持了公司業務,微信支付融入生活,搶紅包已是很是日常的事情。程序員
搶紅包這一簡單的動做,每一次都是對紅包服務後臺的一次請求,在春節期間海量的服務請求下,實際上是一個很典型的高併發編程模型。後臺開發程序員都有一個共識:實現一個功能很容易,難的是大量請求下提升服務性能。redis
在程序員眼裏,你們搶的不是紅包,是紅包後臺服務的鎖 !這裏的鎖不是咱們平常生活中的鎖,後臺服務編程中鎖的概念:數據庫
實現多個進程或線程互斥的訪問共享資源的一種機制
爲便於說明,咱們簡化模型,約定搶紅包服務是多線程服務,搶紅包操做包含如下3個步驟:編程
假設你發了100塊錢紅包,1000我的1秒內同時來搶(高併發),若是不加鎖是這樣的狀況:後端
怎麼解決這個問題呢? 就用到咱們上面說的加鎖來解決。緩存
實現鎖的方式有不少,這裏列舉幾種常見的分類服務器
顧名思義就是悲觀的作最壞打算的鎖機制,佔有鎖期間獨佔資源。
悲觀鎖把搶紅包這三個步驟打包成一個總體作成互斥操做,「在我搶了沒更新數據以前你別來查餘額,查到也不許確」。也能夠類比數據庫的事務來理解。微信
事務必須具有如下四個屬性,簡稱ACID 屬性:
原子性(Atomicity):事務是一個完整的操做。事務的各步操做是不可分的(原子的);要麼都執 行,要麼都不執行
一致性(Consistency):當事務完成時,數據必須處於一致狀態
隔離性(Isolation):對數據進行修改的全部併發事務是彼此隔離的,這代表事務必須是獨立的,它不該以任何方式依賴於或影響其餘事務
永久性(Durability):事務完成後,它對數據庫的修改被永久保持,事務日誌可以保持事務的永久性
它悲觀的認爲你每次去搶紅包必然有其餘人也同時在搶,因此你這條線程在搶的時候要獨佔資源,其餘線程須要阻塞掛起等待你搶完才能進來搶,掛起的線程就幹不了其餘事了。數據結構
魯迅先生說過,浪費CPU資源就是浪費生命!
而一旦你搶完紅包釋放了鎖,其餘在等待中的線程又要搶佔資源、搶到了還要恢復線程上下文。多線程
CPU不斷的切換線程上下文很是浪費服務器資源,嚴重的會致使不能及時處理後續搶紅包請求,須要想辦法提升效率,因而有了樂觀鎖
樂觀鎖是對悲觀鎖的改進,樂觀的認爲加鎖的時候沒有競爭,樂觀鎖不阻塞線程。
一種實現樂觀鎖的方法是數據庫內紅包餘額增長版本號,初始版本號是0,每次搶完紅包版本號加1後再去更新餘額,只有更新的版本號大於數據庫內的版本號才認爲是合法的,予以更新;不然不予更新,線程不阻塞能夠稍後重試,避免頻繁切換線程上下文。
樂觀鎖在搶紅包的步驟一、2不作加鎖判斷,在步驟3的時候才作加鎖判斷版本號。
能夠看到,樂觀鎖在加鎖失敗的時候不掛起線程等待,避免了線程上下文頻繁的切換,提升紅包服務處理性能。
上面兩種鎖的形式都是基於對數據庫的更新來作的,在大請求高併發的時候,頻繁的存取數據庫,尤爲是樂觀鎖重試會對數據庫產生很大的衝擊,在實際生產環境要儘可能減小對數據庫的訪問。
Redis 是一個開源(BSD許可)的,內存中的數據結構存儲系統,它能夠用做數據庫、緩存和消息中間件。也能夠用redis實現分佈式鎖,與數據庫交互兩次:第一次獲取紅包餘額,第二次搶完更新紅包狀態。搶紅包和中間過程更新操做都在內存中進行,這可比數據庫操做快了幾個數量級,顯著改善服務併發性能。
redis分佈式鎖:
利用Redis的SET操做在內存中保存key-value鍵值對,加鎖就是獲取這個鍵值對的值,解鎖就是刪除這個鍵值對。
分佈式鎖也不阻塞線程,關於這種分佈式鎖的實現不在這裏展開說明,能夠參考我另外一篇公衆號文章: redis分佈式鎖的3種實現方式分析,詳細分析了幾種分佈式鎖特色和利弊。
原創不易,看到這裏動動手指,各位的「三連」是對我持續創做的最大支持,咱們下篇文章再見。
能夠微信搜索公衆號「 後端技術學堂 」回覆「資料」有我給你準備的各類編程學習資料。文章每週持續更新,咱們下期見!