Redis概述與進階技術點

前述:

一直有用redis,但對redis的瞭解很片面,這次花了些時間,系統性的將redis瞭解的一遍,在這裏記錄,如果疑惑、補充、不對的地方,希望你可以及時留言交流!

 

基本概念

      • redis是什麼?https://www.jianshu.com/p/2a23257af57b
        1.基於內存亦可持久化的日誌型、Key-Value數據庫。
        2.支持存儲的value類型(5種數據結構):string(字符串)、list(鏈表)、set(集合)、zset(sorted set 有序集合)和hash(哈希類型)。
        3.數據都是緩存在內存中。
        4.redis會週期性的把更新的數據寫入磁盤(rdb)或者把修改操作寫入追加的記錄文件(aof),並且在此基礎上實現了master-slave(主從)同步。
      • 爲什麼用redishttps://www.jianshu.com/p/2a23257af57b
        1.速度快
        2.支持豐富數據類型
        3.支持事務,操作都是原子性。原子性就是對數據的更改要麼全部執行,要麼全部不執行。
        4.豐富的特性。可用於緩存,消息,按key設置過期時間,過期後將會自動刪除。
        5.可持久化,容災能力好。
      • redis適用場景https://www.jianshu.com/p/2a23257af57b
        1.會話緩存
        2.全頁緩存(FPC)
        3.隊列:Reids在內存存儲引擎領域的一大優點是提供 list 和 set 操作,這使得Redis能作爲一個很好的消息隊列平臺來使用。
        4.排行榜/計數器:Redis在內存中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(Sorted Set)。
        5.發佈/訂閱
      • memcacheredis的區別都有哪些?https://www.jianshu.com/p/2a23257af57b
        1.存儲方式
        Memecache把數據全部存在內存之中,斷電後會掛掉,數據不能超過內存大小
        Redis有部份存在硬盤上,這樣能保證數據的持久性
        2.支持的數據類型
        Memcache對數據類型支持相對簡單。
        Redis有複雜的數據類型
        3.底層模型不同
        Redis直接自己構建了VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求
        4.value大小
        redis最大可以達到1GB,而memcache只有1MB
      • redis的基礎數據結構 https://www.jianshu.com/p/c95c8450c5b6
        • string:字符串 string 是 Redis 最簡單的數據結構。在存取時,都會進行序列化與反序列化操作,需要序列化整個對象。
        • list()列表:相當於 Java 語言裏面的 LinkedList。⚠️:是鏈表不是數組。
          故插入和刪除操作塊,時間複雜度爲O(1)
          但索引定位很慢,時間複雜度爲O(n),故查詢速度較慢
          當列表彈出了最後一個元素之後,該數據結構自動被刪除,內存被回收。
          常用做:異步隊列使用++
        • hash(字典):當於 Java 語言裏面的 HashMap。⚠️:是無序的。
          字符串一次性需要全部序列化整個對象,hash 可以對 用戶結構中的每個字段單獨存儲,故也可以部分獲取,節省網絡流量。
          但hash 結構的存儲消耗要高於單個字符串。
        • Set(集合):相當於 Java 語言裏面的 HashSet。⚠️:內部無序的唯一
          集合中最後一個元素移除之後,數據結構自動刪除,內存被回收
        • zset(有序集合):似於 Java 的 SortedSet 和 HashMap 的結合體,一方面它是一個 set,保證了內部 value 的唯一性,另一方面它可以給每個 value 賦予一個 score,代表這個 value 的排序權重

