中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

簡單展示網(wǎng)站模板/百度搜索官網(wǎng)

簡單展示網(wǎng)站模板,百度搜索官網(wǎng),手機網(wǎng)站專題,全包圓裝飾公司官網(wǎng)電話目錄 一、介紹 二、常規(guī)的微服務(wù)設(shè)置路由算法方式 三、通過不懈努力,找到解決思路 四、驗證 五、總結(jié) 一、介紹 最近,遇到這么一個需求: 1、需要在網(wǎng)關(guān)層(目前使用zuul)為某一個服務(wù)指定自定義算法IP Hash路由策…

目錄

一、介紹

二、常規(guī)的微服務(wù)設(shè)置路由算法方式

三、通過不懈努力,找到解決思路

四、驗證

五、總結(jié)


一、介紹

最近,遇到這么一個需求:

1、需要在網(wǎng)關(guān)層(目前使用zuul)為某一個服務(wù)指定自定義算法IP Hash路由策略

2、除第一次改造重啟后,后續(xù)為微服務(wù)添加路由算法時,zuul網(wǎng)關(guān)不能重啟,因為會導(dǎo)致用戶短時間內(nèi)不會使用,也就是說,需要動態(tài)的為服務(wù)修改路由算法

基于上訴兩點,本人查找過不少資料,發(fā)現(xiàn)沒有找到符合的解決方案,也可能是關(guān)鍵詞條不準確的問題,導(dǎo)致很長一段時間陷入泥潭,后來通過編程式選擇服務(wù)進行遠程調(diào)用上,找到了修改的思路。

二、常規(guī)的微服務(wù)設(shè)置路由算法方式

?通過網(wǎng)上查找資料,發(fā)現(xiàn)有以下兩種方式進行配置:配置文件、@RibbonClient或@RibbonClients

為了方便后續(xù)這兩種方式的使用案例,以下先提供一個簡單的IP Hash路由算法,根據(jù)ip去計算索引:

public class MyRule extends AbstractLoadBalancerRule {@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {}@Overridepublic Server choose(Object key) {return this.choose(this.getLoadBalancer(), key);}public Server choose(ILoadBalancer lb, Object key) {if (lb == null) {return null;}List<Server> reachableServers = lb.getReachableServers();// 排序一次,避免從新拉取的服務(wù)順序不一致reachableServers = reachableServers.stream().sorted(Comparator.comparing(Server::getId)).collect(Collectors.toList());HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String remoteAddr = request.getRemoteAddr();int hashCode = Math.abs(remoteAddr.hashCode());int  index = hashCode % reachableServers.size();return reachableServers.get(index);}
}

1、配置文件方式

需要在配置文件中加入以下配置

# 你的服務(wù)名
your-service-name:ribbon:NFLoadBalancerRuleClassName: com.xxx.yyy.MyRule

通過配置文件配置的方式,發(fā)現(xiàn),啟動網(wǎng)關(guān)項目之后,通過網(wǎng)關(guān)訪問該服務(wù)的接口,自定的路由策略能夠生效。

但是,當(dāng)后續(xù)遠程配置文件發(fā)生更新之后,也就是,當(dāng)我們在配置文件中給其他服務(wù)也添加上自定義路由算法時(上訴配置復(fù)制一份,修改服務(wù)名即可),然后執(zhí)行refresh或bus-refresh通知網(wǎng)關(guān)服務(wù)進行配置刷新,發(fā)現(xiàn),新增上去的服務(wù)還是默認使用輪詢算法,也就意味著無法動態(tài)為微服務(wù)修改路由算法,需要想要生效,就得重啟網(wǎng)關(guān)服務(wù)。

目前經(jīng)過我自己測試,發(fā)現(xiàn)是無法動態(tài)修改算法的,也可能是我操作有誤之類的。

2、@RibbonClient或@RibbonClients方式

這種方式就不可能實現(xiàn)動態(tài)算法修改了,但以下還是簡單介紹下這種方式的使用。

1)需要準備一個配置類如下,有一點非常重要,這個配置類不能在標注了@SpringBootApplication注解的啟動類掃描路徑下,否則,該算法將被全局共享,而達不到微服務(wù)定制化。

@Configuration
public class MyRuleConfig {@Beanpublic IRule myRule() {return new MyRule();}}

2)可以在啟動器類上添加如下注解

@RibbonClient(name = "your-servcie-name", configuration = {MyRuleConfig.class})

@RibbonClients(value = {@RibbonClient(name = "your-servcie-name", configuration = {MyRuleConfig.class})
})

重啟網(wǎng)關(guān)服務(wù)后,通過網(wǎng)關(guān)訪問該服務(wù),就可以發(fā)現(xiàn)使用了自定義的路由算法。

