1. 程式人生 > >java 併發程式設計學習筆記(九)多執行緒併發拓展

java 併發程式設計學習筆記(九)多執行緒併發拓展

                                         多執行緒併發拓展

(1)死鎖

public class DeadLockTest implements  Runnable {

    private int flag ;

    private static Object o1=new Object();
    private static Object o2=new Object();

    public DeadLockTest(int flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if(flag == 0){
            synchronized (o2){

                try {
                    Thread.sleep(500);
                    System.out.println("Thread1開始");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o1){
                    System.out.println("Thread1結束!");
                }
            }
        }
        if(flag ==1){
            synchronized (o1){
                try {
                    Thread.sleep(500);
                    System.out.println("Thread2開始");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o2){
                    System.out.println("Thread2結束!");
                }
            }
        }


    }
    public static void  main(String[] args){

        new Thread(new DeadLockTest(0)).start();
        new Thread(new DeadLockTest(1)).start();
    }

}

死鎖問題是多執行緒特有的問題,它可以被認為是執行緒間切換消耗系統性能的一種極端情況。在死鎖時,執行緒間相互等待資源,而又不釋放自身的資源,導致無窮無盡的等待,其結果是系統任務永遠無法執行完成。死鎖問題是在多執行緒開發中應該堅決避免和杜絕的問題。

一般來說,要出現死鎖問題需要滿足以下條件:

1. 互斥條件:一個資源每次只能被一個執行緒使用。

2. 請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。

3. 不剝奪條件:程序已獲得的資源,在未使用完之前,不能強行剝奪。

4. 迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。

只要破壞死鎖 4 個必要條件之一中的任何一個,死鎖問題就能被解決。

死鎖解決方案

死鎖是由四個必要條件導致的,所以一般來說,只要破壞這四個必要條件中的一個條件,死鎖情況就應該不會發生。

  1. 如果想要打破互斥條件,我們需要允許程序同時訪問某些資源,這種方法受制於實際場景,不太容易實現條件;
  2. 打破不可搶佔條件,這樣需要允許程序強行從佔有者那裡奪取某些資源,或者簡單一點理解,佔有資源的程序不能再申請佔有其他資源,必須釋放手上的資源之後才能發起申請,這個其實也很難找到適用場景;
  3. 程序在執行前申請得到所有的資源,否則該程序不能進入準備執行狀態。這個方法看似有點用處,但是它的缺點是可能導致資源利用率和程序併發性降低;
  4. 避免出現資源申請環路,即對資源事先分類編號,按號分配。這種方式可以有效提高資源的利用率和系統吞吐量,但是增加了系統開銷,增大了程序對資源的佔用時間。

如果我們在死鎖檢查時發現了死鎖情況,那麼就要努力消除死鎖,使系統從死鎖狀態中恢復過來。消除死鎖的幾種方式:

1. 最簡單、最常用的方法就是進行系統的重新啟動,不過這種方法代價很大,它意味著在這之前所有的程序已經完成的計算工作都將付之東流,包括參與死鎖的那些程序,以及未參與死鎖的程序;

2. 撤消程序,剝奪資源。終止參與死鎖的程序,收回它們佔有的資源,從而解除死鎖。這時又分兩種情況:一次性撤消參與死鎖的全部程序,剝奪全部資源;或者逐步撤消參與死鎖的程序,逐步收回死鎖程序佔有的資源。一般來說,選擇逐步撤消的程序時要按照一定的原則進行,目的是撤消那些代價最小的程序,比如按程序的優先順序確定程序的代價;考慮程序執行時的代價和與此程序相關的外部作業的代價等因素;

3. 程序回退策略,即讓參與死鎖的程序回退到沒有發生死鎖前某一點處,並由此點處繼續執行,以求再次執行時不再發生死鎖。雖然這是個較理想的辦法,但是操作起來系統開銷極大,要有堆疊這樣的機構記錄程序的每一步變化,以便今後的回退,有時這是無法做到的。

其實即便是商業產品,依然會有很多死鎖情況的發生,例如 MySQL 資料庫,它也經常容易出現死鎖案例。