核心原理

      • 爲什麼快?(https://www.jianshu.com/p/4e6b7809e10a
        • 數據存儲在內存,運算都是內存級別(納秒)
        • 使用單線程,避免了多線程切換(上下文切換)的性能損耗。⚠️:但也正是因爲使用了單線程,在使用redis時,要謹慎使用耗時指令,如keys
      • 單線程
        • 首先單線程最明顯的優勢就是:避免了多線程的切換(上下文切換)。
        • 爲什麼要選用單線程呢?我認爲原因主要有三點:
          • 1.因爲redis是完全基於內存的數據處理,速度本身極快,所以cpu不是redis的瓶頸,使用單線程,也不必考慮多線程頻繁切換而造成性能損耗,但同樣,因爲使用單線程,要注意耗時的指令(keys)
          • 2.使用了I/O多路複用(epoll:https://blog.csdn.net/With_Her/article/details/103846154),大大提高了單線程的效率
          • 3.底層模型不同,redis自己構建了VM機制,而一般的系統函數調用會浪費一定的時間
      • 持久化(https://www.jianshu.com/p/4e6b7809e10a
        • RDB快照
          • redis將內存數據快照保存在dump.rdb的二進制文件中,快照生成與保存的觸發條件可以設置。
          • 可能會丟失最近的數據,但讀取和恢復比較快速
        • AOF(append-only file)
          • 實時將操作指令保存
          • 不會丟失數據,但讀取和恢復會比較耗時
        • Redis4.0後,混合持久化
          • aof會定期根據內存的最新數據重寫aof文件
          • 重寫這一刻之前的內存rdb快照文件的內容和增量的 AOF修改內存數據的命令日誌文件存在一起,都寫入新的aof文件,重寫完新的AOF文件後會重命名之前文件,已完成覆蓋
          • 在 Redis 重啓的時候,可以先加載 rdb 的內容,然後再重放增量 AOF 日誌就可以完全替代之前的 AOF 全量文件重放,重啓效率因此大幅得到提升
      • 淘汰策略(https://www.jianshu.com/p/4e6b7809e10a
          • redis內存超過內存限制時,內存數據會和磁盤開始數據交換(swap),但這樣會讓redis性能大大降低,所以一般在生產環境中,我們一般不允許出現數據交換。故而redis提供了幾種淘汰策略
          • noeviction
            • 不會繼續寫請求,讀請求、DEL操作還可以繼續。這樣數據不會丟失,但是線上業務有影響。這也是redis默認淘汰策略
          • volatile-lru
            • 嘗試淘汰設置過期時間的key,優先淘汰使用最少key。
          • volatile-ttl
            • 嘗試淘汰設置過期時間的key,key剩餘時間越小,優先被淘汰
          • volatile-random
            • 嘗試淘汰設置過期時間的key,在過期key集合中隨機淘汰
          • Allkeys-lru
            • 從全體key中,淘汰使用最少的key
          • Allkeys-random
            • 隨機淘汰全體key集合(未設置過期時間的key,也可能淘汰)
      • redis事物
        • Redis事務:(https://www.toutiao.com/a6586230990916551182/
          提供了一種將多個命令請求打包,然後一次性、按照順序地執行多個命令的機制,並且在事務執行的期間,不會被其他客戶端發送來的命令請求所打斷,它會把事務中所有的命令都執行完畢纔會去執行其他的命令。
        • Redis中提供了multi、exec、discard與watch、unwatch這幾個命令來實現事務的功能
        • multi、exec、discard是redis提供的食物命令。
          multi:標記事務的開始
          exec:執行事務的commands隊列
          discard:結束事務,並清除commands隊列
        • Watch:(https://www.toutiao.com/a6655234522000392708/
          是redis提供的一個樂觀鎖。命令可以監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),之後的事務就不會執行。監控一直持續到EXEC命令(事務中的命令是在EXEC之後才執行的,所以在MULTI命令後可以修改WATCH監控的鍵值)。類似於java的juc包中的cas。
          unwatch命令,則是取消watch。
        • 不支持回滾。(https://www.toutiao.com/a6662238204034286093/
          不同於mysql的事物,redis事物不支持回滾。爲什麼不支持,據所瞭解到的資料:redis可能出現錯誤分爲兩種:
          在執行exec之前:錯誤的語法(參數數量錯誤,參數名錯誤),甚至內存不足等。此時會放棄該事物,不執行該事物內所有命令
          在執行exec之後:命令處理了錯誤類型,如將列表命令用在了字符串上等。此時所有命令都會執行,錯誤的命令執行失敗,但其他正確的命令會正常執行。不會回滾
          爲什麼不回滾?根據錯誤原因可知,絕大部分錯誤都是由於開發過程中的實物造成,而這種錯誤通常不會在生產中出現。不使用回滾,則會讓redis更簡潔、方便、快捷。所以redis選擇了不回滾。
        • redis原子性討論(https://www.toutiao.com/a6662238204034286093/
          嚴格來說,redis不具有原子性
          ACID裏的原子性定義:一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完。事務在執行過程中發生錯誤,會被恢復(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
          而根據上面的討論可知,redis不支持回滾,且當exec後發生錯誤,也仍舊全部執行。所以,嚴格來講,redis不具有原子性。
        • redis與mysql事物的區別
          redis基於commands隊列實現。沒有開啓事物,command立即執行。開啓事物,則排入隊列返回排隊狀態。調用exce纔會執行。
          mysql基於undo/redo日誌實現。undo日誌記錄修改前狀態,redo記錄修改後狀態。無論是否開啓事物都會立刻執行。只是開啓事物後,執行後的狀態記錄在redo日誌,commit之後,數據纔會寫入磁盤。
      • redis管道(https://www.toutiao.com/a6633666258095047176/#comment_area
        • 管道:將多個無依賴關係的獨立命令打包,一次請求,批量執行,一次返回。
        • redis一般的命令執行分開請求執行,每個命令都要單獨的請求,然後阻塞等待執行結果,然後返回。這樣的執行效率很低。管道所做的就是,把多個命令打包一次請求到服務端,然後批量執行命令,後一起返回,以較少網絡請求的次數,提高執行效率。 
        • redis用於降低網絡交互,從而減少網絡所需的時間,以達到提高執行效率的目的
      • redis分區(https://www.toutiao.com/a6768078313442247176/
        • 將數據分割,存儲到多個Redis實例中。如3個key爲:name_1,name_2,name_3,分別存儲到redis01,redis02,redis03三個實例中。
        • 分區可以使得內存橫向擴展,利用多臺機器的內存構建一個更大的redis數據庫。
        • 分區方式:
          • 範圍分區:就像上面舉的例子。可以指定ID 0到10000的用戶存儲到實例R0,而ID 10001到20000的用戶存儲到實例R2等等。但這種方式對key的命名要求有一定限制,而且需要維護一張映射範圍對象範圍與實例關係表。所以範圍一般不受歡迎,且方法低效。
          • 哈希分區:利用哈希方法(如:CRC32(key)方法),將key通過計算轉換爲一組特定數字,然後取模來確定儲存的實例,如果是4個實例,那麼就是CRC32(key)%4,獲得4的餘數(爲0-3),這樣就確定該key應該存儲在那個實例。
          • 客戶端分區:客戶端直接選擇正確節點讀寫指定鍵
          • 代理輔助分區:客戶端通過Redis協議把請求發送給代理,而不是直接發送給真正的Redis實例服務器。這個代理會確保我們的請求根據配置分區策略發送到正確的Redis實例上,並返回給客戶端。Redis和Memcached的代理都是用Twemproxy (這是twitter開源的一個代理框架)來實現代理服務分區的,國內的codis(豌豆莢開源)
          • 可以把一個請求發送給一個隨機的實例,這時實例會把該查詢轉發給正確的節點。通過客戶端重定向(客戶端的請求不用直接從一個實例轉發到另一個實例,而是被重定向到正確的節點),Redis集羣實現了一種混合查詢路由。
        • 分區缺點:
          • 不支持事物
          • 涉及多個key的操作通常是不被支持的,舉例來說,當兩個set映射到不同的redis實例上時,你就不能對這兩個set執行交集操作
          • 數據處理會更復雜,對於實例你必須處理多個RDB/AOF文件,爲了備份數據,需要從多個實例和主機聚合持久文件
          • 增減/刪除容量比較複雜
          • 分區最小力度是鍵,因此不能將一個鍵對應的很大的數據集映射到不同的實例
      • redis cluster(https://blog.51cto.com/14230003/2432331?source=dra
        • redis cluster採用”分而治之”的思想。
          即:將Key按照某種規則劃分成多個分區(哈希槽),將不同分區的數據存放在不同的節點上。其實也是一種分區概念。和上面所說的哈希分區類似:
          首先利用哈希算法(slot = CRC16(Key) mod 16383)將key進行計算,可以得到一個哈希槽(slot)位置,根據該算法一共可有16384個槽(0~16383)。
          我們將key存儲在對應的slot中(一個slot可以存儲多個key),而對應的master節點,負責一定範圍的槽,所有的master節點組成的集羣,覆蓋了0~16283整個槽的範圍。
        • 據說任何計算機問題都可以通過增加一箇中間層來解決。槽的概念也是這麼一箇中間層。
          key—>solt—>master
          key關注slot,而不再關注具體上在哪個master上。由slot負責關注master,這樣master節點只需要維護自己和slot的映射關係。大大降低了集羣擴容
          和收縮的難度,提升了擴展性能。
        • 集羣容錯能力由slave來提供。
          一個master節點必須至少有一個slave,slave負責冷備份,保存master的數據,在master宕機時替換master。redis cluster的默認由master負責讀寫,slave只負責備份。如果請求量較大,且對過期性要求不高,對寫請求不感興趣,可通過readyonly命令將slave配置爲可讀。
        • 節點通信:
          Redis集羣採用P2P的Gossip協議,節點之間不斷地通信交換信息,最終所有節點的狀態都會達成一致。
          ping消息:每個節點頻繁地向其他節點發起ping消息,用於檢測節點是否在線和交換節點狀態信息。
          ~每個節點每秒10次ping,每次選擇5個最久沒有通信的節點。
          ~如發現與某節點cluster_node_timeout / 2的時間未聯繫,立即ping
          ~每次ping會帶上自己節點的信息,還會攜帶1/10其他節點的信息,進行數據交換,至少包含3個其他節點的信息,最多包含總節點-2個其他節點信息
          pong消息:收到ping、meet消息時的響應消息。
          meet消息:新節點加入消息。
          fail消息:節點下線消息。
          forget消息:忘記節點消息,使一個節點下線。這個命令必須在60秒內在所有節點執行,否則超過60秒後該節點重新參與消息交換。實踐中不建議直接使用forget命令來操作節點下線。
        • 節點下線:
          當某個節點出現問題時,需要一定的傳播時間讓多數master節點認爲該節點確實不可用,才能標記標記該節點真正下線。Redis集羣的節點下線包括兩個環節:主觀下線(pfail)和客觀下線(fail)。
          主觀下線:當節點A在cluster-node-timeout時間內和節點B通信(ping-pong消息)一直失敗,則節點A認爲節點B不可用,標記爲主觀下線,並將狀態消息傳播給其他節點。
          客觀下線:當一個節點被集羣內多數master節點標記爲主觀下線後,則觸發客觀下線流程,標記該節點真正下線。
        • 故障恢復:
          當一個master節點客觀下線後,集羣會從slave節點中選出一個提升爲master節點來替換它。
          Redis集羣使用選舉-投票的算法來挑選slave節點。一個slave節點必須獲得包括故障的master節點在內的多數master節點的投票後才能被提升爲master節點。
          假設集羣規模爲3主3從,則必須至少有2個主節點存活才能執行故障恢復。如果部署時將2個主節點部署到同一臺服務器上,則該服務器不幸宕機後集羣無法執行故障恢復。
          默認情況下,Redis集羣如果有master節點不可用,即有一些槽沒有負責的節點,則整個集羣不可用。可以在配置中將cluster-require-full-coverage配置爲no,那麼master節點故障時只會影響訪問它負責的相關槽的數據,不影響對其他節點的訪問。
      • 一致性哈希(https://www.cnblogs.com/huangfuyuan/p/9880379.html#commentform)
        • redis集羣分區中,如果直接使用哈希算法:hash(key) % length。那麼當服務器數量(length)變化,會導致所有緩存的數據需要重新進行hash運算,這樣就導致原來的哪些數據訪問不到了。而這段時間如果訪問量上升了,容易引起服務器雪崩。因此,引入了一致性哈希(redis cluster未採用一致性哈希,而是哈希槽的概念)
        • 一致性哈希:通過對2^32取模的方式,保證了在增加/刪除緩存服務器的情況下,其他緩存服務器的緩存仍然可用,從而不引起雪崩問題。
        • 2^32可以想象爲:形成一個圓環,我們稱之爲:hash環。
        • 服務器:通過算法:hash(服務器的IP地址)% 2^32得到服務器映射到hash環上的位置。hash(緩存數據key)% 2^32,得到被緩存對象在hash環上的位置。
        • 緩存到哪個服務器:從被緩存對象的位置出發,沿順時針方向遇到的第一個服務器,就是當前對象將要被緩存於的服務器
        • 所以在服務器不變的情況下,一個對象必定緩存在一個固定的服務器上,那麼,當再次訪問這對象時,只要再次使用相同的算法計算即可算出這對象被緩存到哪個服務器
        • hash環的偏斜:如果幾個服務器計算後的位置相鄰很近,那麼被緩存的對象很有可能大部分集中緩存在某一臺服務器上。這種現象稱爲Hash環的偏斜。
        • 如何解決Hash環的偏斜:將現有的物理節點通過虛擬的方法複製出來,而被複製出來的節點被稱爲虛擬節點。然後將其均勻的分佈在哈希環上。
        • 某節點宕機:其他節點因爲位置已固定,依然可以提供服務。而宕機的節點會在下次容災分配時,會將宕機節點的數據分配到就近服務區上。

        • 擴容:當新增節點c,且c節點位置位於a,b節點之間,那麼只會影響b節點。a到c節點之間的數據會轉存到c節點,c到b節點的數據依然存儲在b節點上。所以一致性哈希有較好的容錯性與可擴展性。
      • Redis 哨兵模式的選舉過程(https://blog.csdn.net/sz85850597/article/details/86751215
        • 判斷節點宕機(主觀宕機、客觀宕機)
          如果一個節點a認爲主節點b宕機,那麼爲pfail,主觀宕機
          如果一半以上節點認爲主節點b宕機,那麼爲fail,客觀宕機
          注意⚠️:如果爲從節點客觀宕機,則到此爲止。如爲主節點客觀宕機,則開始選舉,進行故障轉移
        • 選舉Leader
          哨兵模式需要先選舉出一個Leader節點,由該節點選擇哪個b節點的子節點作爲接下來的主節點
          每一個Sentinel節點都可以成爲Leader,當一個Sentinel節點確認redis集羣的主節點主觀下線後,會請求其他Sentinel節點要求將自己選舉爲Leader。被請求的Sentinel節點如果沒有同意過其他Sentinel節點的選舉請求,則同意該請求(選舉票數+1),否則不同意。
          如果一個Sentinel節點獲得的選舉票數達到Leader最低票數(quorum和Sentinel節點數/2+1的最大值),則該Sentinel節點選舉爲Leader;否則重新進行選舉。
        • Leader決定新master
          選擇的的過程如下:
          1.過濾故障的從節點
          2.選擇優先級slave-priority最大的從節點作爲主節點,如不存在則繼續
          3.選擇複製偏移量(數據寫入量的字節。即:記錄寫了多少數據。主服務器會把偏移量同步給從服務器,當主從的偏移量一致,則數據是完全同步)最大的從節點作爲主節點,如不存在則繼續
          4.選擇runid(redis每次啓動的時候生成隨機的runid作爲redis的標識)最小的從節點作爲主節點
      • Redis cluster的選舉過程(https://www.cnblogs.com/mengchunchen/p/10059436.html
        • 判斷節點宕機(主觀宕機、客觀宕機)
          如果一個節點a認爲主節點b宕機,那麼爲pfail,主觀宕機
          如果一半以上節點認爲主節點b宕機,那麼爲fail,客觀宕機
        • 從節點過濾
          也就是過濾故障的從節點
          檢查每個slave node與master node斷開連接的時間,如果超過了cluster-node-timeout * cluster-slave-validity-factor,那麼就沒有資格切換成master
        • 從節點選舉
          這裏的選舉與哨兵模式的Leader決定新master一樣的規則
          slave priority(優先級)—>offset(複製偏移量)—>runId
          根據這幾個規則對宕機的master的slave進行排序
          每個從節點,都根據自己對master複製數據的offset,來設置一個選舉時間,offset越大(複製數據越多)的從節點,選舉時間越靠前,優先進行選舉
          所有的master node開始slave選舉投票,給要進行選舉的slave進行投票,如果大部分master node(N/2 + 1)都投票給了某個從節點,那麼選舉通過,那個從節點可以切換成master
          從節點執行主備切換,從節點切換爲主節點
      • 評redis clster與redis哨兵模式的選舉過程
        • 非常相似,但也有不同
        • 不同點:對比哨兵模式,Redis cluster沒有選舉leader。而是直接進行了過濾,選舉slave爲新master的操作
        • 相同點:但選舉的原理基本一致,都是根據優先級,複製量,runid來對節點進行選舉
      • redis分佈式鎖
        • 使用setnx、getset、expire、del這4個命令實現
          setnx(SET if Not eXists):只在鍵 key 不存在的情況下,將鍵 key 的值設置爲 value 。若鍵 key 已經存在, 則 SETNX 命令不做任何動作。返回值:命令在設置成功時返回 1 ,設置失敗時返回 0 。
          getset:GETSET key value,將鍵 key 的值設爲 value ,並返回鍵 key 在被設置之前的舊的value。返回值:如果鍵 key 沒有舊值, 也即是說, 鍵 key 在被設置之前並不存在, 那麼命令返回 null 。當鍵 key 存在但不是字符串類型時,命令返回一個錯誤。
          expire:爲給定 key 設置生存時間,當 key 過期時(生存時間爲 0 ),它會被自動刪除。返回值:設置成功返回 1,不成功返回0。
          del:刪除給定的一個或多個 key ,不存在的 key 會被忽略。返回值:被刪除 key 的數量
        • 分佈式鎖原理(一)(https://blog.csdn.net/dazou1/article/details/88088223):
          • A嘗試去獲取鎖lockkey,通過setnx(lockkey,currenttime+timeout)命令,對lockkey進行setnx,將value值設置爲當前時間+鎖超時時間;
          • 如果返回值爲1,說明redis服務器中還沒有lockkey,也就是沒有其他用戶擁有這個鎖,A就能獲取鎖成功;
          • 在進行相關業務執行之前,先執行expire(lockkey),對lockkey設置有效期,防止死鎖。因爲如果不設置有效期的話,lockkey將一直存在於redis中,其他用戶嘗試獲取鎖時,執行到setnx(lockkey,currenttime+timeout)時,將不能成功獲取到該鎖;
          • 執行相關業務;
          • 釋放鎖,A完成相關業務之後,要釋放擁有的鎖,也就是刪除redis中該鎖的內容,del(lockkey),接下來的用戶才能進行重新設置鎖新值。
          • 如果A在setnx成功後,A成功獲取鎖了,也就是鎖已經存到Redis裏面了,此時服務器異常關閉或是重啓,將不會執行closeOrder,也就不會設置鎖的有效期,這樣的話鎖就不會釋放了,就會產生死鎖。
            在這裏插入圖片描述
        • 分佈式鎖原理(二)https://blog.csdn.net/dazou1/article/details/88088223
          • 爲了解決原理1中會出現的死鎖問題,提出原理2雙重防死鎖,可以更好解決死鎖問題
          • 當A通過setnx(lockkey,currenttime+timeout)命令能成功設置lockkey時,即返回值爲1,過程與原理1一致;
          • 當A通過setnx(lockkey,currenttime+timeout)命令不能成功設置lockkey時,這是不能直接斷定獲取鎖失敗;因爲我們在設置鎖時,設置了鎖的超時時間timeout,噹噹前時間大於redis中存儲鍵值爲lockkey的value值時,可以認爲上一任的擁有者對鎖的使用權已經失效了,A就可以強行擁有該鎖;具體判定過程如下;
          • A通過get(lockkey),獲取redis中的存儲鍵值爲lockkey的value值,即獲取鎖的相對時間lockvalueA
          • lockvalueA!=null && currenttime>lockvalue,A通過當前的時間與鎖設置的時間做比較,如果當前時間已經大於鎖設置的時間臨界,即可以進一步判斷是否可以獲取鎖,否則說明該鎖還在被佔用,A就還不能獲取該鎖,結束,獲取鎖失敗;
          • 步驟4返回結果爲true後,通過getSet設置新的超時時間,並返回舊值lockvalueB,以作判斷,因爲在分佈式環境,在進入這裏時可能另外的進程獲取到鎖並對值進行了修改,只有舊值與返回的值一致才能說明中間未被其他進程獲取到這個鎖
          • lockvalueB == null || lockvalueA==lockvalueB,判斷:若果lockvalueB爲null,說明該鎖已經被釋放了,此時該進程可以獲取鎖;舊值與返回的lockvalueB一致說明中間未被其他進程獲取該鎖,可以獲取鎖;否則不能獲取鎖,結束,獲取鎖失敗。
        • 注意⚠️:如果多服務器部署時,要統一各個服務器的時間。
          在這裏插入圖片描述
           
      •  
發佈了42 篇原創文章 · 獲贊 36 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章