三、通過不懈努力,找到解決思路

溫馨提示:這一節(jié)涉及到了源碼,如果有不想看的小伙伴,直接跳到第四節(jié)即可。

1、上述兩種方式都不能實現(xiàn)動態(tài)配置微服務(wù)的路由算法,我查找了很多資料,也沒有找到有相對應(yīng)的解決方案,長時間陷入泥潭。

于是,我換了個思路,能不能通過編程式的方式去修改微服務(wù)的路由算法,就是我不通過配置文件,也不通過注解,就通過某個類或類對象,去修改微服務(wù)的路由算法,抱著試一試的心態(tài),就去查找到了手動選擇微服務(wù)實例的實例代碼,如下:

@Resource
LoadBalancerClient loadBalancerClient;ServiceInstance serviceInstance = loadBalancerClient.choose("USERINFO-SERVICE");

2、簡單看看ServiceInstance

public interface ServiceInstance {/*** @return The unique instance ID as registered.*/default String getInstanceId() {return null;}/*** @return The service ID as registered.*/String getServiceId();/*** @return The hostname of the registered service instance.*/String getHost();/*** @return The port of the registered service instance.*/int getPort();/*** @return Whether the port of the registered service instance uses HTTPS.*/boolean isSecure();/*** @return The service URI address.*/URI getUri();/*** @return The key / value pair metadata associated with the service instance.*/Map<String, String> getMetadata();/*** @return The scheme of the service instance.*/default String getScheme() {return null;}
}

發(fā)現(xiàn)ServiceInstance實例對象其實是一個具體待調(diào)用服務(wù)相關(guān)信息,也就意味著,在調(diào)用choose這個方法時,已經(jīng)是通過路由算法選擇出了一個服務(wù)來的,那么重點就是LoadBalancerClient的choose方法,RibbonLoadBalancerClient實現(xiàn)了LoadBalancerClient,我們只需要看這個類即可。

3、查看RibbonLoadBalancerClient的choose方法,如下

@Override
public ServiceInstance choose(String serviceId) {return choose(serviceId, null);
}public ServiceInstance choose(String serviceId, Object hint) {// 此處已經(jīng)拿到了具體的服務(wù)信息,那么getLoadBalancer就是關(guān)鍵Server server = getServer(getLoadBalancer(serviceId), hint);if (server == null) {return null;}return new RibbonServer(serviceId, server, isSecure(server, serviceId),serverIntrospector(serviceId).getMetadata(server));
}protected ILoadBalancer getLoadBalancer(String serviceId) {return this.clientFactory.getLoadBalancer(serviceId);
}protected Server getServer(ILoadBalancer loadBalancer, Object hint) {if (loadBalancer == null) {return null;}// Use 'default' on a null hint, or just pass it on?return loadBalancer.chooseServer(hint != null ? hint : "default");
}

通過choose方法的層級調(diào)用可以知道,選擇出一個具體服務(wù)需要由loadBalancer.chooseServer獲取到。

4、點擊chooseServer的實現(xiàn),可以看到有以三個類可以選擇

BaseLoadBalancer

ZoneAwareLoadBalancer

NoOpLoadBalancer

那么到底選誰呢?遇事不決,最簡單的就是給三個類chooseServer中都打個斷點,然后發(fā)起一次接口調(diào)用,看看會進入哪個類,不出意外的話,就是ZoneAwareLoadBalancer的chooseServer方法,然而,BaseLoadBalancer又是ZoneAwareLoadBalancer的父類,所以,繞了一下,我們看BaseLoadBalancer的chooseServer方法就完事了。

5、查看BaseLoadBalancer的chooseServer方法,如下:

public Server chooseServer(Object key) {if (counter == null) {counter = createCounter();}counter.increment();if (rule == null) {return null;} else {try {// 此處直接調(diào)用了自己的屬性對象rulereturn rule.choose(key);} catch (Exception e) {logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key,     e);return null;}}
}

可以看到關(guān)鍵的調(diào)用rule.choose(key)就拿到了待調(diào)用的服務(wù)信息,那么rule從那里來?不急,我們往上翻,找到這個屬性。

6、在BaseLoadBalancer類的開頭可以找到rule這個屬性對象

private final static IRule DEFAULT_RULE = new RoundRobinRule();protected IRule rule = DEFAULT_RULE;

看到這,我們也有意識到了,默認情況下,它就是默認創(chuàng)建輪詢算法的

接著,我們簡單看看這個類的無參構(gòu)造函數(shù),如下:

public BaseLoadBalancer() {this.name = DEFAULT_NAME;this.ping = null;setRule(DEFAULT_RULE);setupPingTask();lbStats = new LoadBalancerStats(DEFAULT_NAME);}

看到了設(shè)置setRule,在點進去看看

public void setRule(IRule rule) {if (rule != null) {this.rule = rule;} else {/* default rule */this.rule = new RoundRobinRule();}if (this.rule.getLoadBalancer() != this) {this.rule.setLoadBalancer(this);}}

重要的來了,敲黑板!

在setRule中, 我們可以看到?jīng)]在給loadBalancer設(shè)置完rule之后,還得把它自己設(shè)置給rule,這在第二節(jié)中,我們自定義路由算法時,將this.loadBalancer傳遞到了我們自定義的choose方法中用到了。