(2)多執行緒併發最佳實踐

  • 使用本地變數
  • 使用不可變類
  • 最小化鎖的作用域範圍s=1/(1-a+a/n)  (a 平行計算部分所佔比例,n 並行處理節點個數,S 加速比)
  • 使用執行緒池Executor ,而不是直接new Thread執行
  • 寧可使用同步也不要使用執行緒的wait和notiyf
  • 使用BlockingQueue 實現生產-消費模式
  • 使用併發集合而不是加了鎖的同步集合
  • 使用Semaphore建立有界的訪問
  • 寧可使用同步程式碼塊,也不適用同步的方法
  • 避免使用靜態變數

(3)高併發處理思路

擴容 

垂直 擴容 :(縱向擴充套件)提高系統的 部件能力

水平擴容:(橫向擴容):增加更多系統成員來實現

資料庫擴容:

讀操作擴充套件:memcache,redis,cdn等快取

寫操作擴充套件:Cassandra,Hbase等

快取:

快取命中率的影響因素: 業務場景合業務需求,快取的設計(粒度和策略),快取容量和基礎設施

本地快取:程式設計實現(成員變數、區域性變數、靜態變數)Guava Cache

分散式快取:  Memcache 、Redis

高併發場景下快取常見問題:

1、快取一致性問題

當資料時效性要求很高時,需要保證快取中的資料與資料庫中的保持一致,而且需要保證快取節點和副本中的資料也保持一致,不能出現差異現象。這就比較依賴快取的過期和更新策略。一般會在資料發生更改的時,主動更新快取中的資料或者移除對應的快取。

2、快取併發問題

快取過期後將嘗試從後端資料庫獲取資料,這是一個看似合理的流程。但是,在高併發場景下,有可能多個請求併發的去從資料庫獲取資料,對後端資料庫造成極大的衝擊,甚至導致 “雪崩”現象。此外,當某個快取key在被更新時,同時也可能被大量請求在獲取,這也會導致一致性的問題。那如何避免類似問題呢?我們會想到類似“鎖”的機制,在快取更新或者過期的情況下,先嚐試獲取到鎖,當更新或者從資料庫獲取完成後再釋放鎖,其他的請求只需要犧牲一定的等待時間,即可直接從快取中繼續獲取資料。

3、快取穿透問題

快取穿透在有些地方也稱為“擊穿”。很多朋友對快取穿透的理解是:由於快取故障或者快取過期導致大量請求穿透到後端資料庫伺服器,從而對資料庫造成巨大沖擊。

這其實是一種誤解。真正的快取穿透應該是這樣的

在高併發場景下,如果某一個key被高併發訪問,沒有被命中,出於對容錯性考慮,會嘗試去從後端資料庫中獲取,從而導致了大量請求達到資料庫,而當該key對應的資料本身就是空的情況下,這就導致資料庫中併發的去執行了很多不必要的查詢操作,從而導致巨大沖擊和壓力。

可以通過下面的幾種常用方式來避免快取傳統問題:

快取空物件

對查詢結果為空的物件也進行快取,如果是集合,可以快取一個空的集合(非null),如果是快取單個物件,可以通過欄位標識來區分。這樣避免請求穿透到後端資料庫。同時,也需要保證快取資料的時效性。這種方式實現起來成本較低,比較適合命中不高,但可能被頻繁更新的資料。

單獨過濾處理

對所有可能對應資料為空的key進行統一的存放,並在請求前做攔截,這樣避免請求穿透到後端資料庫。這種方式實現起來相對複雜,比較適合命中不高,但是更新不頻繁的資料。

3、快取顛簸問題

快取的顛簸問題,有些地方可能被成為“快取抖動”,可以看做是一種比“雪崩”更輕微的故障,但是也會在一段時間內對系統造成衝擊和效能影響。一般是由於快取節點故障導致。業內推薦的做法是通過一致性Hash演算法來解決。

4、快取的雪崩現象

快取雪崩就是指由於快取的原因,導致大量請求到達後端資料庫,從而導致資料庫崩潰,整個系統崩潰,發生災難。導致這種現象的原因有很多種,上面提到的“快取併發”,“快取穿透”,“快取顛簸”等問題,其實都可能會導致快取雪崩現象發生。這些問題也可能會被惡意攻擊者所利用。還有一種情況,例如某個時間點內,系統預載入的快取週期性集中失效了,也可能會導致雪崩。為了避免這種週期性失效,可以通過設定不同的過期時間,來錯開快取過期,從而避免快取集中失效。

