開發人員如何解決 Spring Cloud 服務衝突和實例亂竄?

做者:zlt2000
原文:https://www.cnblogs.com/zlt2000/p/11459390.html?utm_source=tuicool&utm_medium=referral複製代碼

開發人員如何解決 Spring Cloud 服務衝突和實例亂竄?

1、背景html

在咱們開發微服務架構系統時,雖說每一個微服務都是孤立的能夠單獨開發,但實際上並不是如此,要調試和測試你的服務不只須要您的微服務啓動和運行,還須要它的上下文服務、依賴的基礎服務等都要運行;但若是你的系統服務數和依賴比較多呢,那就是一個比較棘手的問題!有沒有辦法能提升開發效率呢?前端

開發人員如何解決 Spring Cloud 服務衝突和實例亂竄?

如上圖所示,咱們能不能用服務器把全部的服務都部署起來,而後開發只在本地運行本身所負責開發的服務,由於須要依賴其餘服務因此本地啓動的服務也須要註冊到公共的註冊中內心;java

例子中業務服務B有3臺實例註冊到註冊中內心git

分別是:服務上的、開發A與開發B本身本機啓動的github

可是這樣作又會出現新的問題:服務會衝突亂竄,意思就是開發A在debug本身的業務服務B服務的時候可能請求會跳轉到其餘人的實例上(服務器、開發B)面試

2、解決思路spring

解決這個服務亂竄問題有一個比較優雅的方式就是自定義負載均衡規則,主要實現如下目標:sql

  1. 普通用戶訪問服務器上的頁面時,請求的全部路由只調用服務器上的實例
  2. 開發A訪問時,請求的全部路由優先調用開發A本機啓動的實例,若是沒有則調用服務器上的實例
  3. 開發B訪問時同上,請求的全部路由優先調用開發B本機啓動的實例,若是沒有則調用服務器上的實例

3、具體實現bash

要實現上面的目標有兩個比較關鍵的問題須要解決服務器

  1. 區分不一樣用戶的服務實例
  2. 實現自定義負載均衡規則

3.1. 區分不一樣用戶的服務實例

直接使用註冊中心的元數據(metadata)來區分就能夠了

主流的註冊中心都帶有元數據管理

以Nacos爲例,只須要在配置文件下添加

spring:
 cloud:
 nacos:
 discovery:
 server-addr: localhost:8848
 metadata:
 version: zlt複製代碼

metadata下的version就是我添加的元數據key爲version,value爲zlt

啓動服務後元數據就會註冊上去,以下圖

開發人員如何解決 Spring Cloud 服務衝突和實例亂竄?

通過元數據區分後,目前是下面這個狀況

  • 服務器的實例version爲空
  • 開發人員本身本地啓動的實例version爲惟一標識(本身的名字)

開發人員如何解決 Spring Cloud 服務衝突和實例亂竄?

3.2. 自定義負載均衡規則

首先在Spring Cloud微服務框架裏實例的負載均衡是由Ribbon負責。

CustomIsolationRule詳細類信息可查看:CustomIsolationRule.java

public class CustomIsolationRule extends RoundRobinRule {
 /**
 * 優先根據版本號取實例
 */
 @Override
 public Server choose(ILoadBalancer lb, Object key) {
 if (lb == null) {
 return null;
 }
 String version = LbIsolationContextHolder.getVersion();
 List<Server> targetList = null;
 List<Server> upList = lb.getReachableServers();
 if (StrUtil.isNotEmpty(version)) {
 //取指定版本號的實例
 targetList = upList.stream().filter(
 server -> version.equals(
 ((NacosServer) server).getMetadata().get(CommonConstant.METADATA_VERSION)
 )
 ).collect(Collectors.toList());
 }
 if (CollUtil.isEmpty(targetList)) {
 //只取無版本號的實例
 targetList = upList.stream().filter(
 server -> {
 String metadataVersion = ((NacosServer) server).getMetadata().get(CommonConstant.METADATA_VERSION);
 return StrUtil.isEmpty(metadataVersion);
 }
 ).collect(Collectors.toList());
 }
 if (CollUtil.isNotEmpty(targetList)) {
 return getServer(targetList);
 }
 return super.choose(lb, key);
 }
 /**
 * 隨機取一個實例
 */
 private Server getServer(List<Server> upList) {
 int nextInt = RandomUtil.randomInt(upList.size());
 return upList.get(nextInt);
 }
}複製代碼

集成輪詢規則RoundRobinRule來實現,主要的邏輯爲

  • 根據上游輸入的版本號version,有值的話則取服務元信息中version值同樣的實例
  • 上游的版本號version沒值或者該版本號匹配不到任何服務,則只取服務元信息中version值爲空的實例

並經過配置開關控制是否開啓自定義負載規則

@Configuration
@ConditionalOnProperty(value = "zlt.ribbon.isolation.enabled", havingValue = "true")
@RibbonClients(defaultConfiguration = {RuleConfigure.class})
public class LbIsolationConfig {
}複製代碼

4、總結

上面提到的區分服務實例自定義負載規則爲整個解決思路的核心點,基本實現了服務實例的隔離,剩下要作的就是上游的version怎樣傳遞呢?,下面我提供兩個思路

  • 開發人員本身啓動前端工程,經過配置參數,統一在前端工程傳遞version
  • 經過postman調用接口的時候在header參數中添加

開發人員如何解決 Spring Cloud 服務衝突和實例亂竄?

參考

https://github.com/Nepxion/Discovery

獲取資料:

最後給你們分享一些學習資料,裏面包括:(BATJ面試資料、高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)和Java進階學習路線圖。

免費領取方式:加微信號 weixin99ting 備註驗證消息 (資料)便可獲取。最後,祝你們早日學有所成!

相關文章
相關標籤/搜索