最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用Gateway自定義負載均衡過濾器

 更新時間:2020年07月06日 10:13:16   作者:愛唱歌的Coder  
這篇文章主要介紹了Java使用Gateway自定義負載均衡過濾器,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

背景

最近項目中需要上傳視頻文件,由于視頻文件可能會比較大,但是我們應用服務器tomcat設置單次只支持的100M,因此決定開發(fā)一個分片上傳接口。
把大文件分成若干個小文件上傳。所有文件上傳完成后通過唯一標示進行合并文件。
我們的開發(fā)人員很快完成了開發(fā),并在單元測試中表現(xiàn)無誤。上傳代碼到測試環(huán)境,喔嚯?。?!出錯了。
經過一段時間的辛苦排查終于發(fā)現(xiàn)問題,測試環(huán)境多實例,分片上傳的接口會被路由到不同的實例,導致上傳后的分片文件在不同的機器,那么也就無法被合并。
知道了原因就好解決,經過一系列的過程最終決定修改網關把uuid相同的請求路由到相同的實例上,這樣就不會出錯了!

準備

由于是公司代碼不方便透露,現(xiàn)使用本地測試代碼。
準備:Eureka注冊中心,Gateway網關,測試微服務

啟動后服務如下兩個測試的微服務,一個網關服務

gateway版本

<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>

此處就說下我網關的配置。

#網關名
spring.cloud.gateway.routes[0].id=route-my-service-id
#網關uri,lb代表負載均衡,后面是服務名,必須要和微服務名一致,不能錯,錯了肯定不能路由
spring.cloud.gateway.routes[0].uri=lb://my-service-id
#斷言,配置的路徑
spring.cloud.gateway.routes[0].predicates[0]=Path=/my-service-id/v3/**
#截取uri前面兩個位置的
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=2

分析

想要修改路由就要知道gateway是如何把我們的請求路由到各個微服務的實例上的。

gateway其實無非就是不同的過濾器,然后對請求進行處理,和zuul類似。gateway自帶了很多過濾器。過濾器分為兩種:

1、GlobalFilter 。顧名思義,全局過濾器,所有請求都會走的過濾器。常見的自帶過濾器LoadBalancerClientFilter(負載均衡過濾器,后面我們就是修改這個地方)。

2、GatewayFilter。網關過濾器,該過濾器可以指定過濾的條件,只有達到了條件的才進入該過濾器。

如果想知道自帶有哪些配置,我們可以查看gateway的自動注入類GatewayAutoConfiguration。

/**
 * @author Spencer Gibb
 */
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class,
		WebFluxAutoConfiguration.class })
@AutoConfigureAfter({ GatewayLoadBalancerClientAutoConfiguration.class,
		GatewayClassPathWarningAutoConfiguration.class })
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {

	@Bean
	public StringToZonedDateTimeConverter stringToZonedDateTimeConverter() {
		return new StringToZonedDateTimeConverter();
	}

	@Bean
	public RouteLocatorBuilder routeLocatorBuilder(
			ConfigurableApplicationContext context) {
		return new RouteLocatorBuilder(context);
	}

	@Bean
	@ConditionalOnMissingBean
	public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(
			GatewayProperties properties) {
		return new PropertiesRouteDefinitionLocator(properties);
	}
省略.......

然后查看負載均衡配置。
GatewayLoadBalancerClientAutoConfiguration

/**
 * @author Spencer Gibb
 */
@Configuration
@ConditionalOnClass({ LoadBalancerClient.class, RibbonAutoConfiguration.class,
		DispatcherHandler.class })
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@EnableConfigurationProperties(LoadBalancerProperties.class)
public class GatewayLoadBalancerClientAutoConfiguration {

	// GlobalFilter beans

	//負載均衡
	@Bean
	@ConditionalOnBean(LoadBalancerClient.class)
	@ConditionalOnMissingBean(LoadBalancerClientFilter.class)
	public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,
			LoadBalancerProperties properties) {
		return new LoadBalancerClientFilter(client, properties);
	}

}

進入LoadBalancerClientFilter,其實就是一個GlobalFilter。
調試代碼試一試呢?發(fā)現(xiàn)果然要走。(此處圖片中應該是my-service-id)。