看到了這一步,我們就要有這么一個大致流程意識了,就是:

1、在第一步通過loadBalancerClient.choose拿到loadBalancer

2、再通過loadBalancer.chooseServer找到實現(xiàn)類BaseLoadBalancer的chooseServer

3、通過BaseLoadBalancer的chooseServer調(diào)用到自己的屬性對象的rule.choose拿到具體待調(diào)用的服務(wù)信息

所以,通過上訴流程,我們簡單得出一個結(jié)論,就是,我們可以通過獲得微服務(wù)對應(yīng)loadBalancer,然后修改它的rule,從而實現(xiàn)動態(tài)更改路由算法。但是,我們又如何拿到服務(wù)對應(yīng)的loadBalancer呢,我們目前流程都沒有提到過怎么去拿,是因為上面所有流程只是說明了最終是調(diào)用loadBalancer中rule的choose方法,接下來我們就講如何拿到微服務(wù)對應(yīng)的loadBalancer。

7、回到第三步,我們看getLoadBalancer這個方法,如下

protected ILoadBalancer getLoadBalancer(String serviceId) {return this.clientFactory.getLoadBalancer(serviceId);
}

我們發(fā)現(xiàn),它是通過this.clientFactory獲取到的loadBalancer,而this.clientFactory的類型是SpringClientFactory。

至此,我就在想,我能不能也通過SpringClientFactory去獲取服務(wù)的loadBalancer,抱著試一試的態(tài)度,我將SpringClientFactory注入進自己的類中,最后發(fā)現(xiàn),真能用,如下:

@Resource
private SpringClientFactory springClientFactory;

我們也能注入使用SpringClientFactory,但它是ribbon包下的一個類,而不是spring默認就有提供的,原因就是在spring-cloud-netflix-ribbon包下有一個類RibbonAutoConfiguration把這個類注冊成了Bean,包括像我們第一步所使用LoadBalancerClient,所以我們也能用到這個Bean

@Bean
public SpringClientFactory springClientFactory() {SpringClientFactory factory = new SpringClientFactory();factory.setConfigurations(this.configurations);return factory;
}@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {    return new RibbonLoadBalancerClient(springClientFactory());
}

好了,自此我們就能通過SpringClientFactory獲取到服務(wù)對應(yīng)的loadBalancer,繼而改掉loadBalancer的rule,從而實現(xiàn)動態(tài)修改rule,接下來就是實踐了。

四、驗證

?1、ServicesRule,用于映射配置文件的結(jié)構(gòu)

public class ServicesRule {private String strategy;private Set<String> services;public String getStrategy() {return strategy;}public void setStrategy(String strategy) {this.strategy = strategy;}public Set<String> getServices() {return services;}public void setServices(Set<String> services) {this.services = services;}
}

2、 RuleProperties,用于與配置文件做關(guān)聯(lián)映射,此處使用@ConfigurationProperties的原因是:當(dāng)遠程配置文件發(fā)生變動,執(zhí)行了refresh或bus-fresh操作時,被該注解修飾的Bean會重新裝配,能夠重新執(zhí)行Bean創(chuàng)建的生命周期(不包括重新創(chuàng)建一個新對象),以該類為例,就是每次刷新時,就會執(zhí)行afterPropertiesSet這個方法。

@ConfigurationProperties(prefix = "services.ribbon")
public class RuleProperties implements InitializingBean, ApplicationContextAware {private List<ServicesRule> rules;private ApplicationContext applicationContext;@Resourceprivate SpringClientFactory springClientFactory;@Overridepublic void afterPropertiesSet() throws Exception {if(rules == null || rules.isEmpty()) {return;}for(ServicesRule rule : rules) {if(StringUtils.isEmpty(rule.getStrategy()) || rule.getServices().isEmpty()) {continue;}Class clazz = Class.forName(rule.getStrategy());if(clazz == null) {continue;}if(!IRule.class.isAssignableFrom(clazz)) {continue;}for(String service : rule.getServices()) {BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) springClientFactory.getLoadBalancer(service);if(baseLoadBalancer == null) {return;}IRule preRule = baseLoadBalancer.getRule();if(preRule.getClass().equals(clazz)) {continue;}AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();IRule iRule = (IRule) beanFactory.createBean(clazz);iRule.setLoadBalancer(baseLoadBalancer);baseLoadBalancer.setRule(iRule);}}}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public List<ServicesRule> getRules() {return rules;}public void setRules(List<ServicesRule> rules) {this.rules = rules;}
}

