具有熔斷能力和活性探測的服務負載均衡解決方案

一、整體架構設計

1.核心組件
  • 負載均衡器:負責選擇可用的服務節點
  • 健康檢查器:定期檢測服務節點的可用性
  • 服務節點管理:維護所有可用節點的狀態信息
2.負載均衡策略
  • 輪詢(Round Robin)
  • 隨機(Random)
  • 加權輪詢(Weighted Round Robin)
  • 最少連接(Least Connection)
  • 一致性哈希(Consistent Hash)

二、完整代碼

1.定義節點服務類
public class ServiceNode {private String ip;private int port;private boolean active;private int weight;private int currentConnections;private long lastActiveTime;// 熔斷相關屬性private int failureCount;private long circuitOpenedTime;private static final int FAILURE_THRESHOLD = 3;private static final long CIRCUIT_BREAKER_TIMEOUT = 30000; // 30秒// 判斷節點是否可用(考慮熔斷狀態)public boolean isAvailable() {if (failureCount >= FAILURE_THRESHOLD) {// 檢查是否應該嘗試恢復if (System.currentTimeMillis() - circuitOpenedTime > CIRCUIT_BREAKER_TIMEOUT) 			  {return true; // 進入半開狀態}return false; // 熔斷中}return active; // 正常狀態}public void recordFailure() {failureCount++;if (failureCount >= FAILURE_THRESHOLD) {circuitOpenedTime = System.currentTimeMillis();}}public void recordSuccess() {failureCount = 0;circuitOpenedTime = 0;}// 其他getter/setter方法...
}
2.負載均衡接口
public interface LoadBalancer {ServiceNode selectNode(List<ServiceNode> nodes);default void onRequestSuccess(ServiceNode node) {node.setLastActiveTime(System.currentTimeMillis());node.setCurrentConnections(node.getCurrentConnections() - 1);}default void onRequestFail(ServiceNode node) {node.setActive(false);}
}
3.實現不同的負載均衡策略
輪詢策略,考慮熔斷狀態
public class RoundRobinLoadBalancer implements LoadBalancer {private final AtomicInteger counter = new AtomicInteger(0);@Overridepublic ServiceNode selectNode(List<ServiceNode> nodes) {List<ServiceNode> availableNodes = nodes.stream().filter(ServiceNode::isAvailable).collect(Collectors.toList());if (availableNodes.isEmpty()) {// 嘗試從不可用節點中選擇已經過了熔斷超時的節點List<ServiceNode> halfOpenNodes = nodes.stream().filter(n -> !n.isHealthy() && n.getFailureCount() >= ServiceNode.FAILURE_THRESHOLD &&System.currentTimeMillis() - n.getCircuitOpenedTime() > ServiceNode.CIRCUIT_BREAKER_TIMEOUT).collect(Collectors.toList());if (!halfOpenNodes.isEmpty()) {// 選擇其中一個進入半開狀態的節點int index = counter.getAndIncrement() % halfOpenNodes.size();ServiceNode selected = halfOpenNodes.get(index);selected.setCurrentConnections(selected.getCurrentConnections() + 1);return selected;}throw new RuntimeException("No available nodes");}int index = counter.getAndIncrement() % availableNodes.size();ServiceNode selected = availableNodes.get(index);selected.setCurrentConnections(selected.getCurrentConnections() + 1);return selected;}@Overridepublic void onRequestSuccess(ServiceNode node) {node.recordSuccess();node.setLastActiveTime(System.currentTimeMillis());node.setCurrentConnections(node.getCurrentConnections() - 1);}@Overridepublic void onRequestFail(ServiceNode node) {node.recordFailure();node.setActive(false);node.setCurrentConnections(node.getCurrentConnections() - 1);}
}
加權輪詢策略
public class WeightedRoundRobinLoadBalancer implements LoadBalancer {private final AtomicInteger counter = new AtomicInteger(0);@Overridepublic ServiceNode selectNode(List<ServiceNode> nodes) {List<ServiceNode> activeNodes = nodes.stream().filter(ServiceNode::isHealthy).collect(Collectors.toList());if (activeNodes.isEmpty()) {throw new RuntimeException("No available nodes");}int totalWeight = activeNodes.stream().mapToInt(ServiceNode::getWeight).sum();int current = counter.getAndIncrement() % totalWeight;for (ServiceNode node : activeNodes) {if (current < node.getWeight()) {node.setCurrentConnections(node.getCurrentConnections() + 1);return node;}current -= node.getWeight();}// fallback to simple round robinint index = counter.get() % activeNodes.size();ServiceNode selected = activeNodes.get(index);selected.setCurrentConnections(selected.getCurrentConnections() + 1);return selected;}
}
4.健康檢查器
public class HealthChecker {private final List<ServiceNode> nodes;private final ScheduledExecutorService scheduler;private final HttpClient httpClient;public HealthChecker(List<ServiceNode> nodes) {this.nodes = nodes;this.scheduler = Executors.newSingleThreadScheduledExecutor();this.httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).connectTimeout(Duration.ofSeconds(2)).build();}public void start() {scheduler.scheduleAtFixedRate(this::checkAllNodes, 0, 10, TimeUnit.SECONDS);}public void stop() {scheduler.shutdown();}private void checkAllNodes() {nodes.parallelStream().forEach(this::checkNode);}private void checkNode(ServiceNode node) {// 如果節點處于熔斷狀態但未超時,不檢查if (node.getFailureCount() >= ServiceNode.FAILURE_THRESHOLD && System.currentTimeMillis() - node.getCircuitOpenedTime() < ServiceNode.CIRCUIT_BREAKER_TIMEOUT) {return;}try {HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://" + node.getIp() + ":" + node.getPort() + "/health")).timeout(Duration.ofSeconds(2)).GET().build();HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());if (response.statusCode() == 200) {node.setActive(true);node.recordSuccess(); // 重置熔斷狀態node.setLastActiveTime(System.currentTimeMillis());} else {node.recordFailure();node.setActive(false);}} catch (Exception e) {node.recordFailure();node.setActive(false);}}
}
5.服務調用封裝
public class ExternalServiceInvoker {private final LoadBalancer loadBalancer;private final List<ServiceNode> nodes;private final HttpClient httpClient;public ExternalServiceInvoker(LoadBalancer loadBalancer, List<ServiceNode> nodes) {this.loadBalancer = loadBalancer;this.nodes = nodes;this.httpClient = HttpClient.newHttpClient();}public String invokeService(String path, String requestBody) throws Exception {ServiceNode node = null;try {node = loadBalancer.selectNode(nodes);HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://" + node.getIp() + ":" + node.getPort() + path)).header("Content-Type", "application/json").timeout(Duration.ofSeconds(5)).POST(HttpRequest.BodyPublishers.ofString(requestBody)).build();HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());if (response.statusCode() >= 200 && response.statusCode() < 300) {loadBalancer.onRequestSuccess(node);return response.body();} else {loadBalancer.onRequestFail(node);throw new RuntimeException("Service call failed with status: " + response.statusCode());}} catch (Exception e) {if (node != null) {loadBalancer.onRequestFail(node);}throw e;}}
}

三、在Spring Boot中的使用

1.配置為Spring Bean
@Configuration
public class LoadBalancerConfiguration {@Beanpublic List<ServiceNode> serviceNodes() {return Arrays.asList(new ServiceNode("192.168.1.101", 8080, 1),new ServiceNode("192.168.1.102", 8080, 1),new ServiceNode("192.168.1.103", 8080, 1),new ServiceNode("192.168.1.104", 8080, 1));}@Beanpublic LoadBalancer loadBalancer() {return new WeightedRoundRobinLoadBalancer();}@Beanpublic HealthChecker healthChecker(List<ServiceNode> nodes) {HealthChecker checker = new HealthChecker(nodes);checker.start();return checker;}@Beanpublic ExternalServiceInvoker externalServiceInvoker(LoadBalancer loadBalancer, List<ServiceNode> nodes) {return new ExternalServiceInvoker(loadBalancer, nodes);}
}
2.在Controller中使用
@RestController
@RequestMapping("/api")
public class MyController {@Autowiredprivate ExternalServiceInvoker serviceInvoker;@PostMapping("/call-external")public ResponseEntity<String> callExternalService(@RequestBody String request) {try {String response = serviceInvoker.invokeService("/external-api", request);return ResponseEntity.ok(response);} catch (Exception e) {return ResponseEntity.status(500).body("Service call failed: " + e.getMessage());}}
}

四、總結與最佳實踐