從應用架構角度,我們可以通過限流、降級、熔斷等手段來降低影響,也可以通過多級快取來避免這種災難。

此外,從整個研發體系流程的角度,應該加強壓力測試,儘量模擬真實場景,儘早的暴露問題從而防範。

5、快取無底洞現象

該問題由 facebook 的工作人員提出的, facebook 在 2010 年左右,memcached 節點就已經達3000 個,快取數千 G 內容。

他們發現了一個問題---memcached 連線頻率,效率下降了,於是加 memcached 節點,

添加了後,發現因為連線頻率導致的問題,仍然存在,並沒有好轉,稱之為”無底洞現象”。

目前主流的資料庫、快取、Nosql、搜尋中介軟體等技術棧中,都支援“分片”技術,來滿足“高效能、高併發、高可用、可擴充套件”等要求。有些是在client端通過Hash取模(或一致性Hash)將值對映到不同的例項上,有些是在client端通過範圍取值的方式對映的。當然,也有些是在服務端進行的。但是,每一次操作都可能需要和不同節點進行網路通訊來完成,例項節點越多,則開銷會越大,對效能影響就越大。 

主要可以從如下幾個方面避免和優化:

資料分佈方式

有些業務資料可能適合Hash分佈,而有些業務適合採用範圍分佈,這樣能夠從一定程度避免網路IO的開銷。

IO優化

可以充分利用連線池,NIO等技術來儘可能降低連線開銷,增強併發連線能力。

資料訪問方式

一次性獲取大的資料集,會比分多次去獲取小資料集的網路IO開銷更小。 

當然,快取無底洞現象並不常見。在絕大多數的公司裡可能根本不會遇到。

訊息佇列

流程A在處理時沒有在當前執行緒同步的處理完而是直接傳送了一條訊息A1到佇列裡,然後訊息佇列過了一段時間(可能是幾毫秒 幾秒 幾分鐘)這個訊息開始被處理,訊息處理的過程就相當於流程A被處理;當然這只是一個簡單的模型下面我們套用實際的場景來看一下,比如下單成功後傳送簡訊提醒;如果沒有訊息佇列我們會選擇同步呼叫發簡訊的介面並等待簡訊傳送成功,正常情況下這麼做是沒有問題的但是如果發簡訊的時候簡訊接口出問題了或者說呼叫超時了等意外情況,這個時候我們就需要設計對應的方案來解決前提是這些方案的設計會比較複雜;
但是當我們使用訊息佇列以後這個事情就會變得非常簡單,使用訊息佇列以後有如下好處:
① 實現了非同步解耦
② 設計變的更加簡單了
③ 保證了資料的最終一致性;
④ 提高效率;

訊息佇列特性:

1 與業務無關 : 只做訊息分發

2 FIFO : 先投遞先到達

3 容災 : 節點的動態增刪和訊息的持久化

4 效能 : 吞吐量提升,系統內部通訊效率提高

為什麼需要訊息佇列?

生產和消費的速度或穩定性等因素不一致;

訊息佇列的好處

1 業務解耦

2 最終一致性 : 用記錄和補償的方式來處理,在做所有的不確定事情之前先記錄然後再去做,它的結果通常分為三種成功失敗或者不確定(比如說超時等);如果是成功我們就可以清楚掉記錄,如果是失敗或者不確定我們可以通過定時任務將所有事情重新做一遍直到成功為止;

3 廣播 : 如果沒有訊息佇列每一個新的業務方介入都需要聯調一次介面,使用訊息佇列只需要關心訊息是否送達到訊息佇列,新接入的介面訂閱相關的訊息自己做處理就可以了;

4 錯峰與流控 : 上下游對於事情的處理是不同的,比如WEB前端每秒承受上千萬的請求都是可以的但是資料庫的處理卻非常有限;迫於成本的壓力我們不能要求資料庫的機器數量與前端資源一樣;這樣的問題同樣存在於系統與系統之間,比如簡訊系統的速度卡在閘道器上邊它與前端的併發量不是一個數量級的,使用者玩幾秒種收到簡訊也是可以的;針對於這樣的場景如果沒有訊息佇列也能實現但是系統的複雜度非常的高;

