T5大牛帶你解析:如何實現分散式技術
1.分散式事務
2. 分散式鎖
Java 原生 API 雖然有併發鎖,但並沒有提供分散式鎖的能力,所以針對分散式場景中的鎖需要解決的方案。
分散式鎖的解決方案大致有以下幾種:
- 基於資料庫實現
- 基於快取(redis,memcached 等)實現
- 基於 Zookeeper 實現
2.1. 基於資料庫實現分散式鎖
實現
1. 建立表
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='鎖定中的方法';
2. 獲取鎖
想要鎖住某個方法時,執行以下 SQL:
insert into methodLock(method_name,desc) values (‘method_name’,‘desc’)
因為我們對
method_name
做了唯一性約束,這裡如果有多個請求同時提交到資料庫的話,資料庫會保證只有一個操作可以成功,那麼我們就可以認為操作成功的那個執行緒獲得了該方法的鎖,可以執行方法體內容。
成功插入則獲取鎖。
3. 釋放鎖
當方法執行完畢之後,想要釋放鎖的話,需要執行以下 Sql:
delete from methodLock where method_name ='method_name'
問題
- 這把鎖強依賴資料庫的可用性。如果資料庫是一個單點,一旦資料庫掛掉,會導致業務系統不可用。
- 這把鎖沒有失效時間,一旦解鎖操作失敗,就會導致鎖記錄一直在資料庫中,其他執行緒無法再獲得到鎖。
- 這把鎖只能是非阻塞的,因為資料的 insert 操作,一旦插入失敗就會直接報錯。沒有獲得鎖的執行緒並不會進入排隊佇列,要想再次獲得鎖就要再次觸發獲得鎖操作。
- 這把鎖是非重入的,同一個執行緒在沒有釋放鎖之前無法再次獲得該鎖。因為資料中資料已經存在了。
解決辦法
- 單點問題可以用多資料庫例項,同時塞 N 個表,N/2+1 個成功就任務鎖定成功
- 寫一個定時任務,隔一段時間清除一次過期的資料。
- 寫一個 while 迴圈,不斷的重試插入,直到成功。
- 在資料庫表中加個欄位,記錄當前獲得鎖的機器的主機資訊和執行緒資訊,那麼下次再獲取鎖的時候先查詢資料庫,如果當前機器的主機資訊和執行緒資訊在資料庫可以查到的話,直接把鎖分配給他就可以了。
小結
- 優點: 直接藉助資料庫,容易理解。
- 缺點: 會有各種各樣的問題,在解決問題的過程中會使整個方案變得越來越複雜。運算元據庫需要一定的開銷,效能問題需要考慮。
2.2. 基於 Redis 實現分散式鎖
相比於用資料庫來實現分散式鎖,基於快取實現的分散式鎖的效能會更好一些。目前有很多成熟的分散式產品,包括 Redis、memcache、Tair 等。這裡以 Redis 舉例。
Redis 命令
- setnx - setnx key val:當且僅當 key 不存在時,set 一個 key 為 val 的字串,返回 1;若 key 存在,則什麼都不做,返回 0。
- expire - expire key timeout:為 key 設定一個超時時間,單位為 second,超過這個時間鎖會自動釋放,避免死鎖。
- delete - delete key:刪除 key
實現
單點實現步驟:
- 獲取鎖的使用,使用 setnx 加鎖,鎖的 value 值為一個隨機生成的 UUID,再使用 expire 設定一個過期值。
- 獲取鎖的時候還設定一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
- 釋放鎖的時候,透過 UUID 判斷是不是該鎖,若是該鎖,則執行 delete 進行鎖釋放。
問題
- 單點問題。如果單機 redis 掛掉了,那麼程式會跟著出錯。
- 如果轉移使用 slave 節點,複製不是同步複製,會出現多個程式獲取鎖的情況
小結
可以考慮使用 redisson 的解決方案。
2.3. 基於 ZooKeeper 實現分散式鎖
實現
這也是 ZooKeeper 客戶端 curator 的分散式鎖實現。
- 建立一個目錄 mylock;
- 執行緒 A 想獲取鎖就在 mylock 目錄下建立臨時順序節點;
- 獲取 mylock 目錄下所有的子節點,然後獲取比自己小的兄弟節點,如果不存在,則說明當前執行緒順序號最小,獲得鎖;
- 執行緒 B 獲取所有節點,判斷自己不是最小節點,設定監聽比自己次小的節點;
- 執行緒 A 處理完,刪除自己的節點,執行緒 B 監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。
小結
ZooKeeper 版本的分散式鎖問題相對比較來說少。
- 鎖的佔用時間限制:redis 就有佔用時間限制,而 ZooKeeper 則沒有,最主要的原因是 redis 目前沒有辦法知道已經獲取鎖的客戶端的狀態,是已經掛了呢還是正在執行耗時較長的業務邏輯。而 ZooKeeper 透過臨時節點就能清晰知道,如果臨時節點存在說明還在執行業務邏輯,如果臨時節點不存在說明已經執行完畢釋放鎖或者是掛了。由此看來 redis 如果能像 ZooKeeper 一樣新增一些與客戶端繫結的臨時鍵,也是一大好事。
- 是否單點故障:redis 本身有很多中玩法,如客戶端一致性 hash,伺服器端 sentinel 方案或者 cluster 方案,很難做到一種分散式鎖方式能應對所有這些方案。而 ZooKeeper 只有一種玩法,多臺機器的節點資料是一致的,沒有 redis 的那麼多的麻煩因素要考慮。
總體上來說 ZooKeeper 實現分散式鎖更加的簡單,可靠性更高。但 ZooKeeper 因為需要頻繁的建立和刪除節點,效能上不如 Redis 方式。
3. 分散式 Session
在分散式場景下,一個使用者的 Session 如果只儲存在一個伺服器上,那麼當負載均衡器把使用者的下一個請求轉發到另一個伺服器上,該伺服器沒有使用者的 Session,就可能導致使用者需要重新進行登入等操作。
分散式 Session 的幾種實現策略:
- 粘性 session
- 應用伺服器間的 session 複製共享
- 基於 cache DB 快取的 session 共享
3.1. Sticky Sessions
需要配置負載均衡器,使得一個使用者的所有請求都路由到一個伺服器節點上,這樣就可以把使用者的 Session 存放在該伺服器節點中。
缺點:當伺服器節點當機時,將丟失該伺服器節點上的所有 Session。
3.2. Session Replication
在伺服器節點之間進行 Session 同步操作,這樣的話使用者可以訪問任何一個伺服器節點。
缺點:佔用過多記憶體;同步過程佔用網路頻寬以及伺服器處理器時間。
3.3. Session Server
使用一個單獨的伺服器儲存 Session 資料,可以存在 MySQL 資料庫上,也可以存在 Redis 或者 Memcached 這種記憶體型資料庫。
缺點:需要去實現存取 Session 的程式碼。
4. 分散式儲存
通常有兩種解決方案:
- 資料分佈:就是把資料分塊存在不同的伺服器上(分庫分表)。
- 資料複製:讓所有的伺服器都有相同的資料,提供相當的服務。
5. 分散式快取
使用快取的好處:
- 提升資料讀取速度
- 提升系統擴充套件能力,透過擴充套件快取,提升系統承載能力
- 降低儲存成本,Cache+DB 的方式可以承擔原有需要多臺 DB 才能承擔的請求量,節省機器成本
根據業務場景,通常快取有以下幾種使用方式
- 懶漢式(讀時觸發):寫入 DB 後, 然後把相關的資料也寫入 Cache
- 飢餓式(寫時觸發):先查詢 DB 裡的資料, 然後把相關的資料寫入 Cache
- 定期重新整理:適合週期性的跑資料的任務,或者列表型的資料,而且不要求絕對實時性
快取分類:
- 應用內快取:如:EHCache
- 分散式快取:如:Memached、Redis
6. 分散式計算
7. 負載均衡
7.1. 演算法
輪詢(Round Robin)
輪詢演算法把每個請求輪流傳送到每個伺服器上。下圖中,一共有 6 個客戶端產生了 6 個請求,這 6 個請求按 (1, 2, 3, 4, 5, 6) 的順序傳送。最後,(1, 3, 5) 的請求會被髮送到伺服器 1,(2, 4, 6) 的請求會被髮送到伺服器 2。
該演算法比較適合每個伺服器的效能差不多的場景,如果有效能存在差異的情況下,那麼效能較差的伺服器可能無法承擔過大的負載(下圖的 Server 2)。
加權輪詢(Weighted Round Robbin)
加權輪詢是在輪詢的基礎上,根據伺服器的效能差異,為伺服器賦予一定的權值。例如下圖中,伺服器 1 被賦予的權值為 5,伺服器 2 被賦予的權值為 1,那麼 (1, 2, 3, 4, 5) 請求會被髮送到伺服器 1,(6) 請求會被髮送到伺服器 2。
最少連線(least Connections)
由於每個請求的連線時間不一樣,使用輪詢或者加權輪詢演算法的話,可能會讓一臺伺服器當前連線數過大,而另一臺伺服器的連線過小,造成負載不均衡。例如下圖中,(1, 3, 5) 請求會被髮送到伺服器 1,但是 (1, 3) 很快就斷開連線,此時只有 (5) 請求連線伺服器 1;(2, 4, 6) 請求被髮送到伺服器 2,只有 (2) 的連線斷開。該系統繼續執行時,伺服器 2 會承擔過大的負載。
最少連線演算法就是將請求傳送給當前最少連線數的伺服器上。例如下圖中,伺服器 1 當前連線數最小,那麼新到來的請求 6 就會被髮送到伺服器 1 上。
加權最少連線(Weighted Least Connection)
在最少連線的基礎上,根據伺服器的效能為每臺伺服器分配權重,再根據權重計算出每臺伺服器能處理的連線數。
隨機演算法(Random)
把請求隨機傳送到伺服器上。和輪詢演算法類似,該演算法比較適合伺服器效能差不多的場景。
源地址雜湊法 (IP Hash)
源地址雜湊透過對客戶端 IP 雜湊計算得到的一個數值,用該數值對伺服器數量進行取模運算,取模結果便是目標伺服器的序號。
- 優點:保證同一 IP 的客戶端都會被 hash 到同一臺伺服器上。
- 缺點:不利於叢集擴充套件,後臺伺服器數量變更都會影響 hash 結果。可以採用一致性 Hash 改進。
7.2. 實現
HTTP 重定向
HTTP 重定向負載均衡伺服器收到 HTTP 請求之後會返回伺服器的地址,並將該地址寫入 HTTP 重定向響應中返回給瀏覽器,瀏覽器收到後需要再次傳送請求。
缺點:
- 使用者訪問的延遲會增加;
- 如果負載均衡器當機,就無法訪問該站點。
DNS 重定向
使用 DNS 作為負載均衡器,根據負載情況返回不同伺服器的 IP 地址。大型網站基本使用了這種方式做為第一級負載均衡手段,然後在內部使用其它方式做第二級負載均衡。
缺點:
- DNS 查詢表可能會被客戶端快取起來,那麼之後的所有請求都會被重定向到同一個伺服器。
修改 MAC 地址
使用 LVS(Linux Virtual Server)這種鏈路層負載均衡器,根據負載情況修改請求的 MAC 地址。
修改 IP 地址
在網路層修改請求的目的 IP 地址。
代理自動配置
正向代理與反向代理的區別:
- 正向代理:發生在客戶端,是由使用者主動發起的。比如外網,客戶端透過主動訪問代理伺服器,讓代理伺服器獲得需要的外網資料,然後轉發回客戶端。
- 反向代理:發生在伺服器端,使用者不知道代理的存在。
PAC 伺服器是用來判斷一個請求是否要經過代理。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69917606/viewspace-2642400/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 大型分散式系統現場,阿里大牛帶你實戰分散式系統分散式阿里
- 大牛帶你玩轉 CSS3 3D 技術CSSS33D
- 技術分享| Etcd如何實現分散式負載均衡及分散式通知與協調分散式負載
- 小白如何入門大資料,資深技術大牛帶你回顧學習路線!大資料
- 華為CloudNative分散式資料庫技術解析Cloud分散式資料庫
- 載均衡技術全解析:Pulsar 分散式系統的最佳實踐分散式
- 分散式事務之事務實現模式與技術(四)分散式模式
- HDFS分散式儲存的意義及技術解析分散式
- Redis如何實現分散式鎖Redis分散式
- zookeeper分散式鎖,你用php是如何實現的呀分散式PHP
- 螞蟻技術專家:一篇文章帶你學習分散式事務分散式
- 滴滴曹樂:如何成為技術大牛?
- 理論+實踐,帶你瞭解分散式訓練分散式
- 「分散式技術專題」SQL 解析的 AP/TP 判別分散式SQL
- 分散式技術-Zookeeper概述分散式
- 【分散式技術專題】「分散式技術架構」一文帶你釐清分散式事務協議及分散式一致性協議的演算法原理和核心流程機制(Paxos篇)分散式架構協議演算法
- ElasticSearch是如何實現分散式的?Elasticsearch分散式
- 如何用 Redis 實現分散式鎖Redis分散式
- 如何使用Redis實現分散式鎖Redis分散式
- 使用 Redis 實現分散式系統輕量級協調技術Redis分散式
- 音視訊技術傻瓜版解析:帶你解鎖RTMP
- 開源分散式資料庫RadonDB的核心技術與實現分散式資料庫
- 技術分享| 基於 Etcd 的分散式鎖實現原理及方案分散式
- 搞懂分散式技術12:分散式ID生成方案分散式
- 搞懂分散式技術17:淺析分散式事務分散式
- 【分散式通知技術-JGroups】分散式
- 分散式儲存技術概念分散式
- 如何用REDIS實現分散式快取Redis分散式快取
- 深度好文 | 資深技術Leader曹樂:如何成為技術大牛
- 天天寫業務程式碼,如何成為技術大牛?
- 技術菜鳥如何聘到大牛工程師?工程師
- 分散式計算技術(上):經典計算框架MapReduce、Spark 解析分散式框架Spark
- 「分散式技術專題」兩種向量化執行引擎的實現方法分散式
- 分散式技術中不可或缺的分散式互斥方案分散式
- 【技術解析】如何用Docker實現SequoiaDB叢集的快速部署Docker
- RAG技術全面解析:Langchain4j如何實現智慧問答的跨越式進化?LangChain
- 帶你快速瞭解 MongoDB 分散式叢集MongoDB分散式
- 架構師帶你玩轉分散式鎖架構分散式