Hystrix針對不可用服務的保護機制以及引入緩存 經過案例瞭解Hystrix的各類基本使用方式

   以前我寫過一篇博文,經過案例瞭解Hystrix的各類基本使用方式,在這篇文章裏,咱們是經過Hystrix調用正常工做的服務,也就是說,Hytrix的保護機制並無起做用,這裏咱們將在HystrixProtectDemo.java裏演示調用不可用的服務時,hystrix啓動保護機制的流程。這個類是基於NormalHystrixDemo.java改寫的,只是在其中增長了getFallback方法,代碼以下。     html

1	//省略必要的package和import代碼
2	public class HystrixProtectDemo extends HystrixCommand<String> {
3		RestClient client = null;
4		HttpRequest request = null;
5	    //構造函數很類似
6		public HystrixDemoProtectDemo() {
7		super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
8		}
9	   //initRestClient方法沒變
10		private void initRestClient(){
11	        //和NormalHystrixDemo.java同樣,具體請參考代碼
12		}
13		//run方法也沒變
14		protected String run() {
15			//和NormalHystrixDemo.java同樣,具體請參考代碼
16		}
17	    //此次多個了getFallback方法,一旦出錯,會調用其中的代碼
18		protected String getFallback() {
19			//省略跳轉到錯誤提示頁面的動做
20			return "Call Unavailable Service.";
21		}
22		//main函數
23		public static void main(String[] args) {
24			HystrixDemoProtectDemo normalDemo = new HystrixDemoProtectDemo();
25			normalDemo.initRestClient();
26			try {
27				Thread.sleep(1000);
28			} catch (InterruptedException e) {
29				e.printStackTrace();
30			}           
31			String result = normalDemo.execute();
32			System.out.println("Call available function, result is:" + result);
33		}
34	}

    這個類裏的構造函數和NormalHystrixDemo.java很類似,而initRestClient和run方法根本沒變,因此就再也不詳細給出了。前端

    在第18行裏,咱們重寫了HystrixCommand類的getFallback方法,在其中定義了一旦訪問出錯的動做,這裏僅僅是輸出一段話,在實際的項目裏,能夠跳轉到相應的錯誤提示頁面。java

    而main函數裏的代碼和NormalHystrixDemo.java裏的徹底同樣,只是,在運行這段代碼前無需運行HystrixServerDemo項目的啓動類,這樣服務必定是調用不到的。運行本段代碼後,咱們能看到以下的結果。  數據庫

             In run瀏覽器

             Call available function, result is:Call Unavailable Service.緩存

    從第2行的輸出上,咱們能確認,一旦調用服務出錯,Hystrix處理類能自動地調用getFallback方法。服務器

    若是這裏沒有定義getFallback方法,那麼一旦服務不可用,那麼用戶可能在鏈接超時以後,在瀏覽器裏看到一串毫無心義的內容,這樣用戶體驗就不好,若是整個系統的其它容錯措施也沒到位,甚至就有可能致使當前和下游模塊癱瘓。併發

    相反,在這裏因爲咱們在hystirx提供的getFallback方法裏作了充分的準備,那麼一旦出現錯誤,這段錯誤處理的代碼能被當即觸發,其效果就至關於熔斷後繼的處理流程。函數

    由getFallback出面,友好地告知用戶出問題了,以及後繼該如何處理,這樣一方面能及時熔斷請求從而保護整個系統,另外一方面不會形成因體驗過差而用戶大規模流失的狀況。post

    若是每次請求都要走後臺應用程序乃至再到數據庫檢索一下數據,這對服務器的壓力太大,有時候這一因素甚至會成爲影響網站服務性能的瓶頸。因此,大多數網站會把一些無需實時更新的數據放入緩存,前端請求是到緩存裏拿數據。    

    Hystrix在提供保護性便利的同時,也能支持緩存的功能,在下面的HystrixCacheDemo.java裏,咱們將演示Hystrix從緩存中讀取數據的步驟,代碼以下。     