常用的訊息佇列介紹

  • Kafka

 

Kafka是Apache下的一個子專案,是一個高效能 跨語言 分散式釋出訂閱訊息佇列系統;

1 Kafka的特性
① 快速持久化 : 它可以在o1的系統開銷下實現訊息的持久化;
② 高吞吐 : 在一臺普通的伺服器上就可以達到10w/秒的吞吐速率;
③ 天生的分散式 : 所有元件天生支援分散式且自動實現負載均衡;

2 Kafka基礎定義
① Broker : Kafka叢集包含一個或多個伺服器,這個伺服器就被稱為Producer;
② Topic : 指每條釋出到Kafka的訊息都有一個類別,這個類別叫做Topic;物理上不同Topic的訊息是分開儲存的,邏輯上一個Topic訊息雖然儲存在一個或者多Producer上但是使用者只需指定訊息的Topic就可以生產或者消費資料而不用關心資料存在哪裡;
③ Partition : 是物理上的概念,每個Topic包含一個或者多個Partition;
④ Producer : 負責釋出訊息到Kafka的Broker裡邊;
⑤ consumer : 訊息消費者,向Kafka broker讀取訊息的客戶端;
⑥ Consumer Group : 每個Consumer屬於一個特定的Consumer Group(可為每個Consumer指定group name,若不指定group name則屬於預設的group);

  • RabbitMQ

 

RabbitMQ是流行的開源訊息佇列系統,用erlang語言開發。RabbitMQ是AMQP(高階訊息佇列協議)的標準實現;

1 RabbitMQ的使用過程
(1)客戶端連線到訊息佇列伺服器,開啟一個channel。
(2)客戶端宣告一個exchange,並設定相關屬性。
(3)客戶端宣告一個queue,並設定相關屬性。
(4)客戶端使用routing key,在exchange和queue之間建立好繫結關係。
(5)客戶端投遞訊息到exchange。

2 RabbitMQ的概念
Broker:簡單來說就是訊息佇列伺服器實體。
Exchange:訊息交換機,它指定訊息按什麼規則,路由到哪個佇列。
Queue:訊息佇列載體,每個訊息都會被投入到一個或多個佇列。
Binding:繫結,它的作用就是把exchange和queue按照路由規則繫結起來。
Routing Key:路由關鍵字,exchange根據這個關鍵字進行訊息投遞。
vhost:虛擬主機,一個broker裡可以開設多個vhost,用作不同使用者的許可權分離。
producer:訊息生產者,就是投遞訊息的程式。
consumer:訊息消費者,就是接受訊息的程式。
channel:訊息通道,在客戶端的每個連線裡,可建立多個channel,每個channel代表一個會話任務。

(4)高併發應用拆分 

比如一個股票系統有使用者資訊、開戶、股票行情、交易、訂單等,拆分後如下圖所示:

原則

  • 業務優先

每個系統都會有多個模組,每個模組又有多個業務功能;按照業務邊界進行切割,再對模組進行拆分。

  • 循序漸進

邊拆分邊測試,保證系統的正常執行。

  • 兼顧技術:重構、分層

不能為了分散式而分散式,拆分過程不僅是業務梳理也是程式碼重構的過程,根據技術進行分層來分配工作,ui對使用者體驗,熟悉C和C++對伺服器,熟悉資料庫的對資料庫,做到術業有專攻,合適的人去做合適的事情。

  • 可靠測試

測試完畢後,才可進行下一步,每一步都要有足夠的測試才可進行下一步,避免小錯誤引起蝴蝶效應。

思考

  • 應用之間通訊: RPC ( dubbo等)、訊息佇列

訊息佇列通常用於傳輸資料包小但是資料量大,對實時性要求低的場景,比如下單後簡訊通知客戶。而採用RPC要求實時性高,這裡通常不會http或者service服務,原因是使用PRC呼叫service方法無感知,在配置好後和本地方法很像。

  • 應用之間資料庫設計:每個應用都有獨立的資料庫

通常情況下,每個應用都有自己獨立的資料庫,如果共同使用的資訊,可以考慮放在common中使用。

  • 避免事務操作跨應用

