中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

T5大牛帶你解析:如何實現分布式技術

發布時間:2020-08-08 10:02:05 來源:ITPUB博客 閱讀:159 作者:lihong 欄目:編程語言

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'

問題
  1. 這把鎖強依賴數據庫的可用性。如果數據庫是一個單點,一旦數據庫掛掉,會導致業務系統不可用。
  2. 這把鎖沒有失效時間,一旦解鎖操作失敗,就會導致鎖記錄一直在數據庫中,其他線程無法再獲得到鎖。
  3. 這把鎖只能是非阻塞的,因為數據的 insert 操作,一旦插入失敗就會直接報錯。沒有獲得鎖的線程并不會進入排隊隊列,要想再次獲得鎖就要再次觸發獲得鎖操作。
  4. 這把鎖是非重入的,同一個線程在沒有釋放鎖之前無法再次獲得該鎖。因為數據中數據已經存在了。

解決辦法
  1. 單點問題可以用多數據庫實例,同時塞 N 個表,N/2+1 個成功就任務鎖定成功
  2. 寫一個定時任務,隔一段時間清除一次過期的數據。
  3. 寫一個 while 循環,不斷的重試插入,直到成功。
  4. 在數據庫表中加個字段,記錄當前獲得鎖的機器的主機信息和線程信息,那么下次再獲取鎖的時候先查詢數據庫,如果當前機器的主機信息和線程信息在數據庫可以查到的話,直接把鎖分配給他就可以了。

小結
  • 優點: 直接借助數據庫,容易理解。
  • 缺點: 會有各種各樣的問題,在解決問題的過程中會使整個方案變得越來越復雜。操作數據庫需要一定的開銷,性能問題需要考慮。

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

實現

單點實現步驟:

  1. 獲取鎖的使用,使用 setnx 加鎖,鎖的 value 值為一個隨機生成的 UUID,再使用 expire 設置一個過期值。
  2. 獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
  3. 釋放鎖的時候,通過 UUID 判斷是不是該鎖,若是該鎖,則執行 delete 進行鎖釋放。

問題
  • 單點問題。如果單機 redis 掛掉了,那么程序會跟著出錯。
  • 如果轉移使用 slave 節點,復制不是同步復制,會出現多個程序獲取鎖的情況

小結

可以考慮使用 redisson 的解決方案。

2.3. 基于 ZooKeeper 實現分布式鎖

實現

這也是 ZooKeeper 客戶端 curator 的分布式鎖實現。

  1. 創建一個目錄 mylock;
  2. 線程 A 想獲取鎖就在 mylock 目錄下創建臨時順序節點;
  3. 獲取 mylock 目錄下所有的子節點,然后獲取比自己小的兄弟節點,如果不存在,則說明當前線程順序號最小,獲得鎖;
  4. 線程 B 獲取所有節點,判斷自己不是最小節點,設置監聽比自己次小的節點;
  5. 線程 A 處理完,刪除自己的節點,線程 B 監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。

小結

ZooKeeper 版本的分布式鎖問題相對比較來說少。

  • 鎖的占用時間限制:redis 就有占用時間限制,而 ZooKeeper 則沒有,最主要的原因是 redis 目前沒有辦法知道已經獲取鎖的客戶端的狀態,是已經掛了呢還是正在執行耗時較長的業務邏輯。而 ZooKeeper 通過臨時節點就能清晰知道,如果臨時節點存在說明還在執行業務邏輯,如果臨時節點不存在說明已經執行完畢釋放鎖或者是掛了。由此看來 redis 如果能像 ZooKeeper 一樣添加一些與客戶端綁定的臨時鍵,也是一大好事。
  • 是否單點故障:redis 本身有很多中玩法,如客戶端一致性 hash,服務器端 sentinel 方案或者 cluster 方案,很難做到一種分布式鎖方式能應對所有這些方案。而 ZooKeeper 只有一種玩法,多臺機器的節點數據是一致的,沒有 redis 的那么多的麻煩因素要考慮。

總體上來說 ZooKeeper 實現分布式鎖更加的簡單,可靠性更高。但 ZooKeeper 因為需要頻繁的創建和刪除節點,性能上不如 Redis 方式。

3. 分布式 Session

在分布式場景下,一個用戶的 Session 如果只存儲在一個服務器上,那么當負載均衡器把用戶的下一個請求轉發到另一個服務器上,該服務器沒有用戶的 Session,就可能導致用戶需要重新進行登錄等操作。

分布式 Session 的幾種實現策略:

  1. 粘性 session
  2. 應用服務器間的 session 復制共享
  3. 基于 cache DB 緩存的 session 共享

3.1. Sticky Sessions

需要配置負載均衡器,使得一個用戶的所有請求都路由到一個服務器節點上,這樣就可以把用戶的 Session 存放在該服務器節點中。

缺點:當服務器節點宕機時,將丟失該服務器節點上的所有 Session。

T5大牛帶你解析:如何實現分布式技術

3.2. Session Replication

在服務器節點之間進行 Session 同步操作,這樣的話用戶可以訪問任何一個服務器節點。

缺點:占用過多內存;同步過程占用網絡帶寬以及服務器處理器時間。

T5大牛帶你解析:如何實現分布式技術

3.3. Session Server

