分佈式項目中,爲了避免某個服務的集中負載過高導致服務性能的下降或者甚至服務掛掉,需要有一套機制將客戶端的請求相對均勻的分發給各個服務,這個機制就可以稱之爲負載均衡。
負載均衡可以在服務端實現,也可以在客戶端實現,在Springcloud中,Ribbon就是作爲客戶端的負載均衡器來實現負載均衡的, 可以和Eureka服務註冊中心一起配合使用,並且在Springcloud中用戶可以很方便的自定義負載均衡的算法。
Ribbon實現負載均衡原理
上圖可以描述爲:
Eureka Server中註冊了各個微服務的實例,Ribbon負載均衡器也註冊進Eureka Server中。在接收到客戶端的請求時,先通過Eureka Server查找可用的服務列表,將查找到的可用服務發送給Ribbon客戶端,Ribbon客戶端通過負載均衡算法選擇其中的一個服務進行遠程調用微服務,將結果返回。
構建Springcloud Ribbon項目
再一次強調,Ribbon是在客戶端實現的負載均衡組件,所以構建項目也是在服務消費者的項目中進行。
- pom.xml
在springcloud中,Ribbon通常和Eureka一起使用,需要使用的maven依賴如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
- application.yml
eureka:
client:
register-with-eureka: false # 自己不作爲Eureka的註冊中心
service-url:
# 指定了Eureka集羣的地址
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002
- 主啓動類添加相應的註解, 因爲Ribbon是註冊在Eureka Server中的,所以這裏添加@EnableRurekaClient註解即可。
@SpringBootApplication
@EnableEurekaClient
public class App_consumer_dept_80 {
public static void main(String[] args) {
SpringApplication.run(App_consumer_dept_80.class, args);
}
}
- 項目中使用RestTemplate來進行微服務的遠程調用,需要在RestTemplate的配置類中啓用負載均衡機制。
@Configuration
public class BeanConfig {
@Bean
@LoadBalanced // 啓用負載均衡
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
- Ribbon是一個負載均衡組件,它和Eureka組合使用時,可以基於微服務的服務名來進行負載均衡調用。通過RestTemplate進行調用時,原本需要寫上微服務的訪問url, 在使用Ribbon後,可以直接寫服務的名字。
@RestController
public class DeptController {
// 使用RestTemplate進行調用時需要指定服務的url
// private static final String URL_PREFIX = "http://localhost:8001";
// 使用Ribbon + Eureka 之後,可以直接通過服務名來進行服務的調用
private static final String URL_PREFIX = "http://provider-dept";
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/dept/{id}")
public Dept get(@PathVariable("id") Long id) {
// 通過RestTemplate進行服務調用
return restTemplate.getForObject(URL_PREFIX + "/api/dept/" + id, Dept.class);
}
...
}