四、服務消費(Ribbon)
1、Spring Cloud Ribbon
Spring Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端負載均衡的工具。它是一個基於HTTP和TCP的客戶端負載均衡器。它可以通過在客戶端中配置ribbonServerList來設定服務端列表去輪詢訪問以達到均衡負載的作用。
當Ribbon與Eureka聯合使用時,ribbonServerList會被DiscoveryEnabledNIWSServerList重寫,擴充套件成從Eureka註冊中心中獲取服務例項列表。同時它也會用NIWSDiscoveryPing來取代IPing,它將職責委託給Eureka來確定服務端是否已經啟動。
2、程式碼演示
建立子模組,命名為microservice-consumer-movie-ribbon,並且在pom.xml檔案中新增相關依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
在eureka的座標中,已經包含了ribbon的座標。
application.yml
spring:
application:
name: microservice-consumer-movie
server:
port: 3001
eureka:
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://admin:[email protected]:1001/eureka
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
應用主類
@SpringBootApplication @EnableEurekaClient public class MainAppConsumer { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(MainAppConsumer.class, args); } }
可以看到,我們在RestTemplate上面添加了一個註解@LoadBalanced,它可以讓這個RestTemplate在請求的時候擁有負載均衡的能力。
User實體類
public class User implements Serializable { private Long id; private String username; private String name; private short age; private BigDecimal balance; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getName() { return name; } public void setName(String name) { this.name = name; } public short getAge() { return age; } public void setAge(short age) { this.age = age; } public BigDecimal getBalance() { return balance; } public void setBalance(BigDecimal balance) { this.balance = balance; } }
建立介面
@RestController public class MovieController { @Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; @GetMapping("/movie/{id}") public User getById(@PathVariable("id") Long id){ return this.restTemplate.getForObject("http://microservice-provider-user/getUser/"+id,User.class); } @GetMapping("/test") public void test(){ ServiceInstance instance = loadBalancerClient.choose("microservice-provider-user"); System.out.println(instance.getServiceId() + "===" + instance.getHost() + "===" + instance.getPort()); } }
可以看到這裡,我們注入了LoadBalancerClient
和RestTemplate
,並在/test介面中,先通過loadBalancerClient
的choose
函式來負載均衡的選出一個microservice-provider-user的服務例項,這個服務例項的基本資訊儲存在ServiceInstance
中,我們列印其中的Host和Port,最後再利用RestTemplate
物件實現對服務提供者介面的呼叫。
我們啟動microservice-discovery-eureka,然後再分別用2001,2002這兩個埠啟動microservice-provider-user,最後啟動microservice-consumer-movie-ribbon這個模組,訪問http://localhost:3001/movie/1介面進行測試,頁面響應:
{"id":1,"username":"user1","name":"張三","age":18,"balance":100.00}
多次訪問http://localhost:3001/test,控制檯列印
microservice-provider-user===192.168.1.7===2001 microservice-provider-user===192.168.1.7===2002 microservice-provider-user===192.168.1.7===2001 microservice-provider-user===192.168.1.7===2002 microservice-provider-user===192.168.1.7===2001 microservice-provider-user===192.168.1.7===2002
因為我們的服務提供者通過兩個埠,啟動了兩次,所以,當我們多次訪問/test介面的時候,ribbon會基於輪詢的負載均衡演算法,依次呼叫這兩個服務,所以看到2001呼叫一次之後,接著會呼叫2002埠。
ribbon中除了輪詢的負載均衡演算法,還存在隨機負載均衡(Random),加權響應時間負載均衡(WeightedResponseTime)等,可以參考https://yq.aliyun.com/articles/61823
我們通過自定義配置,來修改ribbon預設的輪詢負載均衡。
在src目錄下建立一個包,命名為config(避免與應用主類同包或在其子包下面),然後建立一個類,命名為TestConfiguration,程式碼如下所示:
@Configuration public class TestConfiguration { @Bean public IRule ribbonRule() { return new RandomRule(); } }
@Configuration是spring中的一個註解,用於定義配置類,可以替換掉xml檔案。@Bean註解定義在方法上,可以將方法的返回值作為一個物件注入IOC容器中,以供使用。
之後,修改應用啟動主類,在類上新增:
@RibbonClient(name = "microservice-provider-user", configuration = TestConfiguration.class)
來引入我們建立的這個配合類。
上述完成後,我們還是按照之前的啟動順序,依次啟動eureka,user提供者(2001,2002),movie消費者,然後訪問消費者中的兩個介面進行測試。
訪問/movie/1介面,頁面響應
{"id":1,"username":"user1","name":"張三","age":18,"balance":100.00}
多次訪問/test介面,控制檯列印
microservice-provider-user===192.168.1.7===2002 microservice-provider-user===192.168.1.7===2001 microservice-provider-user===192.168.1.7===2002 microservice-provider-user===192.168.1.7===2001 microservice-provider-user===192.168.1.7===2001 microservice-provider-user===192.168.1.7===2001 microservice-provider-user===192.168.1.7===2002 microservice-provider-user===192.168.1.7===2002
可以看到它們使用哪個埠進行響應是隨機的,這就是ribbon中的隨機負載均衡。
我們還可以使用配置檔案進行配置ribbon的負載均衡演算法。
只需要在application.yml中新增如下內容:
microservice-provider-user:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
當然要將之前配置類的方式去掉。