主頁 > 軟體設計 > 微服務架構 | 4.1 基于 Ribbon 的負載均衡詳解

微服務架構 | 4.1 基于 Ribbon 的負載均衡詳解

2022-01-27 07:32:23 軟體設計

目錄
  • 前言
  • 1. Ribbon 基礎知識
    • 1.1 Ribbon 是什么
    • 1.2 與 Ribbon 互動的三種級別層次
    • 1.3 Ribbon在作業時分成兩步
    • 1.4 服務的提供者與消費者
    • 1.5 Ribbon 核心組件 IRule
  • 2. 服務消費者獲取提供者的三個層次示例
    • 2.1 引入 pom.xml 依賴
    • 2.2 使用 Spring DiscoveryClient 查找服務實體
      • 2.2.1 在主程式類上添加注解
      • 2.2.2 使用 DiscoveryClient 查找資訊
    • 2.3 使用帶有 Ribbon 功能的 Spring RestTemplate 呼叫服務
      • 2.3.1 在主程式類上添加注解
      • 2.3.2 使用 Ribbon 的 RestTemplate 來呼叫服務
    • 2.4 使用 Netflix Feign 客戶端呼叫服務
      • 2.4.1 在主程式類上添加注解
      • 2.4.2 定義用于呼叫服務提供者的 Feign 介面
  • 3. 通過 java 配置類自定義負載均衡演算法示例(消費者服務)
    • 3.1 撰寫配置類
    • 3.2 主啟動類上添加注解
  • 4. 通過配置自定義負載均衡演算法示例(消費者服務)
    • 4.1 修改 bootstrap.yml 組態檔
    • 4.2 主程式類
  • 5. 本地負載均衡器的實作(消費者)
    • 5.1 不使用 RestTemplate
    • 5.2 定義負載均衡介面
    • 5.3 實作負載均衡介面
    • 5.4 在 controller 介面中使用本地負載均衡器
  • 最后


前言

參考資料
《Spring Microservices in Action》
《Spring Cloud Alibaba 微服務原理與實戰》
《B站 尚硅谷 SpringCloud 框架開發教程 周陽》

Spring Cloud Ribbon 是基于 Netflix Ribbon 實作的一套客戶端負載均衡的工具;提供客戶端的軟體負載均衡演算法和服務呼叫;


1. Ribbon 基礎知識

1.1 Ribbon 是什么

  • Spring Cloud Ribbon 是基于 Netflix Ribbon 實作的一套客戶端負載均衡的工具;提供客戶端的軟體負載均衡演算法和服務呼叫;
  • Ribbon 客戶端組件提供一系列完善的配置項如連接超時,重試等,簡單的說,就是在組態檔中列出 Load Balancer(簡稱LB)后面所有的機器,Ribbon 會自動基于某種規則(如簡單輪詢,隨機連接等)去連接這些機器;
  • 可以很容易使用Ribbon實作自定義的負載均衡演算法;

1.2 與 Ribbon 互動的三種級別層次

  • Spring DiscoveryClient:提供了對 Ribbon 和 Ribbon 中快取的注冊服務的最低層次訪問;
  • 啟用了 RestTemplate 的 Spring DiscoveryClient
  • Netflix Feign 客戶端

1.3 Ribbon在作業時分成兩步

Ribbon 架構圖

  • 第一步先選擇 EurekaServer,它優先選擇在同一個區域內負載較少的 server;
    第二步再根據用戶指定的策略,在從 server 取到的服務注冊串列中選擇一個地址;

1.4 服務的提供者與消費者

  • 提供者:服務提供者將自己注冊進注冊中心,讓消費者發現;在本例中有多個提供者給消費者提供服務;
  • 消費者:消費者使用服務發現,找到提供者并呼叫提供者服務;在本例中只有一個消費者在多個提供者中選出一個為自己服務;

1.5 Ribbon 核心組件 IRule

IRule 負載均衡

  • 根據特定演算法中從服務串列中選取一個要訪問的服務;
  • 定義了負載均衡的方式;
  • 有以下幾種負載均衡的實作方式:
    • RoundRobinRule:輪詢;
    • RandomRule:隨機;
    • RetryRule:先按照 RoundRobinRule 的策略獲取服務,如果獲取服務失敗則在指定時間內會進行重試,獲取可用的服務;
    • WeightedResponseTimeRule:對 RoundRobinRule 的擴展,回應速度越快的實體選擇權重越大,越容易被選擇;
    • BestAvailableRule:會先過濾掉由于多次訪問故障而處于斷路器跳閘狀態的服務,然后選擇一個并發量最小的服務;
    • AvailabilityFilteringRule:先過濾掉故障實體,再選擇并發較小的實體;
    • ZoneAvoidanceRule:默認規則,復合判斷 server 所在區域的性能和 server 的可用性選擇服務器;

2. 服務消費者獲取提供者的三個層次示例

2.1 引入 pom.xml 依賴

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
  • 如果使用 Eureka 作為注冊中心,則不用引入該依賴,因為 Eureka 的依賴里包含 ribbon 相關依賴 jar 包;

2.2 使用 Spring DiscoveryClient 查找服務實體

2.2.1 在主程式類上添加注解

  • @EnableDiscoveryClient:表明可以被注冊中心發現,是 Sring Cloud 的觸發器,其作用是使應用程式能夠使用 DiscoveryClient 和 Ribbon 庫;

2.2.2 使用 DiscoveryClient 查找資訊

在服務消費者的 client 包下;

@Component
public class ProviderDiscoveryClient {

    //自動注入 DiscoveryClient 類,該類用于與 Ribbon 互動
    @Autowired
    private DiscoveryClient discoveryClient;

    public Provide getProvide(String providerId) {
        RestTemplate restTemplate = new RestTemplate();
        //獲取服務提供者的所有實體串列,ServiceInstance 用于保存關于服務的特定實體(包括主機名、埠荷 URL)
        List<ServiceInstance> instances = discoveryClient.getInstances("provider-instance-name");

        if (instances.size()==0) return null;
        //檢索要呼叫的服務端點
        String serviceUri = String.format("%s/providers/%s",instances.get(0).getUri().toString(), providerId);

		//使用標準的 Spring REST 模板類去呼叫服務
        ResponseEntity< provider > restExchange =
                restTemplate.exchange(
                        serviceUri,
                        HttpMethod.GET,
                        null, Provider.class, providerId);
        
        return restExchange.getBody();
    }
}
  • 這種方法存在以下問題:

    • 沒有利用 Ribbon 的客戶端負載均衡,呼叫哪個服務實體需要開發人員定義;
    • 開發人員必須構建一個用來呼叫服務的 URL;
    • 實體化 ResTemplate 類,不符合 Spring IoC 規范;
  • 結合本篇《5. 本地負載均衡器的實作(消費者)》即可用到客戶端負載均衡,即:開發人員定義了本地負載均衡器來實作了負載均衡;

2.3 使用帶有 Ribbon 功能的 Spring RestTemplate 呼叫服務

2.3.1 在主程式類上添加注解

@SpringBootApplication //只需要這個注解即可
public class Application {
  @LoadBalanced //告訴 Spring Cloud 創建一個支持 Ribbon 的 RestTemplate
  @Bean
  public RestTemplate getRestTemplate(){
      return new RestTemplate();
  }
  public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
  }
}
  • Spring Cloud 早期版本中,RestTemplate 類默認自動支持 Ribbon;
  • 自從 Spring Cloud 發布 Angel 版本后,Spring Cloud 中的 RestTemplate 不再支持 Ribbon;
  • 因此,后續版本必須使用 @LoadBalanced 注解顯式標注,才能將 Ribbon 和 RestTemplate 一起使用;
  • *RestTemplate 不一定放在主程式類里;也可以在 config 包下新建一個 ApplicationContextConfig 配置類,將 RestTemplate 放在該類里:
@Configuration
public class ApplicationContextConfig{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

2.3.2 使用 Ribbon 的 RestTemplate 來呼叫服務

在服務消費者的 client 包下;

@Component
public class ProviderRestTemplateClient {
    //自動注入即可,不用實體化
    @Autowired
    RestTemplate restTemplate;

    public Provider getProvider(String providerId){
        ResponseEntity<Provider> restExchange =
                restTemplate.exchange(
                        //使用 Eureka 服務 ID 來構建目標 URL
                        "http://provider-instance-name/providers/{providerId}",
                        HttpMethod.GET,
                        null, Provider.class, providerId);
        return restExchange.getBody();
    }
}
  • 通過使用 RestTemplate 類,Ribbon 將在所有服務實體之間輪詢負載均衡所有請求;

2.4 使用 Netflix Feign 客戶端呼叫服務

Feign 相關知識將在下篇《4.2 基于 Feign 與 OpenFeign 的服務介面呼叫》中說明,這里僅把重點放在與上述兩種呼叫提供者服務的區別與對比;

2.4.1 在主程式類上添加注解

@EnableFeignClients:表示啟用 Feign 客戶端;

2.4.2 定義用于呼叫服務提供者的 Feign 介面

@FeignClient("provider-instance-name") //標識服務為 feign 的客戶端
public interface ProviderFeignClient {
    //定義端點的路徑和動作
    @RequestMapping( 
            method= RequestMethod.GET,
            value="https://www.cnblogs.com/providers/{providerId}",
            consumes="application/json")
    //定義傳入端點的引數,該方法可以由客戶端呼叫以觸發組織服務        
    Provider getProvider(@PathVariable("providerId") String providerId);
}
  • 要是用 ProviderFeignClient 類,開發人員只需要自動裝配并使用它即可;

3. 通過 java 配置類自定義負載均衡演算法示例(消費者服務)

指切換默認的負載均衡演算法,切換后的仍為現成的(與本地負載均衡器有所區別,本地負載均衡器要自己實作);

3.1 撰寫配置類