分散式事務是一個很消耗資源的問題,應用之間服務分開開發,能夠保持相互獨立。

框架

服務化 Dubbo

 微服務Spring Cloud

 微服務:獨立的服務共同組成一個系統

要實踐微服務要解決4個問題:


客戶端如何訪問這些服務
API Gateway提供統一的服務入口,對前臺透明,同時可以聚合後臺的服務,提供安全過濾流控等api的管理功能
服務之間是如何通訊的
非同步的話使用訊息佇列,同步呼叫使用REST或者是RPC,Rest可以使用springboot,RPC通常使用Dubbo
同步呼叫一致性強但是出現呼叫問題,REST一般基於http實現,能夠跨客戶端,同時對客戶端沒有更多的要求。
RPC的傳輸協議更高效,安全也更加可控。特別是在一個公司內部如果有統一的開發規範和統一的框架,它的開發效率會更加明顯。
而非同步訊息在分散式系統中有特別廣泛的應用,它既能減少呼叫服務之間的耦合,又能成為呼叫之間的緩衝,確保訊息積壓不會沖垮被呼叫方。
同時保證呼叫方的使用者的體驗,繼續幹自己的活。付出的代價是一致性的減慢,需要接受資料的最終一致性
如何實現如此多服務
在微服務架構中一般每一服務都會拷貝進行負載均衡,服務如何相互感知,如何相互管理,這就是服務發現的問題了,一般都是進行服務註冊資訊的分散式管理。
服務掛了該如何解決,有什麼備份方案和應急處理機制
分散式最大的特性就是網路是不可靠的,當系統是由一系列的呼叫鏈組成的時候,其中任何一個出問題都不至於影響到整個鏈路。
相應的手段有:重試機制、應用的限流、熔斷機制、負載均衡、系統降級

(5) 應用限流

限流就是通過對併發訪問/請求進行限速或一個時間視窗內的請求進行限速,從而達到保護系統的目的。一般系統可以通過壓測來預估能處理的峰值,一旦達到設定的峰值閥值,則可以拒絕服務(定向錯誤頁或告知資源沒有了)、排隊或等待(例如:秒殺、評論、下單)、降級(返回預設資料)

限流不能亂用,否則正常流量會出現一些奇怪的問題,從而導致使用者抱怨。

 

假設有130W到140W的資料插入到資料庫中,如果沒有做限流,資料庫的主庫會突然接收到130w的插入操作

首先是網路上的開銷,很可能直接把頻寬佔滿,導致其他請求無法正常傳輸和處理,其次會是資料庫的負載突然增高,導致無法處理某些資料庫的操作,也有可能資料庫沒有足夠的連線導致某些資料庫插入查詢失敗;

還有一點就是現在資料庫都做了主從設計,主資料庫的資料還要同步給從庫,這時瞬間插入了大量的資料,會帶來從庫和主庫的延遲特別大,這時從庫查詢不準確的概率也會跟著提升。

如果我們放慢插入資料庫的速度,這時插入資料庫主庫的速率會很正常,同步到從庫也很正常。網路消耗也可以接收不會影響其他服務。

 1.計數器法

有時我們還會使用計數器來進行限流,主要用來限制一定時間內的總併發數,比如資料庫連線池、執行緒池、秒殺的併發數;計數器限流只要一定時間內的總請求數超過設定的閥值則進行限流,是一種簡單粗暴的總數量限流,而不是平均速率限流。

這個方法有一個致命問題:臨界問題——當遇到惡意請求,在0:59時,瞬間請求100次,並且在1:00請求100次,那麼這個使用者在1秒內請求了200次,使用者可以在重置節點突發請求,而瞬間超過我們設定的速率限制,使用者可能通過演算法漏洞擊垮我們的應用。

2.滑動視窗演算法

 在上圖中,整個紅色矩形框是一個時間視窗,在我們的例子中,一個時間視窗就是1分鐘,然後我們將時間視窗進行劃分,如上圖我們把滑動視窗

劃分為6格,所以每一格代表10秒,每超過10秒,我們的時間視窗就會向右滑動一格,每一格都有自己獨立的計數器,例如:一個請求在0:35到達,

