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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM