前面咱們已經完成了註冊中心和服務提供者兩個基礎組件。接着介紹使用Spring Cloud Ribbon在客戶端負載均衡的調用服務。html
ribbon 是一個客戶端負載均衡器,能夠簡單的理解成相似於 nginx的負載均衡模塊的功能。nginx
主流的LB方案可分紅兩類:web
一種是集中式LB, 即在服務的消費方和提供方之間使用獨立的LB設施(能夠是硬件,如F5, 也能夠是軟件,如nginx), 由該設施負責把訪問請求經過某種策略轉發至服務的提供方;算法
另外一種是進程內LB,將LB邏輯集成到消費方,消費方從服務註冊中心獲知有哪些地址可用,而後本身再從這些地址中選擇出一個合適的服務器。Ribbon就屬於後者,它只是一個類庫,集成於消費方進程,消費方經過它來獲取到服務提供方的地址。spring
Ribbon的架構圖:以下:瀏覽器
1.首先咱們先在原來的基礎上新建一個Ribbon模塊,以下圖:服務器
如今咱們單獨使用ribbon,在Ribbon模塊下添加依賴,以下圖所示:架構
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.0.RELEASE</version> </dependency>
修改application.yml文件,以下所示:app
server: port: 8082 spring: application: name: Ribbon-Consumer #providers這個是本身命名的,ribbon,listOfServer這兩個是規定的 providers: ribbon: listOfServers: localhost:8080,localhost:8081
在Ribbon模塊下新建一個測試類以下代碼 * Created by cong on 2018/5/8. */負載均衡
@RestController public class ConsumerController {
//注入負載均衡客戶端 @Autowired
private LoadBalancerClient loadBalancerClient; @RequestMapping("/consumer") public String helloConsumer() throws ExecutionException, InterruptedException {
//這裏是根據配置文件的那個providers屬性取的 ServiceInstance serviceInstance = loadBalancerClient.choose("providers");
//負載均衡算法默認是輪詢,輪詢取得服務 URI uri = URI.create(String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort())); return uri.toString();
}
運行結果以下:
會輪詢的獲取到兩個服務的URL 訪問第一次,瀏覽器出現http://localhost:8080 訪問第二次就會出現http://localhost:8081
在這裏給普及一下有哪些負載均衡算法:
1:簡單輪詢負載均衡(RoundRobin)
以輪詢的方式依次將請求調度不一樣的服務器,即每次調度執行i = (i + 1) mod n,並選出第i臺服務器。
2:隨機負載均衡 (Random)
隨機選擇狀態爲UP的Server
3:加權響應時間負載均衡 (WeightedResponseTime)
根據相應時間分配一個weight,相應時間越長,weight越小,被選中的可能性越低。
4:區域感知輪詢負載均衡(ZoneAvoidanceRule)
複合判斷server所在區域的性能和server的可用性選擇server
有興趣的還能夠看一下我在Ngnix的隨筆文章中列出的負載均衡算法實現:http://www.cnblogs.com/huangjuncong/p/8319182.html
若是想配置其餘輪詢算法在yml配置文件中配置,以下配置一個隨機算法所示:
server: port: 8082 spring: application: name: Ribbon-Consumer #providers這個是本身命名的,ribbon,listOfServer這兩個是規定的 providers: ribbon: listOfServers: localhost:8080,localhost:8081 ##若是不想選用默認的輪詢的負載均衡算法,在這裏作以下配置 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
接着在啓動類動一下手腳讓咱們配置的隨機算法的負載均衡生效,只須要實現一個實現了IRule接口的Bean便可,以下:
package hjc; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class RibbonApplication { public static void main(String[] args) { SpringApplication.run(RibbonApplication.class, args); } @Bean public IRule ribbonRule(){ return new RandomRule(); } }
所以從新啓動Ribbon啓動類,獲得的結果是隨機的,以下所示:
瀏覽器隨機出現http://localhost:8080 或者http://localhost:8081
那麼問題來了,服務的地址是寫死在配置文件中,若是某個服務掛了,那麼還會把請求轉發到掛掉的服務中,所以,解決的辦法是,跟Eureka對接,結合一塊兒用。就能夠依靠Eureka動態的獲取一個可用的服務列表,隔一段時間我就更新一次,
或者Eureka設置一個監聽端口,某一個服務掛了,Eureka通知我,我會知道,變動服務列表,這樣不久造成一個閉環了嗎?這樣就不存在高可用性問題了。跟Eureka配合一塊兒用同時解決了的Ribbon的單點故障問題。
第一步,毫無疑問就是修改Ribbon模塊的pom.xml文件,加入以下依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.3.5.RELEASE</version> </dependency>
第二步,修改yml配置文件以下:
server: port: 8082 spring: application: name: Ribbon-Consumer eureka: #客戶端 client: #註冊中心地址 service-url: defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
這樣就能夠跟Eureka結合,這樣Ribbon就能夠經過Eureka動態的獲取服務列表
接着在啓動類加上服務發現註解,以下:
@EnableDiscoveryClient
啓動類接着聲明一個負載均衡的請求器@LoadBalanced,還有請求發起的工具RestTemplate
以下代碼:
@SpringBootApplication @EnableDiscoveryClient public class RibbonApplication { public static void main(String[] args) { SpringApplication.run(RibbonApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
接着咱們在上一節文章中的兩個provider1,provider2模塊添加一下測試代碼:以下:
provider1:
package hjc.hello; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created by cong on 2018/5/8. */ @RestController public class HelloController { @RequestMapping("/hello") public String hello(){ return "hello1"; } }
provider2代碼以下:
package hjc.hello; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created by cong on 2018/5/8. */ @RestController public class HelloController { @RequestMapping("/hello") public String hello(){ return "hello2"; } }
接着咱們用RestTemplate進行面向服務調用,再也不面向IP調用。
以下代碼:
/** * Created by cong on 2018/5/8. */ @RestController public class ConsumerController { @Autowired private RestTemplate restTemplate; @RequestMapping("/consumer") public String helloConsumer() throws ExecutionException, InterruptedException { return restTemplate.getForEntity("http://HELLO-SERVICE/hello",String.class).getBody();
}
接着啓動Ribbon模塊,咱們看一下Eureka儀表盤,以下:
能夠看到多了RIBBON-CONSUMER服務
接着咱們繼續在已經運行的Ribbon模塊上,在瀏覽器輸入localhost:8082,運行結果以下:
hello1或者hello2,
能夠看到hello1 ,hello2輪詢方式出現,由於默認就是輪詢方式
到這裏咱們還發現Ribbon仍是單點故障的,這裏我來解釋一下:
由於這裏我是單獨創建一個SpringBoot的Ribbon模塊,實際使用並非這樣用的,Ribbon是客戶端的負載均衡,是跟客戶端綁定在一塊兒的,咱們實際運用的時候每每會在服務裏面引入一個客戶端負載均衡去鏈接到Eureka客戶中心,
這樣咱們還存在Ribbon單點故障嗎?不存在了,由於咱們服務提供者就是高可用的,這樣仍是個單點嗎?這裏讀者的思考必須轉過彎來,這一篇隨筆我只是爲了演示Ribbon,實際使用並非這樣用的。