  • 注意:自定義配置類不能放在 @ComponentScan 所掃描的當前包下以及子包下,否則自定義的配置類會被所有的Ribbon客戶端所共享,達不到自定義的目的;
  • @ComponentScan 注解被封裝到主啟動類上的 @SpringBootApplication 注解,其默認掃描主啟動類所在包及其子包,因此我們要回傳上一級目錄新建一個 myRule 目錄存放我們自定義的負載均衡配置類;

自定義負載均衡演算法的檔案目錄結構

@Configuration
public class MySelfRule {
    @Bean
    public IRule myRule(){
        return new RandomRule();//定義為隨機
    }
}

3.2 主啟動類上添加注解

  • @RibbonClient(name = "provider-instance-name" ,configuration=MySelfRule.class):表示使用自定義負載均衡演算法;
    • name:指定服務提供者的實體名稱;
    • configuration:指定需要使用哪個配置類的負載均衡;
    • 表示 provider 服務使用 MySelfRule 對應的 Ribbon 配置;
  • 同樣,需要對 RestTemplate 類用 @LoadBalanced 注解顯示宣告;

4. 通過配置自定義負載均衡演算法示例(消費者服務)

指切換默認的負載均衡演算法,切換后的仍為現成的(與本地負載均衡器有所區別,本地負載均衡器要自己實作);

4.1 修改 bootstrap.yml 組態檔

  • 上述 java 配置類的效果等價于下面這樣的組態檔:
#服務提供者的實體名稱
provider-instance-name:
  ribbon:
    #代表 Ribbon 使用的負載均衡策略,屬性的值為:IRule 的實作類
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    
    #其他可用的配置屬性
    # NFLoadBalancerClassName : 配置 ILoadBalancer 的實作類
    # NFLoadBalancerPingClassName : 配置 IPing 的實作類
    # NIWSServerListClassName: 配置 ServerList 的實作類
    # NIWSServerListFilterClassName: 配置 ServerListtFilter 的實作類

4.2 主程式類

  • 不需要 @RibbonClient 注解;
  • 同樣,需要對 RestTemplate 類用 @LoadBalanced 注解顯示宣告;

5. 本地負載均衡器的實作(消費者)

本地負載均衡器不同于自定義負載均衡演算法;前者的負載均衡演算法需要自己手動實作,后者只是切換成另一種現成的負載均衡演算法;

5.1 不使用 RestTemplate

  • 即主程式類不需要對 RestTemplate 類用 @LoadBalanced 注解顯示宣告;
  • 可以刪去也可以注釋 @LoadBalanced 注解;

5.2 定義負載均衡介面

可以新建一個包,專門存放我們自己寫的負載均衡演算法;

public interface LoadBalancer{
    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}

5.3 實作負載均衡介面

  • 可以根據業務要求寫不同的負載均衡演算法,這里僅提供一種示例;
  • 該示例實作了一種較為簡單的原子性的負載均衡演算法;
@Component
public class MyLB implements LoadBalancer{
    private AtomicInteger atomicInteger = new AtomicInteger(0);
    public final int getAndIncrement(){
        int current;
        int next;

        do {
            current = this.atomicInteger.get();
            next = current >= 2147483647 ? 0 : current + 1;
        }while(!this.atomicInteger.compareAndSet(current,next));
        System.out.println("*****第幾次訪問,次數next: "+next);
        return next;
    }

    //負載均衡演算法:rest介面第幾次請求數 % 服務器集群總數量 = 實際呼叫服務器位置下標  ,每次服務重啟動后rest介面計數從1開始,
    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances){
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}

5.4 在 controller 介面中使用本地負載均衡器

  • 類似于本篇《2.2 使用 Spring DiscoveryClient 查找服務實體》;
  • 不同之處在于 2.2 沒有負載均衡功能,這里在 2.2 的基礎上,開發人員自己定義了本地負載均衡器,不使用 Ribbon 提供的負載均衡,故《5.1 不使用 RestTemplate》中提到的不用對 RestTemplate 類使用 @LoadBalanced 注解顯示宣告
@RestController
public class OrderController{
    //服務提供者示例的名字
    public static final String PAYMENT_URL = "http://provider-instance-name";
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private LoadBalancer loadBalancer;
    @Resource
    private DiscoveryClient discoveryClient;
 
    @GetMapping(value = "https://www.cnblogs.com/provider/mylb")
    public String getProviderLB(){
        //獲取服務提供者的所有實體串列
        List<ServiceInstance> instances = discoveryClient.getInstances("provider-instance-name");
        if(instances == null || instances.size() <= 0){
            return null;
        }
        //使用本地負載均衡器選出提供者服務
        ServiceInstance serviceInstance = loadBalancer.instances(instances);
        URI uri = serviceInstance.getUri();
        return restTemplate.getForObject(uri+"/provider/mylb",String.class);
    }
}


最后

新人制作,如有錯誤,歡迎指出,感激不盡!
歡迎關注公眾號,會分享一些更日常的東西!
如需轉載,請標注出處!

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/421662.html

標籤:其他

上一篇:PowerDotNet平臺化軟體架構設計與實作系列(12):HCRM人員管理平臺

下一篇:PowerDotNet平臺化軟體架構設計與實作系列(12):HCRM人員管理平臺

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more