1. 程式人生 > 其它 >OpenFeign與負載均衡

OpenFeign與負載均衡

一、Ribbon與OpenFeign關係

  說到 OpenFeign就不得不提 Ribbon,OpenFeign預設將Ribbon作為負載均衡器,直接內建了 Ribbon。在匯入OpenFeign 依賴後無需專門匯入Ribbon 依賴。

  Ribbon 是 Netflix 公司的一個開源的負載均衡專案,一個客戶端負載均衡器,執行在消費者端。簡單來說就是在消費者端配置對提供者的負載均衡器。這點與 Dubbo略有不同,Dubbo 在消費者端與提供者端均可配置負載均衡器。

二、宣告式Rest客戶端OpenFeign案例

(一)消費端配置

  1、新增openfeign依賴

    注意, 這裡使用的是 spring-cloud-starter-openfeign 依賴,而非 spring-cloud-starter-feign依賴。

        <!--feign依賴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

  2、定義feign介面

    使用@FeignClient設定需要呼叫的專案名稱,同時使用RequestMapping進行呼叫,呼叫地址要和服務提供者的地址保持一致。

@FeignClient(value = "provider01-depart")//註解作用:聲明當前為Feign客戶端介面
@RequestMapping("/provider/depart")// 引數為要呼叫的提供者相應的uri,抽取所有方法的公有uri地址
public interface DepartService {//更加符合面向介面api呼叫習慣
    @PostMapping("/save")
    boolean saveDepart(@RequestBody Depart depart);
    @DeleteMapping(
"/del/{id}") boolean removeDepartById(@PathVariable("id") int id); @PutMapping("/update") boolean modifyDepart(@RequestBody Depart depart); @GetMapping("/get/{id}") Depart getDepartById(@PathVariable("id") int id); @GetMapping("/list") List<Depart> listAllDeparts(); }

  3、處理器注入Feign客戶端物件

@RestController
@RequestMapping("/feign/consumer/depart")
public class DepartFeignController {
    @Autowired
    private DepartService departService;//跨服務根據id查詢
    @GetMapping("/get/{id}")
    public Depart getHandle(@PathVariable("id") int id) {
        return departService.getDepartById(id);
    }
}

  4、修改啟動類

    使用@EnableFeignClients來開啟對Feign客戶端的支援,同時設定客戶端掃描的包。

    由於直接使用了Feign Client,因此就不再使用RestTemplate進行處理了。

@SpringBootApplication
@EnableFeignClients(basePackages = "com.lcl.cloud.alibaba.consumer02.service")//開啟當前服務支援Feign客戶端,作用掃描所有客戶端介面
public class Consumer02Application {

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

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

}

  5、需要注意的一點,就是Feign的服務名稱不能使用下劃線和橫線,否則會報 Service id not legal hostname (provider02_nacosconfig) 的錯誤。

      

(二)超時配置

  1、客戶端的超時配置