最終被路由到這個地方,負載均衡使用的是ribbon,關于ribbon暫時不討論。


重點在這兒,通過現(xiàn)在的uri選擇到具體的uri。而這個方法恰恰是一個protected方法,我們可以重寫該方法加上我們自己的業(yè)務邏輯。

protected ServiceInstance choose(ServerWebExchange exchange) {
		return loadBalancer.choose(
				((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost());
	}

實現(xiàn)

重寫LoadBalancerClientFilter中的choose方法,實現(xiàn)自定義邏輯

/**
 * @Description 自定義負載均衡
 * @Author Singh
 * @Date 2020-07-02 10:36
 * @Version
 **/
public class CustomLoadBalancerClientFilter extends LoadBalancerClientFilter implements BeanPostProcessor {

  private final DiscoveryClient discoveryClient;

  private final List<IChooseRule> chooseRules;

  public CustomLoadBalancerClientFilter(LoadBalancerClient loadBalancer,
                     LoadBalancerProperties properties,
                     DiscoveryClient discoveryClient) {
    super(loadBalancer, properties);
    this.discoveryClient = discoveryClient;
    this.chooseRules = new ArrayList<>();
    chooseRules.add(new EngineeringChooseRule());
  }

  protected ServiceInstance choose(ServerWebExchange exchange) {
    if(!CollectionUtils.isEmpty(chooseRules)){
      Iterator<IChooseRule> iChooseRuleIterator = chooseRules.iterator();
      while (iChooseRuleIterator.hasNext()){
        IChooseRule chooseRule = iChooseRuleIterator.next();
        ServiceInstance choose = chooseRule.choose(exchange,discoveryClient);
        if(choose != null){
          return choose;
        }
      }
    }
    return loadBalancer.choose(
        ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost());
  }
}

定義通用選擇實例規(guī)則

/**
 * @Description 自定義選擇實例規(guī)則
 * @Author Singh
 * @Date 2020-07-02 11:03
 * @Version
 **/
public interface IChooseRule {

  /**
   * 返回null那么使用gateway默認的負載均衡策略
   * @param exchange
   * @param discoveryClient
   * @return
   */
  ServiceInstance choose(ServerWebExchange exchange, DiscoveryClient discoveryClient);

}

實現(xiàn)自定義路由策略

/**
 * @Description 微服務負載均衡策略
 * @Author Singh
 * @Date 2020-07-02 11:10
 * @Version
 **/
public class EngineeringChooseRule implements IChooseRule {

  @Override
  public ServiceInstance choose(ServerWebExchange exchange, DiscoveryClient discoveryClient) {
    URI originalUrl = (URI) exchange.getAttributes().get(GATEWAY_REQUEST_URL_ATTR);
    String instancesId = originalUrl.getHost();
    if(instancesId.equals("my-service-id")){
      if(originalUrl.getPath().contains("/files/upload")){
        try{
          List<ServiceInstance> instances = discoveryClient.getInstances(instancesId);
          MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
          String uuid = queryParams.get("uuid").get(0);
          int hash = uuid.hashCode() >>> 16 ;
          int index = hash % instances.size();
          return instances.get(index);
        }catch (Exception e){
          //do nothing
        }
      }
    }

    return null;
  }
}

最后注入自定義負載均衡過濾器。

/**
 * @Description
 * @Author Singh
 * @Date 2020-07-01 17:57
 * @Version
 **/
@Configuration
public class GetawayConfig {

//  @Bean
//  public RouteLocator routeLocator(RouteLocatorBuilder builder) {
//    //lb://hjhn-engineering/files/upload
//    return builder.routes()
//        .route(r ->r.path("/**").filters(
//                    f -> f.stripPrefix(2).filters(new EngineeringGatewayFilter())
//                ).uri("lb://hjhn-engineering")
//        ) .build();
//  }

  @Bean
  public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,
                               LoadBalancerProperties properties,
                              DiscoveryClient discoveryClient) {
      return new CustomLoadBalancerClientFilter(client, properties,discoveryClient);
  }

}

如此,相同uuid的請求就可以通過hash取模路由到相同的機器上了,當然這樣還是存在問題,比如多添加一個實例,或者掛了一個實例,掛之前有一個請求到A,掛之后可能到B,因為此時取模就不同了,還是會到不同請求。但是這種情況很少發(fā)生,所以暫時不考慮。

或許有hash槽的方式可以解決一點問題,后續(xù)研究?。。。?!

到此這篇關于Java使用Gateway自定義負載均衡過濾器的文章就介紹到這了,更多相關Java 自定義負載均衡過濾器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java音頻播放示例分享(java如何播放音頻)

    java音頻播放示例分享(java如何播放音頻)

    java如何播放音頻?下面的代碼就介紹了java音頻播放示例,需要的朋友可以參考下
    2014-04-04
  • 面試JAVA時,問到spring該怎么回答

    面試JAVA時,問到spring該怎么回答

    這篇文章主要介紹了Spring面試資料,學Java的小伙伴都知道Spring是面試的必問環(huán)節(jié),看完了一天就可掌握數(shù)據(jù)結構和算法的面試題,快來看看吧
    2021-08-08
  • java中CompletableFuture異步執(zhí)行方法

    java中CompletableFuture異步執(zhí)行方法

    本文主要介紹了java中CompletableFuture異步執(zhí)行方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • Java堆空間爆滿導致宕機的問題分析及解決

    Java堆空間爆滿導致宕機的問題分析及解決

    團隊有一個服務,一直運行的好好的,突然訪問異常了,先是請求超時,然后直接無法訪問,本文將給大家介紹Java堆空間爆滿導致宕機的問題分析及解決,需要的朋友可以參考下
    2024-02-02
  • MyBatis代碼自動生成器Mybatis-Generator的使用詳解

    MyBatis代碼自動生成器Mybatis-Generator的使用詳解

    本文詳細介紹如何在SpringBoot項目中使用MyBatis-Generator進行代碼生成,包括配置文件的添加、POM依賴配置、運行配置等步驟,通過自動生成代碼,可以簡化MyBatis的繁瑣配置和SQL編寫,提高開發(fā)效率,注意要考慮MySQL版本兼容性,以及確保路徑配置正確
    2024-10-10
  • Spring data JPA只查詢部分字段問題及解決

    Spring data JPA只查詢部分字段問題及解決

    這篇文章主要介紹了Spring data JPA只查詢部分字段問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java基礎:徹底搞懂java多線程

    Java基礎:徹底搞懂java多線程

    篇文章主要介紹了Java多線程的相關資料,幫助大家更好的理解和學習Java線程相關知識,感興趣的朋友可以了解下,希望能給你帶來幫助
    2021-08-08
  • 解決springboot?druid數(shù)據(jù)庫連接池連接失敗后一直重連問題

    解決springboot?druid數(shù)據(jù)庫連接池連接失敗后一直重連問題

    這篇文章主要介紹了解決springboot?druid數(shù)據(jù)庫連接池連接失敗后一直重連問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • PowerJob分布式任務調度源碼流程解讀

    PowerJob分布式任務調度源碼流程解讀

    這篇文章主要為大家介紹了PowerJob分布式任務調度源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-02-02
  • Java中的靜態(tài)代碼塊與構造代碼塊詳解

    Java中的靜態(tài)代碼塊與構造代碼塊詳解

    靜態(tài)代碼塊在JVM加載類時執(zhí)行,僅執(zhí)行一次,用于初始化靜態(tài)變量或執(zhí)行一次性設置,構造代碼塊在每次創(chuàng)建對象時執(zhí)行,用于實例變量的初始化或執(zhí)行創(chuàng)建對象時的公共邏輯,靜態(tài)代碼塊按定義順序執(zhí)行,構造代碼塊在構造方法前執(zhí)行
    2024-11-11

最新評論

台江县| 大庆市| 泰和县| 永济市| 南城县| 揭东县| 那曲县| 陕西省| 兴安盟| 北川| 睢宁县| 宕昌县| 株洲县| 丹江口市| 永泰县| 颍上县| 西丰县| 合水县| 涪陵区| 南溪县| 古蔺县| 金寨县| 邢台市| 遂宁市| 盖州市| 贺兰县| 莱阳市| 朔州市| 都匀市| 嵊泗县| 休宁县| 天峻县| 湖南省| 开江县| 同德县| 吉水县| 惠州市| 峨眉山市| 普兰店市| 渑池县| 云阳县|