那麼0:30到0:39的計數器會+1,那麼滑動視窗是怎麼解決臨界點的問題呢?如上圖,0:59到達的100個請求會在灰色區域格子中,而1:00到達的請求

會在紅色格子中,視窗會向右滑動一格,那麼此時間視窗內的總請求數共200個,超過了限定的100,所以此時能夠檢測出來觸發了限流。

回頭看看計數器演算法,會發現,其實計數器演算法就是視窗滑動演算法,只不過計數器演算法沒有對時間視窗進行劃分,所以是一格。

由此可見,當滑動視窗的格子劃分越多,限流的統計就會越精確。

 

3.漏銅演算法

這個演算法很簡單。首先,我們有一個固定容量的桶,有水進來,也有水出去。對於流進來的水,我們無法預計共有多少水流進來,也無法預計流水速度,但

對於流出去的水來說,這個桶可以固定水流的速率,而且當桶滿的時候,多餘的水會溢位來。

 

4.令牌桶演算法

從上圖中可以看出,令牌演算法有點複雜,桶裡存放著令牌token。桶一開始是空的,token以固定的速率r往桶裡面填充,直到達到桶的容量,多餘的token會

被丟棄。每當一個請求過來時,就會嘗試著移除一個token,如果沒有token,請求無法通過。

(6)服務降級與服務熔斷

服務降級:

服務壓力劇增的時候根據當前的業務情況及流量對一些服務和頁面有策略的降級,以此環節伺服器的壓力,以保證核心任務的進行。

同時保證部分甚至大部分任務客戶能得到正確的相應。也就是當前的請求處理不了了或者出錯了,給一個預設的返回。

服務熔斷:

在股票市場,熔斷這個詞大家都不陌生,是指當股指波幅達到某個點後,交易所為控制風險採取的暫停交易措施。相應的,服務熔斷一般是指軟體系統中,由於某些原因使得服務出現了過載現象,為防止造成整個系統故障,從而採用的一種保護措施,所以很多地方把熔斷亦稱為過載保護。

 

降級分類

降級按照是否自動化可分為:自動開關降級和人工開關降級。

降級按照功能可分為:讀服務降級、寫服務降級。

降級按照處於的系統層次可分為:多級降級。

 

自動降級分類

(1)、超時降級:主要配置好超時時間和超時重試次數和機制,並使用非同步機制探測回覆情況

(2)、失敗次數降級:主要是一些不穩定的api,當失敗呼叫次數達到一定閥值自動降級,同樣要使用非同步機制探測回覆情況

(3)、故障降級:比如要呼叫的遠端服務掛掉了(網路故障、DNS故障、http服務返回錯誤的狀態碼、rpc服務丟擲異常),則可以直接降級。降級後的處理方案有:預設值(比如庫存服務掛了,返回預設現貨)、兜底資料(比如廣告掛了,返回提前準備好的一些靜態頁面)、快取(之前暫存的一些快取資料)

(4)、限流降級

當我們去秒殺或者搶購一些限購商品時,此時可能會因為訪問量太大而導致系統崩潰,此時開發者會使用限流來進行限制訪問量,當達到限流閥值,後續請求會被降級;降級後的處理方案可以是:排隊頁面(將使用者導流到排隊頁面等一會重試)、無貨(直接告知使用者沒貨了)、錯誤頁(如活動太火爆了,稍後重試)。

 

服務熔斷和服務降級比較:

兩者其實從有些角度看是有一定的類似性的:
  1. 目的很一致,都是從可用性可靠性著想,為防止系統的整體緩慢甚至崩潰,採用的技術手段;
  2. 最終表現類似,對於兩者來說,最終讓使用者體驗到的是某些功能暫時不可達或不可用;
  3. 粒度一般都是服務級別,當然,業界也有不少更細粒度的做法,比如做到資料持久層(允許查詢,不允許增刪改);
  4. 自治性要求很高,熔斷模式一般都是服務基於策略的自動觸發,降級雖說可人工干預,但在微服務架構下,完全靠人顯然不可能,開關預置、配置中心都是必要手段;
而兩者的區別也是明顯的:
  1. 觸發原因不太一樣,服務熔斷一般是某個服務(下游服務)故障引起,而服務降級一般是從整體負荷考慮;
  2. 管理目標的層次不太一樣,熔斷其實是一個框架級的處理,每個微服務都需要(無層級之分),而降級一般需要對業務有層級之分(比如降級一般是從最外圍服務開始)
  3. 實現方式不太一樣