feign:
  client:
    config:
      default:
        #連線超時時間
        connectTimeout: 5000
        #資料讀取超時是時間
        readTimeout: 5000

  2、服務端模擬超時  

    public Depart getDepartById(int id) {
        try {
            TimeUnit.SECONDS.sleep(6);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(repository.existsById(id)) {
            return repository.getOne(id);
        }
        Depart depart = new Depart();
        depart.setName(departName);
        return depart;
    }

  3、驗證結果

      

(三)Gzip壓縮設定

  Feign 支援對請求和響應進行 Gzip 壓縮以提高通訊效率。注意,這裡的請求是指 Feign向提供者所提交的請求,響應是指 Feign 向客戶端作出的響應。

      

  配置在官網中可以檢視:https://docs.spring.io/spring-cloud-openfeign/docs/2.2.5.RELEASE/reference/html/#feign-requestresponse-compression

  引數如下所示:

feign.compression.request.enabled=true
feign.compression.response.enabled=true

三、更換負載均衡策略

(一)更換內建策略

  若要更換負載均衡策略,則首先要了解負載均衡策略的定義介面 IRule。Ribbon 預設採用的是 RoundRobinRule,即輪詢策略。但通過修改消費者工程的配置檔案,或修改消費者的啟動類或 JavaConfig 類可以實現更換負載均衡策略的目的。

  1、修改配置檔案

    修改配置檔案,在其中新增如下內容,指定要使用的負載均衡策略 <clientName>. <clientConfigNameSpace>.NFLoadBalancerRuleClassName。

    該方式的好處是,可以為不同的微服務指定相應的負載均衡策略。

provider02Nacosconfig:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

  2、修改JavaConfig類

    在 JavaConfig 類中新增負載 Bean 方法。全域性所有feign對應服務都可以生效。

@Configuration
public class FeignConfiguration {
    /**
     * 配置隨機的負載均衡策略
     * 特點:對所有的服務都生效
     */
    @Bean
    public IRule loadBalancedRule() {
        return new RandomRule();
    }
}

(二)自定義負載均衡策略

  1、定義一個負載均衡策略

    該負載均衡策略的思路是:從所有可用的 provider 中排除掉指定埠號的provider,剩餘 provider 進行隨機選擇。

/**
 * 自定義負載均衡演算法
 */
public class CustomRule implements IRule {
    private ILoadBalancer lb;
    private List<Integer> excludePorts;

    public CustomRule() {
    }

    public CustomRule(List<Integer> excludePorts) {
        this.excludePorts = excludePorts;
    }

    @Override
    public void setLoadBalancer(ILoadBalancer lb) {
        this.lb = lb;
    }

    @Override
    public ILoadBalancer getLoadBalancer() {
        return lb;
    }

    /**
     * 目標:自定義負載均衡策略:從所有可用的provider中排除掉指定埠號的provider,剩餘provider進行隨機選擇
     * 實現步驟:
     * 1.獲取到所有Server
     * 2.從所有Server中排除掉指定埠的Server後,剩餘的Server
     * 3.從剩餘Server中隨機選擇一個Server
     */
    @Override
    public Server choose(Object key) {
        // 1.獲取到所有Server
        List<Server> servers = lb.getReachableServers();
        // 2.從所有Server中排除掉指定埠的Server後,剩餘的Server
        List<Server> availableServers = this.getAvailableServers(servers);
        // 3.從剩餘Server中隨機選擇一個Server
        return this.getAvailableRandomServers(availableServers);
    }

    private List<Server> getAvailableServers(List<Server> servers) {
        // 若沒有指定要排除的port,則返回所有Server
        if(excludePorts == null || excludePorts.size() == 0) {
            return servers;
        }
        List<Server> aservers = servers.stream()
                // filter()
                // noneMatch() 只有當流中所有元素都沒有匹配上時,才返回true,只要有一個匹配上了,則返回false
                .filter(server -> excludePorts.stream().noneMatch(port -> server.getPort() == port))
                .collect(Collectors.toList());

        return aservers;
    }

    private Server getAvailableRandomServers(List<Server> availableServers) {
        // 獲取一個[0,availableServers.size())的隨機數
        int index = new Random().nextInt(availableServers.size());
        return availableServers.get(index);
    }
}

  2、修改JavaConfig類,使用自定義的負載均衡策略

@Configuration
public class FeignConfiguration {
    @Bean
    public IRule loadBalancedRule() {
        List<Integer> list = new ArrayList<>();
        list.add(8081);//排除訪問埠
        return new CustomRule(list);
    }
}

(三)Ribbon內建負載均衡演算法

  1、 RoundRobinRule

    輪詢策略:Ribbon 預設採用的策略。若經過一輪輪詢沒有找到可用的provider,其最多輪詢 10 輪(程式碼中寫死的,不能修改)。若還未找到,則返回 null。

  2、RandomRule

    隨機策略:從所有可用的 provider 中隨機選擇一個。

  3、RetryRule

    重試策略:先按照 RoundRobinRule 策略獲取 server,若獲取失敗,則在指定的時限內重試。預設的時限為 500 毫秒。

  4、BestAvailableRule

    最可用策略:選擇併發量最小的 provider,即連線的消費者數量最少的provider。其會遍歷服務列表中的每一個server,選擇當前連線數量minimalConcurrentConnections 最小的server。

  5、AvailabilityFilteringRule

    可用過濾演算法:該演算法規則是過濾掉處於熔斷狀態的 server 與已經超過連線極限的server,對剩餘 server 採用輪詢策略。

四、負載均衡器SpringCloudLoadBalancer

  由於 Netflix 對於 Ribbon 的維護已經暫停,所以 Spring Cloud 對於負載均衡建議使用由其自己定義的 Spring Cloud LoadBalancer。對於Spring Cloud LoadBalancer 的使用非常簡單。

  1、關閉Ribbon的負載均衡器

spring:
  application:
    name: consumer01-depart
  cloud:
    loadbalancer:
      # 關閉Ribbon的負載均衡器
      ribbon:
        enabled: false

  2、pom中新增LoadBalancer依賴

        <!--spring cloud loadbalancer 依賴--> 
        <dependency> 
            <groupId>org.springframework.cloud</groupId> 
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>
------------------------------------------------------------------
-----------------------------------------------------------
---------------------------------------------
朦朧的夜 留筆~~