  1. 選擇合適的負載均衡策略

    • 對于性能相近的節點,使用輪詢或隨機
    • 對于性能差異大的節點,使用加權輪詢
    • 對于長連接服務,考慮最少連接算法
  2. 健康檢查配置建議

    • 檢查間隔:5-30秒
    • 超時時間:1-3秒
    • 檢查端點:/health或/actuator/health
  3. 生產環境注意事項

    • 添加日志記錄節點選擇過程和健康狀態變化
    • 實現優雅降級,當所有節點不可用時返回緩存數據或友好錯誤
    • 考慮使用分布式配置中心動態調整節點列表
  4. 性能優化

    • 使用連接池減少連接建立開銷
    • 實現請求重試機制(帶退避策略)
    • 添加熔斷器模式防止級聯故障
  5. 結合熔斷機制

    1. 完整的熔斷機制:基于失敗計數和超時的自動熔斷/恢復
    2. 三種狀態
      • 關閉(CLOSED):正常狀態
      • 打開(OPEN):熔斷狀態,拒絕請求
      • 半開(HALF-OPEN):嘗試恢復狀態
    3. 與負載均衡深度集成
      • 節點選擇時自動跳過熔斷中的節點
      • 健康檢查會重置成功節點的熔斷狀態
      • 支持半開狀態下的試探性請求
    4. 可視化監控:通過REST端點查看節點和熔斷狀態

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92957.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92957.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92957.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

技術演進中的開發沉思-62 DELPHI VCL系列:VCL下的設計模式

今天聊聊設計模式&#xff0c;當然這個章節目前僅限于DELPHI VCL,因為接下來梳理的Factory/Factory Method、Bootstrap 和 ForEach 這三種設計樣例&#xff0c;看似獨立&#xff0c;卻在實際開發中相互配合&#xff0c;共同構建起高效、靈活的程序架構。在 DELPHI VCL 開發的技…

Docker 101:面向初學者的綜合教程

掌握 Docker 已成為軟件開發中的一項關鍵技能。本教程探討了容器化的世界&#xff0c;包括其核心概念、優缺點&#xff0c;以及開始使用容器化的分步指南。 無論是 Docker 的新手&#xff0c;還是希望復習基礎知識的更有經驗的開發人員&#xff0c;本指南都能滿足需求。 什么…

RTOS YAFFS

在 YAFFS (Yet Another Flash File System) 的語境中&#xff0c;“Check Point” 并不是一個標準的、核心的官方術語。它更可能是對 YAFFS 關鍵機制 Summary 或 Checkpointing 功能的非正式表述或理解偏差。其核心含義是指 YAFFS 在特定時刻保存文件系統關鍵元數據的狀態&…

【SpringBoot系列-02】自動配置機制源碼剖析

【SpringBoot系列-02】自動配置機制源碼剖析 咱們天天用Spring Boot&#xff0c;一個SpringBootApplication注解扔進去&#xff0c;啥配置都不用寫&#xff0c;項目就跑起來了。你有沒有過這種疑惑&#xff1a;那些DispatcherServlet、DataSource是從哪冒出來的&#xff1f;今天…

51單片機-51單片機最小系統

本章概述思維導圖&#xff1a;51單片機最小系統51單片機最小系統是51系列單片機&#xff08;如AT89C51、STC89C52等&#xff09;能夠獨立工作的最簡電路配置&#xff0c;它為單片機提供了運行所需的基本條件。51單片機最小系統板是嵌入式系統開發的基礎平臺&#xff0c;集成了單…

git學習1

目錄引入版本控制集中式和分布式版本控制git工作機制代碼托管中心Git常用命令設置用戶簽名初始化本地庫查看庫狀態add和提交版本穿梭git分支操作分支定義分支好處分支操作查看分支創建分支切換分支分支合并&#x1f495;?&#x1fa77;合并沖突git團隊協作團隊內協作跨團隊協作…

redis原理篇--Dict

Dict數據結構一、Redis字典的核心組件Redis字典由三部分構成&#xff1a;dictht&#xff08;哈希表&#xff09;&#xff1a;存儲桶數組與元數據dictEntry&#xff08;哈希節點&#xff09;&#xff1a;存儲鍵值對dict&#xff08;字典主體&#xff09;&#xff1a;包含雙哈希表…

靜態路由主備切換

在網絡中&#xff0c;靜態路由的主備切換是實現網絡冗余的基礎方案之一&#xff0c;通過配置不同優先級的靜態路由&#xff0c;確保主用路徑故障時&#xff0c;流量能自動切換到備用路徑&#xff0c;提升網絡可靠性。以下從知識講解和實驗配置兩部分詳細說明。一、靜態路由主備…

PDF處理控件Aspose.PDF教程:在C#、Java、Python中快速縮小PDF

如果您的PDF太大&#xff0c;無法通過電子郵件發送&#xff0c;或者在線加載時間過長&#xff0c;您可以在幾秒鐘內縮小 PDF 大小。本教程介紹了借助Aspose.PDF使用 C#、Java 和 Python 編程快速縮小PDF的方法。 Aspose.PDF官方試用版下載 通過編程縮小 PDF 尺寸 如果您需要…

AWS EKS 常用命令大全:從基礎管理到高級運維

前言 Amazon Elastic Kubernetes Service (EKS) 是 AWS 提供的托管 Kubernetes 服務,大大簡化了 K8s 集群的部署和管理工作。作為 EKS 管理員或開發者,熟練掌握 kubectl 命令是日常工作的基礎。本文將詳細介紹 EKS 環境中常用的 kubectl 命令,涵蓋集群管理、工作負載操作、…

GitHub Browser-Use 的部署失敗記錄:失敗了,失敗了。。。。

一、項目背景與核心作用 browser-use 是一個開源的瀏覽器自動化工具&#xff0c;通過集成 AI 智能體&#xff08;如 GPT、Claude、DeepSeek 等大型語言模型&#xff09;&#xff0c;實現用自然語言控制瀏覽器操作。其核心目標是 簡化網頁交互自動化&#xff0c;尤其適合復雜、…

調用springboot接口返回403,問題定位及總結

背景在一次與前端聯調后端接口時前端返回接口返回狀態碼是403&#xff0c;前端返回說已經帶了請求token。排查 查看后端控制臺沒有出現任何錯誤信息。自己postman手動調用接口&#xff0c;發現接口正常。仔細核對前端調用接口與postman請求的區別&#xff0c;沒有發現任何問題。…

布隆過濾器原理分析、應用場景、與redis使用案例

一、核心結構與工作原理1.1 數據結構布隆過濾器由以下兩部分組成&#xff1a;位數組&#xff08;Bit Array&#xff09;&#xff1a;一個長度為 m 的二進制數組&#xff0c;初始所有位為0。哈希函數組&#xff1a;k 個獨立的哈希函數&#xff0c;每個函數將輸入元素映射到位數組…

異步并發×編譯性能:Dart爬蟲的實戰突圍

Dart憑借其高效的異步并發模型、AOT編譯性能和現代化的語法&#xff0c;正成為爬蟲開發中值得關注的新選擇。特別是對于Flutter應用開發者而言&#xff0c;Dart提供了一種"全棧同語言"的獨特優勢。 本文我將通過實戰代碼展示如何利用Dart的核心優勢——包括基于Futur…

Day 8: 深度學習綜合實戰與進階技術 - 從優化到部署的完整流程

Day 8: 深度學習綜合實戰與進階技術 - 從優化到部署的完整流程 ?? 學習目標: 掌握深度學習模型優化、調試、遷移學習等工業級技能,能夠構建高性能的深度學習應用 ?? 核心概念概覽 核心概念解釋: 模型優化: 通過正則化、學習率調度等技術提升模型性能和泛化能力 為什么需…

特征工程--機器學習

1、特征工程1.1 概念特征工程&#xff08;Feature Engineering&#xff09;是機器學習項目中非常關鍵的一步&#xff0c;它是指通過領域知識來選擇、創建或修改能夠使機器學習模型更好地工作的特征&#xff08;即輸入變量&#xff09;。特征工程的目標是提高模型的性能&#xf…

支持任意 MCP 協議的客戶端

支持任意 MCP 協議的客戶端&#xff08;如&#xff1a;Cursor、Claude、Cline&#xff09;可方便使用高德地圖 MCP server。目前支持Streamable HTTP, SSE 和 Node.js I/O 三種接入方式(推薦用戶使用Streamable HTTP)。 快速接入-MCP Server|高德地圖API

【線性代數】目錄

【線性代數】線性方程組與矩陣——&#xff08;1&#xff09;線性方程組與矩陣初步【線性代數】線性方程組與矩陣——行列式【線性代數】線性方程組與矩陣——&#xff08;2&#xff09;矩陣與線性方程組的解【線性代數】線性方程組與矩陣——&#xff08;3&#xff09;線性方程…

豆包新模型+PromptPilot:AI應用開發全流程實戰指南

> 當深度推理的豆包大模型遇上智能提示詞引擎,傳統AI開發中**70%的調試時間被壓縮至幾分鐘**,一場從“手工調參”到“智能優化”的開發范式革命正在發生。 ## 一、技術架構解析:雙引擎驅動智能進化 ### 1.1 豆包新模型的技術突破 2025年火山引擎推出的**豆包1.6系列模型…

Day13 Vue工程化

1.介紹&環境準備 npm兩項全局配置2.項目介紹&開發流程 npm create vue3.3.4 / install / run dev3.API風格 setup ref() onMounted()兩種風格選項式API寫法轉為組合式API寫法在根組件App.vue中引用寫好的xxx.vue4.案例1.引入組件2.完整代碼<script></script&g…