使用一個單獨的服務器存儲 Session 數據,可以存在 MySQL 數據庫上,也可以存在 Redis 或者 Memcached 這種內存型數據庫。

缺點:需要去實現存取 Session 的代碼。

T5大牛帶你解析:如何實現分布式技術

4. 分布式存儲

通常有兩種解決方案:

  1. 數據分布:就是把數據分塊存在不同的服務器上(分庫分表)。
  2. 數據復制:讓所有的服務器都有相同的數據,提供相當的服務。

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。

T5大牛帶你解析:如何實現分布式技術

該算法比較適合每個服務器的性能差不多的場景,如果有性能存在差異的情況下,那么性能較差的服務器可能無法承擔過大的負載(下圖的 Server 2)。

T5大牛帶你解析:如何實現分布式技術

加權輪詢(Weighted Round Robbin)

加權輪詢是在輪詢的基礎上,根據服務器的性能差異,為服務器賦予一定的權值。例如下圖中,服務器 1 被賦予的權值為 5,服務器 2 被賦予的權值為 1,那么 (1, 2, 3, 4, 5) 請求會被發送到服務器 1,(6) 請求會被發送到服務器 2。

T5大牛帶你解析:如何實現分布式技術

最少連接(least Connections)

由于每個請求的連接時間不一樣,使用輪詢或者加權輪詢算法的話,可能會讓一臺服務器當前連接數過大,而另一臺服務器的連接過小,造成負載不均衡。例如下圖中,(1, 3, 5) 請求會被發送到服務器 1,但是 (1, 3) 很快就斷開連接,此時只有 (5) 請求連接服務器 1;(2, 4, 6) 請求被發送到服務器 2,只有 (2) 的連接斷開。該系統繼續運行時,服務器 2 會承擔過大的負載。

T5大牛帶你解析:如何實現分布式技術

最少連接算法就是將請求發送給當前最少連接數的服務器上。例如下圖中,服務器 1 當前連接數最小,那么新到來的請求 6 就會被發送到服務器 1 上。

T5大牛帶你解析:如何實現分布式技術

加權最少連接(Weighted Least Connection)

在最少連接的基礎上,根據服務器的性能為每臺服務器分配權重,再根據權重計算出每臺服務器能處理的連接數。

T5大牛帶你解析:如何實現分布式技術

隨機算法(Random)

把請求隨機發送到服務器上。和輪詢算法類似,該算法比較適合服務器性能差不多的場景。

T5大牛帶你解析:如何實現分布式技術

源地址哈希法 (IP Hash)

源地址哈希通過對客戶端 IP 哈希計算得到的一個數值,用該數值對服務器數量進行取模運算,取模結果便是目標服務器的序號。

  • 優點:保證同一 IP 的客戶端都會被 hash 到同一臺服務器上。
  • 缺點:不利于集群擴展,后臺服務器數量變更都會影響 hash 結果。可以采用一致性 Hash 改進。

T5大牛帶你解析:如何實現分布式技術

7.2. 實現

HTTP 重定向

HTTP 重定向負載均衡服務器收到 HTTP 請求之后會返回服務器的地址,并將該地址寫入 HTTP 重定向響應中返回給瀏覽器,瀏覽器收到后需要再次發送請求。

缺點:

  • 用戶訪問的延遲會增加;
  • 如果負載均衡器宕機,就無法訪問該站點。

T5大牛帶你解析:如何實現分布式技術

DNS 重定向

使用 DNS 作為負載均衡器,根據負載情況返回不同服務器的 IP 地址。大型網站基本使用了這種方式做為第一級負載均衡手段,然后在內部使用其它方式做第二級負載均衡。

缺點:

  • DNS 查找表可能會被客戶端緩存起來,那么之后的所有請求都會被重定向到同一個服務器。

T5大牛帶你解析:如何實現分布式技術

修改 MAC 地址

使用 LVS(Linux Virtual Server)這種鏈路層負載均衡器,根據負載情況修改請求的 MAC 地址。

T5大牛帶你解析:如何實現分布式技術

修改 IP 地址

在網絡層修改請求的目的 IP 地址。

T5大牛帶你解析:如何實現分布式技術

代理自動配置

正向代理與反向代理的區別:

  • 正向代理:發生在客戶端,是由用戶主動發起的。比如外網,客戶端通過主動訪問代理服務器,讓代理服務器獲得需要的外網數據,然后轉發回客戶端。
  • 反向代理:發生在服務器端,用戶不知道代理的存在。

PAC 服務器是用來判斷一個請求是否要經過代理。

T5大牛帶你解析:如何實現分布式技術


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

商河县| 祁阳县| 房山区| 曲靖市| 中方县| 塔城市| 金乡县| 无锡市| 兴安县| 东光县| 牡丹江市| 黎平县| 古交市| 长宁区| 遂平县| 文昌市| 阳朔县| 墨脱县| 施甸县| 宜川县| 宜宾县| 祁阳县| 惠安县| 香港| 温宿县| 东乡族自治县| 徐州市| 德令哈市| 普定县| 崇义县| 黑河市| 定襄县| 乌苏市| 磐安县| 合山市| 齐齐哈尔市| 玉门市| 虎林市| 绩溪县| 桃江县| 新源县|