Spring Cloud系列(三):服務消費與負載均衡

上一篇介紹了服務提供者,有了註冊中心和服務提供者,我們就可以進行服務消費了。Spring Cloud可以通過RestTemplate+Ribbon和Feign這兩種方式消費服務。

我們仍然在上一篇的項目中添加功能,btw,源碼是分章節的,而且後一份代碼其實包含了前一份代碼,也就是chapter2包含了chapter1的代碼,每個chapter的源碼其實都是完整可以獨立運行的。

一、啓動註冊中心和服務提供者

先啓動之前的註冊中心和服務提供者,這裏爲了方便啓動單節點的註冊中心就夠了,如果想測試註冊中心集羣的請自行測試,方法在前面的章節已經介紹過,這裏就不再贅述。

啓動成功後訪問http://localhost:8761/,可以看到現在註冊的服務只有一個服務提供者

二、RestTemplate+Ribbon

2.1、新建一個module

新建一個Spring Initializr的module,名稱爲service-consumer-ribbon,選擇Spring Web、Eureka Discovery Client和Ribbon三個依賴,完成後主要依賴如下

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

2.2、創建RestTemplate

爲了方便直接在啓動類添加好了,另外需要加上註解@EnableEurekaClient,把自身註冊到註冊中心

@SpringBootApplication
@EnableEurekaClient
public class ServiceConsumerRibbonApplication {

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

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

2.3、創建Service和Controller

創建一個RibbonConsumerService類和一個RibbonConsumerController類
 

@Service
public class RibbonConsumerService {
    @Autowired
    private RestTemplate restTemplate;

    public String index(String uid) {
        return restTemplate.getForObject("http://SERVICE-PROVIDER/callServiceProvider?uid=" + uid, String.class);
    }
}
@RestController
public class RibbonConsumerController {
    @Autowired
    private RibbonConsumerService ribbonConsumerService;

    @RequestMapping("/index")
    public String index(@RequestParam("uid") String uid) {
        return ribbonConsumerService.index(uid);
    }
}

稍微解釋一下這兩個類:這兩個類的寫法其實就和springboot項目中的寫法沒有什麼區別,就是在Controller中調用Service,唯一需要說明的就是Service類中,通過RestTemplate對象來調用服務提供者提供的接口,其中域名SERVICE-PROVIDER(這裏姑且認爲是域名吧)就是服務提供者的應用名稱(在配置文件中指定)。

2.4、添加配置信息

在application.properties文件中添加以下配置

server.port=8080
spring.application.name=consumer-ribbon

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

這時訪問http://localhost:8761/可以看到註冊的服務多了一個消費者CONSUMER-RIBBON

2.5、測試

在瀏覽器訪問http://localhost:8080/index?uid=ribbon將會返回以下信息

三、Feign

使用Ribbon的方式有一個比較麻煩的地方就是調用提供者的http服務需要手動去構建,而Feign就簡單很多。

3.1、新建一個module

新建一個module,名稱爲service-consumer-feign,選擇Spring Web、Eureka Discovery Client和OpenFeign三個依賴,如下

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

3.2、創建Service和Controller

先在啓動類上加上@EnableEurekaClient和@EnableFeignClients,再創建一個FeignConsumerService接口和一個FeignConsumerController類,FeignConsumerService接口定義如下:

@FeignClient(value = "service-provider")
public interface FeignConsumerService {

