<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        分布式鎖的多種實現方式

        來源:懂視網 責編:小采 時間:2020-11-09 09:18:02
        文檔

        分布式鎖的多種實現方式

        分布式鎖的多種實現方式:目前幾乎很多大型網站及應用都是分布式部署的,分布式場景中的數據一致性問題一直是一個比較重要的話題。分布式的CAP理論告訴我們任何一個分布式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tol
        推薦度:
        導讀分布式鎖的多種實現方式:目前幾乎很多大型網站及應用都是分布式部署的,分布式場景中的數據一致性問題一直是一個比較重要的話題。分布式的CAP理論告訴我們任何一個分布式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tol

        目前幾乎很多大型網站及應用都是分布式部署的,分布式場景中的數據一致性問題一直是一個比較重要的話題。分布式的CAP理論告訴我們“任何一個分布式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance),最多只能同時滿足兩項。”所以,很多系統在設計之初就要對這三者做出取舍。在互聯網領域的絕大多數的場景中,都需要犧牲強一致性來換取系統的高可用性,系統往往只需要保證“最終一致性”,只要這個最終時間是在用戶可以接受的范圍內即可。

        在很多場景中,我們為了保證數據的最終一致性,需要很多的技術方案來支持,比如分布式事務、分布式鎖等。有的時候,我們需要保證一個方法在同一時間內只能被同一個線程執行。在單機環境中,Java中其實提供了很多并發處理相關的API,但是這些API在分布式場景中就無能為力了。也就是說單純的Java Api并不能提供分布式鎖的能力。所以針對分布式鎖的實現目前有多種方案。

        針對分布式鎖的實現,目前比較常用的有以下幾種方案:

        基于數據庫實現分布式鎖 基于緩存(redis,memcached,tair)實現分布式鎖 基于Zookeeper實現分布式鎖

        在分析這幾種實現方案之前我們先來想一下,我們需要的分布式鎖應該是怎么樣的?(這里以方法鎖為例,資源鎖同理)

      1. 可以保證在分布式部署的應用集群中,同一個方法在同一時間只能被一臺機器上的一個線程執行。

      2. 這把鎖要是一把可重入鎖(避免死鎖)

      3. 這把鎖最好是一把阻塞鎖(根據業務需求考慮要不要這條)

      4. 有高可用的獲取鎖和釋放鎖功能

      5. 獲取鎖和釋放鎖的性能要好

      6. 基于數據庫實現分布式鎖

        基于數據庫表

        要實現分布式鎖,最簡單的方式可能就是直接創建一張鎖表,然后通過操作該表中的數據來實現了。

        當我們要鎖住某個方法或資源時,我們就在該表中增加一條記錄,想要釋放鎖的時候就刪除這條記錄。

        創建這樣一張數據庫表:

        CREATE TABLE `methodLock` (
         `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
         `method_name` varchar(64) NOT NULL DEFAULT '' COMMENT '鎖定的方法名',
         `desc` varchar(1024) NOT NULL DEFAULT '備注信息',
         `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '保存數據時間,自動生成',
         PRIMARY KEY (`id`),
         UNIQUE KEY `uidx_method_name` (`method_name `) USING BTREE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='鎖定中的方法';

        當我們想要鎖住某個方法時,執行以下SQL:

        insert into methodLock(method_name,desc) values (‘method_name’,‘desc’)

        因為我們對method_name做了唯一性約束,這里如果有多個請求同時提交到數據庫的話,數據庫會保證只有一個操作可以成功,那么我們就可以認為操作成功的那個線程獲得了該方法的鎖,可以執行方法體內容。

        當方法執行完畢之后,想要釋放鎖的話,需要執行以下Sql:

        delete from methodLock where method_name ='method_name'

        上面這種簡單的實現有以下幾個問題:

        1、這把鎖強依賴數據庫的可用性,數據庫是一個單點,一旦數據庫掛掉,會導致業務系統不可用。

        2、這把鎖沒有失效時間,一旦解鎖操作失敗,就會導致鎖記錄一直在數據庫中,其他線程無法再獲得到鎖。

        3、這把鎖只能是非阻塞的,因為數據的insert操作,一旦插入失敗就會直接報錯。沒有獲得鎖的線程并不會進入排隊隊列,要想再次獲得鎖就要再次觸發獲得鎖操作。

        4、這把鎖是非重入的,同一個線程在沒有釋放鎖之前無法再次獲得該鎖。因為數據中數據已經存在了。

        當然,我們也可以有其他方式解決上面的問題。

        數據庫是單點?搞兩個數據庫,數據之前雙向同步。一旦掛掉快速切換到備庫上。

        沒有失效時間?只要做一個定時任務,每隔一定時間把數據庫中的超時數據清理一遍。

        非阻塞的?搞一個while循環,直到insert成功再返回成功。

        非重入的?在數據庫表中加個字段,記錄當前獲得鎖的機器的主機信息和線程信息,那么下次再獲取鎖的時候先查詢數據庫,如果當前機器的主機信息和線程信息在數據庫可以查到的話,直接把鎖分配給他就可以了。

        基于數據庫排他鎖

        除了可以通過增刪操作數據表中的記錄以外,其實還可以借助數據中自帶的鎖來實現分布式的鎖。

        我們還用剛剛創建的那張數據庫表。可以通過數據庫的排他鎖來實現分布式鎖。 基于MySql的InnoDB引擎,可以使用以下方法來實現加鎖操作:

        public boolean lock(){
         connection.setAutoCommit(false)
         while(true){
         try{
         result = select * from methodLock where method_name=xxx for update;
         if(result==null){
         return true;
         }
         }catch(Exception e){
         }
         sleep(1000);
         }
         return false;
        }

        在查詢語句后面增加for update,數據庫會在查詢過程中給數據庫表增加排他鎖。當某條記錄被加上排他鎖之后,其他線程無法再在該行記錄上增加排他鎖。

        我們可以認為獲得排它鎖的線程即可獲得分布式鎖,當獲取到鎖之后,可以執行方法的業務邏輯,執行完方法之后,再通過以下方法解鎖:

        public void unlock(){
         connection.commit();
        }

        通過connection.commit()操作來釋放鎖。

        這種方法可以有效的解決上面提到的無法釋放鎖和阻塞鎖的問題。

        阻塞鎖? for update語句會在執行成功后立即返回,在執行失敗時一直處于阻塞狀態,直到成功。

        鎖定之后服務宕機,無法釋放?使用這種方式,服務宕機之后數據庫會自己把鎖釋放掉。

        但是還是無法直接解決數據庫單點和可重入問題。

        總結

        總結一下使用數據庫來實現分布式鎖的方式,這兩種方式都是依賴數據庫的一張表,一種是通過表中的記錄的存在情況確定當前是否有鎖存在,另外一種是通過數據庫的排他鎖來實現分布式鎖。

        數據庫實現分布式鎖的優點

        直接借助數據庫,容易理解。

        數據庫實現分布式鎖的缺點

        會有各種各樣的問題,在解決問題的過程中會使整個方案變得越來越復雜。

        操作數據庫需要一定的開銷,性能問題需要考慮。

        基于緩存實現分布式鎖

        相比較于基于數據庫實現分布式鎖的方案來說,基于緩存來實現在性能方面會表現的更好一點。而且很多緩存是可以集群部署的,可以解決單點問題。

        目前有很多成熟的緩存產品,包括Redis,memcached以及我們公司內部的Tair。

        這里以Tair為例來分析下使用緩存實現分布式鎖的方案。關于Redis和memcached在網絡上有很多相關的文章,并且也有一些成熟的框架及算法可以直接使用。

        基于Tair的實現分布式鎖在內網中有很多相關文章,其中主要的實現方式是使用TairManager.put方法來實現。

        public boolean trylock(String key) {
         ResultCode code = ldbTairManager.put(NAMESPACE, key, "This is a Lock.", 2, 0);
         if (ResultCode.SUCCESS.equals(code))
         return true;
         else
         return false;
        }
        public boolean unlock(String key) {
         ldbTairManager.invalid(NAMESPACE, key);
        }

        以上實現方式同樣存在幾個問題:

        1、這把鎖沒有失效時間,一旦解鎖操作失敗,就會導致鎖記錄一直在tair中,其他線程無法再獲得到鎖。

        2、這把鎖只能是非阻塞的,無論成功還是失敗都直接返回。

        3、這把鎖是非重入的,一個線程獲得鎖之后,在釋放鎖之前,無法再次獲得該鎖,因為使用到的key在tair中已經存在。無法再執行put操作。

        當然,同樣有方式可以解決。

        沒有失效時間?tair的put方法支持傳入失效時間,到達時間之后數據會自動刪除。

        非阻塞?while重復執行。

        非可重入?在一個線程獲取到鎖之后,把當前主機信息和線程信息保存起來,下次再獲取之前先檢查自己是不是當前鎖的擁有者。

        但是,失效時間我設置多長時間為好?如何設置的失效時間太短,方法沒等執行完,鎖就自動釋放了,那么就會產生并發問題。如果設置的時間太長,其他獲取鎖的線程就可能要平白的多等一段時間。這個問題使用數據庫實現分布式鎖同樣存在

        總結

        可以使用緩存來代替數據庫來實現分布式鎖,這個可以提供更好的性能,同時,很多緩存服務都是集群部署的,可以避免單點問題。并且很多緩存服務都提供了可以用來實現分布式鎖的方法,比如Tair的put方法,redis的setnx方法等。并且,這些緩存服務也都提供了對數據的過期自動刪除的支持,可以直接設置超時時間來控制鎖的釋放。

        使用緩存實現分布式鎖的優點

        性能好,實現起來較為方便。

        使用緩存實現分布式鎖的缺點

        通過超時時間來控制鎖的失效時間并不是十分的靠譜。

        基于Zookeeper實現分布式鎖

        基于zookeeper臨時有序節點可以實現的分布式鎖。

        大致思想即為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除即可。同時,其可以避免服務宕機導致的鎖無法釋放,而產生的死鎖問題。

        來看下Zookeeper能不能解決前面提到的問題。

        鎖無法釋放?使用Zookeeper可以有效的解決鎖無法釋放的問題,因為在創建鎖的時候,客戶端會在ZK中創建一個臨時節點,一旦客戶端獲取到鎖之后突然掛掉(Session連接斷開),那么這個臨時節點就會自動刪除掉。其他客戶端就可以再次獲得鎖。

        非阻塞鎖?使用Zookeeper可以實現阻塞的鎖,客戶端可以通過在ZK中創建順序節點,并且在節點上綁定監聽器,一旦節點有變化,Zookeeper會通知客戶端,客戶端可以檢查自己創建的節點是不是當前所有節點中序號最小的,如果是,那么自己就獲取到鎖,便可以執行業務邏輯了。

        不可重入?使用Zookeeper也可以有效的解決不可重入的問題,客戶端在創建節點的時候,把當前客戶端的主機信息和線程信息直接寫入到節點中,下次想要獲取鎖的時候和當前最小的節點中的數據比對一下就可以了。如果和自己的信息一樣,那么自己直接獲取到鎖,如果不一樣就再創建一個臨時的順序節點,參與排隊。

        單點問題?使用Zookeeper可以有效的解決單點問題,ZK是集群部署的,只要集群中有半數以上的機器存活,就可以對外提供服務。

        可以直接使用zookeeper第三方庫Curator客戶端,這個客戶端中封裝了一個可重入的鎖服務。

        public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        try {
        return interProcessMutex.acquire(timeout, unit);
        } catch (Exception e) {
        e.printStackTrace();
        }
        return true;
        }
        public boolean unlock() {
        try {
        interProcessMutex.release();
        } catch (Throwable e) {
        log.error(e.getMessage(), e);
        } finally {
        executorService.schedule(new Cleaner(client, path), delayTimeForClean, TimeUnit.MILLISECONDS);
        }
        return true;
        }

        Curator提供的InterProcessMutex是分布式鎖的實現。acquire方法用戶獲取鎖,release方法用于釋放鎖。

        使用ZK實現的分布式鎖好像完全符合了本文開頭我們對一個分布式鎖的所有期望。但是,其實并不是,Zookeeper實現的分布式鎖其實存在一個缺點,那就是性能上可能并沒有緩存服務那么高。因為每次在創建鎖和釋放鎖的過程中,都要動態創建、銷毀瞬時節點來實現鎖功能。ZK中創建和刪除節點只能通過Leader服務器來執行,然后將數據同不到所有的Follower機器上。

        總結

        使用Zookeeper實現分布式鎖的優點

        有效的解決單點問題,不可重入問題,非阻塞問題以及鎖無法釋放的問題。實現起來較為簡單。

        使用Zookeeper實現分布式鎖的缺點

        性能上不如使用緩存實現分布式鎖。 需要對ZK的原理有所了解。

        三種方案的比較

        從理解的難易程度角度(從低到高)

        數據庫 > 緩存 > Zookeeper

        從實現的復雜性角度(從低到高)

        Zookeeper >= 緩存 > 數據庫

        從性能角度(從高到低)

        緩存 > Zookeeper >= 數據庫

        從可靠性角度(從高到低)

        Zookeeper > 緩存 > 數據庫

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        分布式鎖的多種實現方式

        分布式鎖的多種實現方式:目前幾乎很多大型網站及應用都是分布式部署的,分布式場景中的數據一致性問題一直是一個比較重要的話題。分布式的CAP理論告訴我們任何一個分布式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tol
        推薦度:
        標簽: 種方法 實現 mysql
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲激情视频网站| 亚洲av无码潮喷在线观看| 久久亚洲精品国产精品婷婷| 久久精品人成免费| 亚洲综合激情九月婷婷| 精品久久久久成人码免费动漫| 亚洲精品韩国美女在线| 久久久高清免费视频 | 8x网站免费入口在线观看| 亚洲欧洲一区二区| 美女视频黄的全免费视频 | 亚洲免费闲人蜜桃| 成人免费在线观看网站| 在线观看亚洲专区| 国产精品亚洲αv天堂无码| 国产在线观看免费视频软件 | 美丽的姑娘免费观看在线播放| 亚洲精品综合久久中文字幕 | 亚洲丁香婷婷综合久久| 国产a级特黄的片子视频免费| 无遮挡免费一区二区三区| 国产成人A人亚洲精品无码| 99国产精品免费视频观看| 亚洲永久在线观看| 亚洲国产成人爱av在线播放| 中国性猛交xxxxx免费看| 亚洲综合婷婷久久| 日本19禁啪啪无遮挡免费动图| 国产精品免费一区二区三区| 亚洲国产人成在线观看69网站| 99久久免费国产精品特黄| 免费看黄福利app导航看一下黄色录像| 亚洲天堂在线视频| 91麻豆国产免费观看| 国产亚洲人成在线播放| 亚洲国产精品无码久久SM| 国产精品无码免费播放| 国产精品成人啪精品视频免费| 亚洲精品国产成人中文| 免费一级特黄特色大片在线观看| 久草视频在线免费看|