服務降級要考慮的問題:

 1.核心和非核心服務

2.是否支援降級,降級策略

3.業務放通的場景,策略

 

Hystrix,該庫旨在通過控制那些訪問遠端系統、服務和第三方庫的節點,從而對延遲和故障提供更強大的容錯能力。Hystrix具備擁有回退機制和斷路器功能的執行緒和訊號隔離,請求快取和請求打包(request collapsing,即自動批處理,譯者注),以及監控和配置等功能。

 

(7)資料庫分庫分表

資料庫的瓶頸

  • 單個庫資料量太大;考慮多個庫解決問題。
  • 單個數據庫伺服器壓力過大、讀寫瓶頸;考慮多個庫、讀寫分離解決問題。
  • 單個表資料量過大;考慮分表解決問題。

資料庫切庫與分庫

對資料庫的操作中讀多寫少,且讀操作佔用系統資源多,耗時長,適用多個分庫進行負載均衡。詳情檢視: 自定義註解完成資料庫切庫

切庫的基礎及實際應用中,隨著業務增加,併發增加,需做到讀寫分離;
自定義註解完成資料庫切庫-程式碼實現;另一種方式是在業務中直接定義兩個資料庫連結:主庫連線和從庫連線;更新資料時,讀取主庫連線,

支援多資料來源:指一個專案裡,同時可以訪問多個不同的資料庫。
原理:單個數據源在配置時會繫結一套mybatis配置,多個數據源時,不同的資料來源繫結不同的mybatis配置就可以了,簡單的思路就是讓不同的資料來源掃描不同的包,讓不同的包下的mapper對應連線不同的資料來源去處理邏輯。

資料庫分表

分表的型別

  1. 橫向(水平)分表(Horizontal Partitioning)
    這種形式分割槽是對錶的行進行分割,通過這樣的方式不同分組裡面的物理列分割的資料集得以組合,從而進行個體分割(單分割槽)或集體分割(1個或多個分割槽)。所有在表中定義的列在每個資料集中都能找到,所以表的特性依然得以保持。
  2. 縱向(垂直)分表(Vertical Partitioning)
    這種分割方式一般來說是通過對錶的垂直劃分來減少目標表的寬度,使某些特定的列被劃分到特定的分割槽,每個分割槽都包含了其中的列所對應的行。

    在資料庫供應商開始在他們的資料庫引擎中建立分割槽(主要是水平分割槽)時,DBA和建模者必須設計好表的物理分割槽結構,不要儲存冗餘的資料(不同表中同時都包含父表中的資料)或相互聯結成一個邏輯父物件(通常是檢視)。這種做法會使水平分割槽的大部分功能失效,有時候也會對垂直分割槽產生影響。

    分表的好處

  3. 效能的提升(Increased performance)- 在掃描操作中,如果MySQL的優化器知道哪個分割槽中才包含特定查詢中需要的資料,它就能直接去掃描那些分割槽的資料,而不用浪費很多時間掃描不需要的地方了。需要舉個例子?好啊,百萬行的表劃分為10個分割槽,每個分割槽就包含十萬行資料,那麼查詢分割槽需要的時間僅僅是全表掃描的十分之一了,很明顯的對比。同時對十萬行的表建立索引的速度也會比百萬行的快得多得多。如果你能把這些分割槽建立在不同的磁碟上,這時候的I/O讀寫速度就“不堪設想”;
  4. 對資料管理的簡化(Simplified data management)- 分割槽技術可以讓DBA對資料的管理能力提升。通過優良的分割槽,DBA可以簡化特定資料操作的執行方式。例如:DBA在對某些分割槽的內容進行刪除的同時能保證餘下的分割槽的資料完整性(這是跟對錶的資料刪除這種大動作做比較的)。

(8)高可用的一些手段

  1. 任務排程系統分散式:elastic-job元件 + zookeeper;
  2. 主備切換:Apache curator + zookeeper分散式鎖;
  3. 監控報警機制。詳情參看: https://www.imooc.com/article/20891 業務相關監控報警系統