    @RequestMapping("/callServiceProvider")
    String index(@RequestParam("uid") String uid);
}

主要就是通過註解的方式聲明一個提供者的服務,@FeignClient註解的值就是服務提供者的應用名稱。

FeignConsumerController類的寫法和RibbonConsumerController的寫法無異,都是在controller中調用service,這裏不多說。

3.3、添加配置信息

在application.properties文件中添加以下配置

server.port=8080
spring.application.name=consumer-feign

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

3.4、啓動&測試

啓動註冊中心、服務提供者和feign消費者項目(如果ribbon消費者項目還在運行先停掉,不然端口會衝突),訪問http://localhost:8080/index?uid=feign

四、負載均衡

到目前爲止我們的服務提供者是單節點的,如果這個節點掛了,那麼所有調用了這個服務提供的接口的服務都無法正常工作,爲了保證服務的高可用,我們需要有多個服務提供者的節點,然後在消費服務時,一方面假如某個甚至幾個服務提供者掛掉之後,還可以有正常的服務在工作,另一方面,加入請求量很大的時候,多個服務提供者的節點也可以分攤流量,減輕單個節點的處理壓力,這一點和Nginx+多個Tomcat的架構是一致的,只不過在這裏我們做負載均衡的組件不是Nginx,而是Ribbon,(Feign的底層也是依賴Ribbon來做負載均衡的)。

4.1、Ribbon負載均衡策略

Ribbon的負載均衡策略源於com.netflix.loadbalancer.IRule接口,有一個抽象類AbstractLoadBalancerRule實現了該接口,而其它官方提供的策略類都是直接或者間接繼承了這個抽象類。下面介紹幾種官方提供的策略

4.1.1、AvailabilityFilteringRule

可用過濾策略:過濾掉一直連接失敗並被標記爲 circuit tripped 的 Server,過濾掉那些高併發連接的 Server(active connections 超過配置的網值)。

4.1.2、BestAvailableRule

最低併發策略:逐個考察 Server,如果 Server 斷路器打開,則忽略,再選擇其中併發連接最低的 Server。

4.1.3、RandomRule

隨機策略:隨機選擇Server。

4.1.4、RetryRule

重試策略:在一個配置時間段內當選擇 Server 不成功,則一直嘗試選擇一個可用的 Server。

4.1.5、RoundRobinRule

輪詢策略:按順序循環選擇Server。

4.1.6、WeightedResponseTimeRule

響應時間權重策略:這是一個基於響應時間來分配的策略,響應時間越短的節點,被選中的概率越大。在舊的版本這個策略的類叫ResponseTimeWeightedRule,新版本建議使用WeightedResponseTimeRule。

4.1.7、ZoneAvoidanceRule

區域權衡策略:綜合判斷Server所在區域的性能和Server的可用性輪詢選擇Server,並且判定一個AWS Zone的運行性能是否可用,剔除不可用的Zone中的所有Server。

4.1.8、CustomRule

自定義策略:好吧,官方當然沒有這麼一個策略類,這裏寫出來的意思是我們可以自己自定義一種策略。

4.2、啓動多個服務提供者

既然要做負載均衡,那麼服務提供者自然不能是單節點,單節點也無法測試各種策略。先在service-provider module中添加三個配置文件application-provider1.properties、application-provider2.properties、application-provider3.properties,然後把application.properties中的內容複製到三個配置文件中,把其中的端口號改掉,創建三個啓動配置項

爲了等會知道調用了那個服務提供者,稍微修改一下啓動類,在其中加上端口的信息
 

@SpringBootApplication
@EnableEurekaClient
@RestController
public class ServiceProviderApplication {

    @Value("${server.port}")
    private int port;

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

    @RequestMapping("/callServiceProvider")
    public String callServiceProvider(@RequestParam("uid") String uid) {
//        return "用戶" + uid + "調用了此服務";
        return "服務" + port + "的消息:用戶" + uid + "調用了此服務";
    }
}

可以先把所有正在運行的服務都停止,然後分別啓動註冊中心和這三個服務提供者和Ribbon消費者,然後訪問<http://localhost:8080/index?uid=ribbon>,當不斷訪問返回的結果是不同的,但是總會按照某個順序返回,比如我的就是8771-8773-8772-8771……這樣的順序返回

服務8771的消息:用戶ribbon調用了此服務
服務8773的消息:用戶ribbon調用了此服務
服務8772的消息:用戶ribbon調用了此服務

目前我們並沒有配置任何的負載均衡策略,但是從結果看已經實現了負載均衡,默認就是RoundRobinRule這種順序輪詢的策略,如果希望按照其它策略分發,只需要在service-consumer-ribbon中的配置文件加上以下配置

SERVICE-PROVIDER.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

service-provider是服務提供者的名稱,值是策略類,比如上面配置的是隨機分發策略。重啓service-consumer-ribbon再次不斷地訪問http://localhost:8080/index?uid=ribbon,可以發現每次返回的結果都是隨機的了。

Feign消費者中的做法是完全一致的,這裏不再贅述。

指定負載均衡策略的另一種方式

我們還可以在啓動類加上一個策略類的Bean,spring在啓動的時候就會加載這個bean來覆蓋默認的策略了

@Bean
public RandomRule randomRule() {
    return new RandomRule();
}

更多的負載均衡的策略可以自行嘗試,這裏就不再過多介紹了。

五、總結

到此,服務消費和負載均衡介紹完畢,下一篇介紹斷路器。

源碼已經上傳到github:https://github.com/spareyaya/spring-cloud-demo/tree/master/chapter3
 

如果你想了解更多java相關的知識,可以訪問我的個人博客:http://notebook.techhuman.cn/

也歡迎你關注我的公衆號獲得文章推送

 

發佈了6 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章