javascript
Spring Clould负载均衡重要组件:Ribbon中重要类的用法
? ? Ribbon是Spring Cloud Netflix全家桶中負(fù)責(zé)負(fù)載均衡的組件,它是一組類庫的集合。通過Ribbon,程序員能在不涉及到具體實現(xiàn)細(xì)節(jié)的基礎(chǔ)上“透明”地用到負(fù)載均衡,而不必在項目里過多地編寫實現(xiàn)負(fù)載均衡的代碼。
? ? 比如,在某個包含Eureka和Ribbon的集群中,某個服務(wù)(可以理解成一個jar包)被部署在多臺服務(wù)器上,當(dāng)多個服務(wù)使用者同時調(diào)用該服務(wù)時,這些并發(fā)的請求能被用一種合理的策略轉(zhuǎn)發(fā)到各臺服務(wù)器上。
? ? 事實上,在使用Spring Cloud的其它各種組件時,我們都能看到Ribbon的痕跡,比如Eureka能和Ribbon整合,而在后文里將提到的提供網(wǎng)關(guān)功能Zuul組件在轉(zhuǎn)發(fā)請求時,也可以整合Ribbon從而達(dá)到負(fù)載均衡的效果。
? ? 從代碼層面來看,Ribbon有如下三個比較重要的接口。
? ? 第一,ILoadBalancer,這也叫負(fù)載均衡器,通過它,我們能在項目里根據(jù)特定的規(guī)則合理地轉(zhuǎn)發(fā)請求,常見的實現(xiàn)類有BaseLoadBalancer。
? ? 第二,IRule,這個接口有多個實現(xiàn)類,比如RandomRule和RoundRobinRule,這些實現(xiàn)類具體地定義了諸如“隨機(jī)“和”輪詢“等的負(fù)載均衡策略,我們還能重寫該接口里的方法來自定義負(fù)載均衡的策略。
在BaseLoadBalancer類里,我們能通過IRule的實現(xiàn)類設(shè)置負(fù)載均衡的策略,這樣該負(fù)載均衡器就能據(jù)此合理地轉(zhuǎn)發(fā)請求。
? ? 第三,IPing接口,通過該接口,我們能獲取到當(dāng)前哪些服務(wù)器是可用的,我們也能通過重寫該接口里的方法來自定義判斷服務(wù)器是否可用的規(guī)則。在BaseLoadBalancer類里,我們同樣能通過IPing的實現(xiàn)類設(shè)置判斷服務(wù)器是否可用的策略。? ??
1 ILoadBalancer:負(fù)載均衡器接口
? ? 在Ribbon里,我們還可以通過ILOadBalancer這個接口以基于特定的負(fù)載均衡策略來選擇服務(wù)器。
? ? 通過下面的ILoadBalancerDemo.java,我們來看下這個接口的基本用法。這個類是放在4.2部分創(chuàng)建的RabbionBasicDemo項目里,代碼如下。? ??
1 //省略必要的package和import代碼 2 public class ILoadBalancerDemo { 3 public static void main(String[] args){ 4 //創(chuàng)建ILoadBalancer的對象 5 ILoadBalancer loadBalancer = new BaseLoadBalancer(); 6 //定義一個服務(wù)器列表 7 List<Server> myServers = new ArrayList<Server>(); 8 //創(chuàng)建兩個Server對象 9 Server s1 = new Server("ekserver1",8080); 10 Server s2 = new Server("ekserver2",8080); 11 //兩個server對象放入List類型的myServers對象里 12 myServers.add(s1); 13 myServers.add(s2); 14 //把myServers放入負(fù)載均衡器 15 loadBalancer.addServers(myServers); 16 //在for循環(huán)里發(fā)起10次調(diào)用 17 for(int i=0;i<10;i++){ 18 //用基于默認(rèn)的負(fù)載均衡規(guī)則獲得Server類型的對象 19 Server s = loadBalancer.chooseServer("default"); 20 //輸出IP地址和端口號 21 System.out.println(s.getHost() + ":" + s.getPort()); 22 } 23 } 24 }? ? ?在第5行里,我們創(chuàng)建了BaseLoadBalancer類型的loadBalancer對象,而BaseLoadBalancer是負(fù)載均衡器ILoadBalancer接口的實現(xiàn)類。
? ? 在第6到第13行里,我們創(chuàng)建了兩個Server類型的對象,并把它們放入了myServers里,在第15行里,我們把List類型的myServers對象放入了負(fù)載均衡器里。
? ? 在第17到22行的for循環(huán)里,我們通過負(fù)載均衡器模擬了10次選擇服務(wù)器的動作,具體而言,是在第19行里,通過loadBalancer的chooseServer方法以默認(rèn)的負(fù)載均衡規(guī)則選擇服務(wù)器,在第21行里,我們是用“打印”這個動作來模擬實際的“使用Server對象處理請求”的動作。
? ? 上述代碼的運(yùn)行結(jié)果如下所示,其中我們能看到,loadBalancer這個負(fù)載均衡器把10次請求均攤到了2臺服務(wù)器上,從中確實能看到 “負(fù)載均衡”的效果。
? ? 第二,IRule,這個接口有多個實現(xiàn)類,比如RandomRule和RoundRobinRule,這些實現(xiàn)類具體地定義了諸如“隨機(jī)“和”輪詢“等的負(fù)載均衡策略,我們還能重寫該接口里的方法來自定義負(fù)載均衡的策略。
? ? 在BaseLoadBalancer類里,我們能通過IRule的實現(xiàn)類設(shè)置負(fù)載均衡的策略,這樣該負(fù)載均衡器就能據(jù)此合理地轉(zhuǎn)發(fā)請求。
? ? 第三,IPing接口,通過該接口,我們能獲取到當(dāng)前哪些服務(wù)器是可用的,我們也能通過重寫該接口里的方法來自定義判斷服務(wù)器是否可用的規(guī)則。在BaseLoadBalancer類里,我們同樣能通過IPing的實現(xiàn)類設(shè)置判斷服務(wù)器是否可用的策略。??
1 ekserver2:8080 2 ekserver1:8080 3 ekserver2:8080 4 ekserver1:8080 5 ekserver2:8080 6 ekserver1:8080 7 ekserver2:8080 8 ekserver1:8080 9 ekserver2:8080 10 ekserver1:8080? ??
2 IRule:定義負(fù)載均衡規(guī)則的接口
? ? 在Ribbon里,我們可以通過定義IRule接口的實現(xiàn)類來給負(fù)載均衡器設(shè)置相應(yīng)的規(guī)則。在下表里,我們能看到IRule接口的一些常用的實現(xiàn)類。
| 實現(xiàn)類的名字 | 負(fù)載均衡的規(guī)則 |
| RandomRule | 采用隨機(jī)選擇的策略 |
| RoundRobinRule | 采用輪詢策略 |
| RetryRule | 采用該策略時,會包含重試動作 |
| AvailabilityFilterRule | 會過濾些多次連接失敗和請求并發(fā)數(shù)過高的服務(wù)器 |
| WeightedResponseTimeRule | 根據(jù)平均響應(yīng)時間為每個服務(wù)器設(shè)置一個權(quán)重,根據(jù)該權(quán)重值優(yōu)先選擇平均響應(yīng)時間較小的服務(wù)器 |
| ZoneAvoidanceRule | 優(yōu)先把請求分配到和該請求具有相同區(qū)域(Zone)的服務(wù)器上 |
? ? 在下面的IRuleDemo.java的程序里,我們來看下IRule的基本用法。
? ?
1 //省略必要的package和import代碼 2 public class IRuleDemo { 3 public static void main(String[] args){ 4 //請注意這是用到的是BaseLoadBalancer,而不是ILoadBalancer接口 5 BaseLoadBalancer loadBalancer = new BaseLoadBalancer(); 6 //聲明基于輪詢的負(fù)載均衡策略 7 IRule rule = new RoundRobinRule(); 8 //在負(fù)載均衡器里設(shè)置策略 9 loadBalancer.setRule(rule); 10 //如下定義3個Server,并把它們放入List類型的集合中 11 List<Server> myServers = new ArrayList<Server>(); 12 Server s1 = new Server("ekserver1",8080); 13 Server s2 = new Server("ekserver2",8080); 14 Server s3 = new Server("ekserver3",8080); 15 myServers.add(s1); 16 myServers.add(s2); 17 myServers.add(s3); 18 //在負(fù)載均衡器里設(shè)置服務(wù)器的List 19 loadBalancer.addServers(myServers); 20 //輸出負(fù)載均衡的結(jié)果 21 for(int i=0;i<10;i++){ 22 Server s = loadBalancer.chooseServer(null); 23 System.out.println(s.getHost() + ":" + s.getPort()); 24 } 25 } 26 }? ??這段代碼和上文里的ILoadBalancerDemo.java很相似,但有如下的差別點。
? ? 1 在第5行里,我們是通過BaseLoadBalancer這個類而不是接口來定義負(fù)載均衡器,原因是該類包含setRule方法。
? ? 2 在第7行定義了一個基于輪詢規(guī)則的rule對象,并在第9行里把它設(shè)置進(jìn)負(fù)載均衡器。
? ? 3 在第19行里,我們是把包含3個Server的List對象放入負(fù)載均衡器,而不是之前的兩個。由于這里存粹是為了演示效果,所以我們就放入一個根本不存在的“ekserver3”服務(wù)器。
? ? 運(yùn)行該程序后,我們可以看到有10次輸出,而且確實是按“輪詢”的規(guī)則有順序地輸出3個服務(wù)器的名字。如果我們把第7行的代碼改成如下,那么就會看到 “隨機(jī)”地輸出服務(wù)器名。
??? IRule rule = new RandomRule();
? ??
3 ?IPing:判斷服務(wù)器是否可用的接口
? ? 在項目里,我們一般會讓ILoadBalancer接口自動地判斷服務(wù)器是否可用(這些業(yè)務(wù)都封裝在Ribbon的底層代碼里),此外,我們還可以用Ribbon組件里的IPing接口來實現(xiàn)這個功能。
? ? 在下面的IRuleDemo.java代碼里,我們將演示IPing接口的一般用法。? ??
1 //省略必要的package和import代碼 2 class MyPing implements IPing { 3 public boolean isAlive(Server server) { 4 //如果服務(wù)器名是ekserver2,則返回false 5 if (server.getHost().equals("ekserver2")) { 6 return false; 7 } 8 return true; 9 } 10 }? ??第2行定義的MyPing類實現(xiàn)了IPing接口,并在第3行重寫了其中的isAlive方法。
? ? 在這個方法里,我們根據(jù)服務(wù)器名來判斷,具體而言,如果名字是ekserver2,則返回false,表示該服務(wù)器不可用,否則返回true,表示當(dāng)前服務(wù)器可用。?? ??
11 public class IRuleDemo { 12 public static void main(String[] args) { 13 BaseLoadBalancer loadBalancer = new BaseLoadBalancer(); 14 //定義IPing類型的myPing對象 15 IPing myPing = new MyPing(); 16 //在負(fù)載均衡器里使用myPing對象 17 loadBalancer.setPing(myPing); 18 //同樣是創(chuàng)建三個Server對象并放入負(fù)載均衡器 19 List<Server> myServers = new ArrayList<Server>(); 20 Server s1 = new Server("ekserver1", 8080); 21 Server s2 = new Server("ekserver2", 8080); 22 Server s3 = new Server("ekserver3", 8080); 23 myServers.add(s1); 24 myServers.add(s2); 25 myServers.add(s3); 26 loadBalancer.addServers(myServers); 27 //通過for循環(huán)多次請求服務(wù)器 28 for (int i = 0; i < 10; i++) { 29 Server s = loadBalancer.chooseServer(null); 30 System.out.println(s.getHost() + ":" + s.getPort()); 31 } 32 } 33 }? ??在第12行的main函數(shù)里,我們在第15行創(chuàng)建了IPing類型的myPing對象,并在第17行把這個對象放入了負(fù)載均衡器。通過第18到第26行的代碼,我們創(chuàng)建了三個服務(wù)器,并把它們也放入負(fù)載均衡器。
? ? 在第28行的for循環(huán)里,我們依然是請求并輸出服務(wù)器名。由于這里的負(fù)載均衡器loadBalancer中包含了一個IPing類型的對象,所以在根據(jù)策略得到服務(wù)器后,會根據(jù)myPing里的isActive方法來判斷該服務(wù)器是否可用。
? ? 由于在這個方法里,我們定義了ekServer2這臺服務(wù)器不可用,所以負(fù)載均衡器loadBalancer對象始終不會把請求發(fā)送到該服務(wù)器上,也就是說,在輸出結(jié)果中,我們不會看到“ekserver2:8080”的輸出。
? ? 從中我們能看到IPing接口的一般用法,我們可以通過重寫其中的isAlive方法來定義“判斷服務(wù)器是否可用“的邏輯,在實際項目里,判斷的依據(jù)無非是”服務(wù)器響應(yīng)是否時間過長“或”發(fā)往該服務(wù)器的請求數(shù)是否過多“,而這些判斷方法都封裝在IRule接口以及它的實現(xiàn)類里,所以在一般的場景中我們用到IPing接口。
4 ?預(yù)告&版權(quán)申明
? ? ?在本周的后面時間里,我將繼續(xù)給出用Eureka+Ribbon高可用負(fù)載均衡架構(gòu)的搭建方法。
? ? ?本文內(nèi)容摘自本人寫的專業(yè)書籍,轉(zhuǎn)載時請同時引入該版權(quán)申明,請勿用于商業(yè)用途。
轉(zhuǎn)載于:https://www.cnblogs.com/JavaArchitect/p/8648420.html
總結(jié)
以上是生活随笔為你收集整理的Spring Clould负载均衡重要组件:Ribbon中重要类的用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 方法中的this参数
- 下一篇: SpringCloud基本模块分配搭建以