1. 程式人生 > >四、服務消費(Ribbon)

四、服務消費(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());

    }

}

可以看到這裡,我們注入了LoadBalancerClientRestTemplate,並在/test介面中,先通過loadBalancerClientchoose函式來負載均衡的選出一個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

當然要將之前配置類的方式去掉。