1. 程式人生 > >Spring Cloud(四)RestTemplate服務呼叫與Ribbon負載均衡

Spring Cloud(四)RestTemplate服務呼叫與Ribbon負載均衡

Spring Cloud(四)RestTemplate服務呼叫與Ribbon負載均衡

上面已經把產品和使用者兩個微服務註冊到服務治理中心了。對於業務,則往往需要各個微服務之間相互地協助才能完成。例如,可能把產品交易資訊放到產品服務中,而在交易時,有時需要根據使用者的等級來決定默寫商品的折扣,如白銀會員9折,黃金會員8折等等。也就是說分散式系統在執行交易邏輯時,還需要使得產品微服務得到使用者資訊才可以決定產品的折扣,而使用者的資訊則是放置在使用者微服務中的。為了方便使用者微服務中獲取使用者資訊,使用者微服務會以REST風格提供一個請求URL。這樣對於產品微服務就可以通過REST請求獲取使用者服務。

除了處理獲取其他服務的資料外,這裡還需要注意服務節點之間的負載均衡,畢竟一個微服務可以由多個節點提供服務。不過這些都不困難,因為Spring Cloud提供了RibbonFeign元件來幫助我們來完成這些任務。通過它們,各個微服務之間就能夠相互呼叫,並且它會預設實現了負載均衡。

Ribbon客戶端負載均衡

對於Ribbon,其實並沒有什麼神祕的,它實際就是一個RestTemplate物件。只是上面還討論了多個節點的問題,例如排程使用者微服務時,因為使用者微服務存在多個節點,具體會使用哪個節點提供服務呢?關於這點Spring Cloud已經遮蔽了一些底層的細節,它只需要一個簡單的@LoadBalance

註解就看可以提供負載均衡的演算法。這十分符合spring boot的原則,提供預設的實現方式,減少開發者的工作量。在預設情況下,它會提供輪詢的負載均衡演算法。其他的負載均衡演算法比較複雜,這裡不講(我也不會。。。)

下面用例項來說明Ribbon的使用。現在使用者微服務上寫一個Pojo

User

package com.lay.user.pojo;

import java.io.Serializable;

/**
 * @Description:
 * @Author: lay
 * @Date: Created in 16:31 2018/11/26
 * @Modified By:IntelliJ IDEA
 */
public class UserPo implements Serializable { private static final long serialVersionUID = 6984412951642658165L; private Long id; private String userName; //1-白銀會員,2-黃金會員,3-鑽石會員 private int level; private String note; public static long getSerialVersionUID() { return serialVersionUID; } 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 int getLevel() { return level; } public void setLevel(int level) { this.level = level; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } }

然後我們可以給出基於REST風格的實現使用者返回的程式碼

@RestController
public class UserController {
    //日誌
    private static final Logger log= LoggerFactory.getLogger(UserController.class);

    //服務發現客戶端
    @Autowired
    private DiscoveryClient discoveryClient;

    //獲取使用者資訊
    @GetMapping("/user/{id}")
    public UserPo getUserPo(@PathVariable("id") Long id){
        ServiceInstance service = discoveryClient.getInstances("USER").get(0);
        log.info("【"+service.getServiceId()+"】"+service.getHost()+": "+service.getPort());
        UserPo userPo=new UserPo();
        userPo.setId(id);
        userPo.setLevel((int) (id&3+1));
        userPo.setUserName("user_name_"+id);
        userPo.setNote("note_"+id);
        return userPo;
    }

這裡DiscoveryClient物件是spring boot自動建立的。

然後我們在產品微服務新增對Ribbon的依賴

Ribbon依賴

        <!-- ribbon負載均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

然後對RestTemplate進行初始化

@SpringBootApplication
public class ProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }

    //初始化RestTemplate
    @LoadBalanced //多節點負載均衡
    @Bean(name="restTemplate")
    public RestTemplate initRestTemplate(){
        return new RestTemplate();
    }
}

測試

@RestController
@RequestMapping("product")
public class ProductController {

    // 注入RestTemplate
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/ribbon")
    public List<UserPo> testRibbon() {
        List<UserPo> list = new ArrayList<>();
        UserPo user = null;
        for (int i = 0; i < 10; i++) {
            //這裡使用USER這個服務ID,代表使用者維服務系統
            //該ID通過屬性spring.application.name來指定
            //user = restTemplate.getForObject("http://USER/user/"+(i+1), UserPo.class);
            Long id = Long.valueOf((i + 1));
            user = restTemplate.getForObject("http://USER/user/"+(i+1),UserPo.class);
            list.add(user);
        }
        return list;
    }
}

程式碼中注入了RestTemplate物件,這是自動實現客戶端均衡負載的物件。然後再方法中使用"USER"這個字串代替了伺服器以及其段哦偶,這是一個服務ID(Service ID),在Eureka伺服器中可以看到它的各個節點,他是使用者微服務通過屬性spring.application.name來指定的。這裡故意地呼叫了10次,這樣就能夠觀察各個使用者微服務節點的日誌來觀察負載均衡的情況。