3、 @ConfigurationProperties需要@EnableConfigurationProperties支持

@EnableConfigurationProperties(value = {RuleProperties.class})
@Configuration
public class RulePropertiesConfiguration {
}

4、配置文件添加以下配置:

# 自動義的可動態(tài)更新路由算法的配置
services:ribbon:rules:- strategy: com.xxx.yyy.myRuleservices:- your-service-name

5、測試

能夠正常為服務(wù)動態(tài)添加自定義的路由算法,無須重啟網(wǎng)關(guān)服務(wù)

6、缺點

1、不支持懶加載,通過我們上述操作,提前將服務(wù)對應(yīng)loadBalancer加載出來了。

2、在替換rule的這個過程中可能存在并發(fā)問題,如果不介意在切換rule過程中,可能存在一瞬間用戶調(diào)用存在問題的情況的話,就可以不做處理。否則,需要自己選擇更為穩(wěn)妥的方式進行動態(tài)路由實現(xiàn)。

五、總結(jié)

?通過這么長度篇幅講了如何動態(tài)修改微服務(wù)的rule,主要是做一次記錄,給大家提供思路,也給我后期遇到同類問題做參考。

http://www.risenshineclean.com/news/404.html

相關(guān)文章:

  • wordpress頁面markdown/seo品牌
  • 三明網(wǎng)站優(yōu)化/推廣優(yōu)化網(wǎng)站排名
  • 有哪些攝影網(wǎng)站/站長工具源碼
  • 建設(shè)網(wǎng)站成本預(yù)算/青島疫情最新情況
  • 外貿(mào)網(wǎng)站使用攻略/自己開網(wǎng)店怎么運營
  • 企業(yè)網(wǎng)站要更新文章嗎/域名注冊查詢?nèi)肟?/a>
  • 支付網(wǎng)站建設(shè)費/正規(guī)的培訓(xùn)學(xué)校
  • 網(wǎng)站關(guān)鍵詞庫如何做/惠州seo推廣外包
  • 做網(wǎng)站jsp和php/成功營銷十大經(jīng)典案例
  • 網(wǎng)站子頁面如何做seo/信息流優(yōu)化師工作總結(jié)
  • 怎么做一簾幽夢網(wǎng)站/全渠道營銷管理平臺
  • 珠海網(wǎng)站建設(shè)小程序/百度搜索網(wǎng)站
  • 武漢企業(yè)建站公司/百度官方電話號碼
  • 二手車交易網(wǎng)站怎么做/百度推廣網(wǎng)址是多少
  • 網(wǎng)站設(shè)計服務(wù)有哪些/網(wǎng)頁seo
  • 網(wǎng)站開發(fā) 項目計劃/免費推廣網(wǎng)站地址大全
  • 鹽城市亭湖區(qū)建設(shè)局網(wǎng)站/博客可以做seo嗎
  • 10個值得推薦的免費設(shè)計網(wǎng)站/怎么讓網(wǎng)站快速收錄
  • photoshop在線修圖/東莞seo管理
  • 門戶網(wǎng)站樣式/百度提問在線回答問題
  • 網(wǎng)站聯(lián)系我們的地圖怎么做的/seo收費標準
  • 北京網(wǎng)站建設(shè)交易/肇慶seo優(yōu)化
  • 網(wǎng)站 色調(diào)/世界搜索引擎大全
  • 南充網(wǎng)站建設(shè)工作室/互聯(lián)網(wǎng)推廣有哪些方式
  • 工業(yè)和信息化部icp網(wǎng)站備案系統(tǒng)/百度查詢?nèi)肟?/a>
  • 游戲推廣網(wǎng)站如何做的/一件代發(fā)48個貨源網(wǎng)站
  • 淘寶客怎么建設(shè)網(wǎng)站/實時新聞
  • 姜堰 萬邦建設(shè)集團網(wǎng)站/seosem是什么職位
  • 信融網(wǎng)站建設(shè)網(wǎng)站開發(fā)/百度推廣代運營公司
  • 做網(wǎng)站傻瓜/汕頭企業(yè)網(wǎng)絡(luò)推廣