1    //省略必要的package和import代碼
2    public class HystrixCacheDemo extends HystrixCommand<String> {
3        //用戶id
4        Integer id;
5         //用一個HashMap來模擬數據庫裏的數據
6        private HashMap<Integer,String> userList = new HashMap<Integer,String>();
7        //構造函數
8        public HystrixCacheDemo(Integer id) {
9        super(HystrixCommandGroupKey.Factory.asKey("RequestCacheCommand"));        
10            this.id = id;
11            userList.put(1, "Tom");
12        }

    在第3行裏,咱們定義了一個用戶id,並在第6行定義了一個存放用戶信息的HashMap。

    在第8行的構造函數裏,咱們在第10行裏用參數id來初始化了本對象的id屬性,並在第11行裏,經過put方法模擬地構建了一個用戶,在項目裏,用戶的信息實際上是存在數據庫裏的。    

13        protected String run() {
14            System.out.println("In run");
15            return userList.get(id);
16        }

    若是不走緩存的話,第13行定義run函數將會被execute方法觸發,在其中的第15行裏,咱們經過get方法從userList這個HashMap裏得到一條用戶數據,這裏咱們用get方法來模擬根據id從數據庫裏獲取數據的諸多動做。    

17		protected String getCacheKey() {
18			return String.valueOf(id);
19		}

  第17行定義的getCacheKey方法是Hystrix實現緩存的關鍵,在其中咱們能夠定義「緩存對象的標準」,具體而言,咱們在這裏是返回String.valueOf(id),也就是說,若是第二個HystrixCacheDemo對象和第一個對象具備相同的String.valueOf(id)的值,那麼第二個對象在調用execute方法時,就能夠走緩存。

    

public static void main(String[] args) {        
21         //初始化上下文,不然沒法用緩存機制
22            HystrixRequestContext context = HystrixRequestContext.initializeContext();
23            //定義兩個具備相同id的對象
24            HystrixCacheDemo cacheDemo1 = new HystrixCacheDemo(1);
25            HystrixCacheDemo cacheDemo2 = new HystrixCacheDemo(1);
26            //第一個對象調用的是run方法,沒有走緩存    
27            System.out.println("the result for cacheDemo1 is:" + cacheDemo1.execute());
28            System.out.println("whether get from cache:" + cacheDemo1.isResponseFromCache);
29            //第二個對象,因爲和第一個對象具備相同的id,因此走緩存    
30            System.out.println("the result for cacheDemo2 is:" + cacheDemo2.execute());
31            System.out.println("whether get from cache:" + cacheDemo2.isResponseFromCache);
32            //銷魂上下文,以清空緩存
33            context.shutdown();
34            //再次初始化上下文,但因爲緩存已清,因此cacheDemo3沒走緩存
35            context = HystrixRequestContext.initializeContext();
36            HystrixCacheDemo cacheDemo3 = new HystrixCacheDemo(1);
37            System.out.println("the result for 3 is:" + cacheDemo3.execute());
38            System.out.println("whether get from cache:" + cacheDemo3.isResponseFromCache);
39            context.shutdown();

    在第20行的main方法裏,咱們定義了以下的主要邏輯。

    第一,在第22行,經過initializeContext方法,初始化了上下文,這樣才能啓動緩存機制。,在第24和25行裏,咱們建立了兩個不一樣名的,但相同id的HystrixCacheDemo對象。

    第二,在第27行裏,咱們經過cacheDemo1對象的execute方法,根據id查找用戶,雖然咱們在這裏是經過run方法裏第15行的get方法從HashMap裏取數據,但你們能夠把這想象成從數據表裏取數據。

    第三,在第30行裏,咱們調用了cacheDemo2對象的execute方法,因爲它和cacheDemo1對象具備相同的id,因此這裏並無走execute方法,而是直接從保存cacheDemo1.execute的緩存裏拿數據,這就能夠避免因屢次訪問數據庫而形成了系統損耗。

    第四,咱們在第33行銷燬了上下文,並在第35行裏從新初始化了上下文,以後,雖然在第36行定義的cacheDemo3對象的id依然是1,但因爲上下文對象被重置過,其中的緩存也被清空,因此在第37裏執行的execute方法並無走緩存。

    運行上述代碼,咱們能看到以下的輸出,這些打印結果能很好地驗證上述對主要流程的說明。    

1    In run
2    the result for cacheDemo1 is:Tom
3    whether get from cache:false
4    the result for cacheDemo2 is:Tom
5    whether get from cache:true
6    In run
7    the result for 3 is:Tom

    這裏請你們注意,在緩存相關的getCacheKey方法裏,咱們不是定義「保存緩存值」的邏輯,而是定義「緩存對象的標準」,初學者常常會混淆這點。具體而言,在這裏的getCacheKey方法裏,咱們並無保存id是1的User對象的值(這裏是Tom),而是定義了以下的標準:只要兩個(或多個)HystrixCacheDemo對象具備相同的String.valueOf(id)的值,並且緩存中也已經存有id的1的結果值,那麼後繼對象則能夠直接從緩存裏讀數據。

    

    在上文裏,咱們演示了經過Hystrix調用可用以及不可用服務的運行結果,並在調用過程當中引入了緩存機制,這裏,咱們將在上述案例的基礎上概括Hystrix的通常工做流程。

    第一,咱們能夠經過extends HystrixCommand<T>的方式,讓一個類具有Hystrix保護機制的特性,其中T是泛型,在上述案例中咱們用到的是String。

    第二,一旦繼承了HystrixCommand以後,咱們就能夠經過重寫run方法和getFallback方法來定義調用「可用」和「不可用」服務的業務功能代碼,其中,這兩個方法的返回值須要和第一步裏定義的泛型T一致。而在項目裏,咱們通常在getFallback方法裏,定義「服務不可用」時的保護措施(也就是後文裏將要提到的降級措施)。

    第三,咱們還能夠經過緩存機制來下降併發狀況下對服務器的壓力,在Hystrix裏,咱們能夠在getCacheKey裏定義「判斷能夠走緩存對象的標準」。

    在使用緩存是,請注意兩點,第一須要開啓上下文,第二,Hystrix會根據定義在類裏的屬性判斷屢次調用的對象是不是同一個,若是是,並且以前被調用過,則能夠走緩存。

    本文謝絕轉載。

相關文章
相關標籤/搜索