0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Proxyless的多活流量和微服務(wù)治理

京東云 ? 來(lái)源:jf_75140285 ? 作者:jf_75140285 ? 2024-08-28 16:54 ? 次閱讀

1. 引言

1.1 項(xiàng)目的背景及意義

在當(dāng)今的微服務(wù)架構(gòu)中,應(yīng)用程序通常被拆分成多個(gè)獨(dú)立的服務(wù),這些服務(wù)通過(guò)網(wǎng)絡(luò)進(jìn)行通信。這種架構(gòu)的優(yōu)勢(shì)在于可以提高系統(tǒng)的可擴(kuò)展性和靈活性,但也帶來(lái)了新的挑戰(zhàn),比如:

服務(wù)間通信的復(fù)雜性:不同服務(wù)之間需要進(jìn)行可靠的通信,處理失敗重試、負(fù)載均衡等問(wèn)題。

故障的容錯(cuò)處理:系統(tǒng)的復(fù)雜性給與運(yùn)維及故障處理帶來(lái)更大的挑戰(zhàn),如何快速處理故障解決線上問(wèn)題,這是考驗(yàn)一個(gè)企業(yè)基礎(chǔ)設(shè)施建設(shè)的重要關(guān)卡。

最初,開發(fā)者使用SDK來(lái)解決這些問(wèn)題,通過(guò)在代碼中集成各種庫(kù)和工具來(lái)實(shí)現(xiàn)服務(wù)治理。然而,隨著微服務(wù)架構(gòu)的規(guī)模不斷擴(kuò)大,這種方法逐漸顯現(xiàn)出局限性:

代碼侵入性:需要在每個(gè)服務(wù)的代碼中集成和配置各種庫(kù),增加了代碼的復(fù)雜性和維護(hù)成本。

一致性問(wèn)題:不同服務(wù)可能使用不同版本的庫(kù),導(dǎo)致治理邏輯不一致,SDK的升級(jí)難度凸顯。

為了解決這些問(wèn)題,服務(wù)網(wǎng)格(Service Mesh)應(yīng)運(yùn)而生。服務(wù)網(wǎng)格通過(guò)在服務(wù)間引入一個(gè)代理層(通常稱為Sidecar),將服務(wù)治理的邏輯從應(yīng)用代碼中分離出來(lái),實(shí)現(xiàn)了更好的治理和管理。然而,服務(wù)網(wǎng)格的引入也帶來(lái)了額外的復(fù)雜性和性能開銷。

在這樣的背景下,我們通過(guò)Java字節(jié)碼增強(qiáng)技術(shù),在服務(wù)治理領(lǐng)域提供了一種創(chuàng)新的解決方案。它結(jié)合了SDK和服務(wù)網(wǎng)格的優(yōu)點(diǎn),提供了無(wú)侵入性的治理邏輯注入、靈活的擴(kuò)展性和高效的性能優(yōu)化。這種方法不僅簡(jiǎn)化了微服務(wù)架構(gòu)中的服務(wù)治理,還提升了系統(tǒng)的可觀測(cè)性和安全性,對(duì)于現(xiàn)代微服務(wù)環(huán)境具有重要意義。

1.2 項(xiàng)目概述

Joylive Agent 是一個(gè)基于字節(jié)碼增強(qiáng)的框架,專注于多活和單元化場(chǎng)景下的流量治理。它提供了以下功能:多活流量調(diào)度、全鏈路灰度發(fā)布、QPS和并發(fā)限制、標(biāo)簽路由、負(fù)載均衡,熔斷降級(jí),鑒權(quán)等流量治理策略。其特性包括微內(nèi)核架構(gòu)、強(qiáng)類隔離、業(yè)務(wù)零侵入等,使其在保持高性能的同時(shí)對(duì)業(yè)務(wù)代碼影響最小,是面向Java領(lǐng)域的新一代Proxyless Service Mesh探索實(shí)現(xiàn)。

項(xiàng)目地址:
https://github.com/jd-opensource/joylive-agent
重要的事情說(shuō)三遍:求Star,求Star,求Star。請(qǐng)Star完畢后繼續(xù)閱讀后文。

2. 微服務(wù)架構(gòu)演進(jìn)及優(yōu)缺點(diǎn)

2.1 單體架構(gòu)階段

最初,大多數(shù)應(yīng)用都是作為單體應(yīng)用開發(fā)的。所有功能都集中在一個(gè)代碼庫(kù)中,部署也是作為一個(gè)整體。這種形式也是我們學(xué)習(xí)編程之初,最原始的模樣。確切的說(shuō),這種形態(tài)并不屬于微服務(wù)。如下圖所示:

wKgZombO5bOALV66AABWmg83ey8199.jpg

優(yōu)點(diǎn): 簡(jiǎn)單、易于開發(fā)和測(cè)試,適合小團(tuán)隊(duì)和小規(guī)模應(yīng)用。

缺點(diǎn): 這種架構(gòu)隨著應(yīng)用規(guī)模增大,可能會(huì)面臨維護(hù)困難、擴(kuò)展性差等問(wèn)題。

2.2 垂直拆分階段

隨著應(yīng)用規(guī)模的成長(zhǎng),此時(shí)會(huì)考慮將每個(gè)功能模塊(服務(wù))拆分為獨(dú)立的應(yīng)用,也就是垂直拆分,擁有自己的代碼庫(kù)、數(shù)據(jù)庫(kù)和部署生命周期。服務(wù)之間通過(guò)輕量級(jí)協(xié)議(如HTTP、gRPC)通信。也就是正式開啟了面向服務(wù)的架構(gòu)(SOA)。這種形態(tài)體現(xiàn)為:服務(wù)發(fā)現(xiàn)通過(guò)DNS解析,Consumer與Provider之間會(huì)有LB進(jìn)行流量治理。服務(wù)間通過(guò)API進(jìn)行通信。如下圖所示:

wKgaombO5bSAQgRgAAB9EDGfRSE903.jpg

優(yōu)點(diǎn): 獨(dú)立部署和擴(kuò)展,每個(gè)服務(wù)可以由獨(dú)立的團(tuán)隊(duì)開發(fā)和維護(hù),提高了敏捷性。

缺點(diǎn): 增加了分布式系統(tǒng)的復(fù)雜性,需要處理服務(wù)間通信、數(shù)據(jù)一致性、服務(wù)發(fā)現(xiàn)、負(fù)載均衡等問(wèn)題,也因?yàn)橹虚g引入LB而降低了性能。

2.3 微服務(wù)成熟階段

這個(gè)階段引入更多的微服務(wù)治理和管理工具,使用專業(yè)的微服務(wù)框架或中間件,通過(guò)專門定制的微服務(wù)通訊協(xié)議,讓應(yīng)用取得更高的吞吐性能。如API網(wǎng)關(guān)、注冊(cè)中心、分布式追蹤等。DevOps和持續(xù)集成/持續(xù)部署(CI/CD)流程成熟。代表產(chǎn)物如Spring Cloud,Dubbo等。此時(shí)典型的微服務(wù)場(chǎng)景還都是具體的微服務(wù)SDK提供的治理能力。通訊流程為:SDK負(fù)責(zé)向注冊(cè)中心注冊(cè)當(dāng)前服務(wù)信息,當(dāng)需要進(jìn)行服務(wù)消費(fèi)時(shí),同樣向注冊(cè)中心請(qǐng)求服務(wù)提供者信息,然后直連服務(wù)提供者IP及端口并發(fā)送請(qǐng)求。如下圖所示:

wKgZombO5bWADqvSAABDg4bE9is300.jpg

優(yōu)點(diǎn): 高度可擴(kuò)展、彈性和靈活性,支持高頻率的發(fā)布和更新。

缺點(diǎn): 系統(tǒng)復(fù)雜性和運(yùn)維成本較高,需要成熟的技術(shù)棧和團(tuán)隊(duì)能力。微服務(wù)治理能力依賴SDK,升級(jí)更新成本高,需要綁定業(yè)務(wù)應(yīng)用更新。

2.4 服務(wù)網(wǎng)格架構(gòu)

隨著云原生容器化時(shí)代的到來(lái),服務(wù)網(wǎng)格是一種專門用于管理微服務(wù)之間通信的基礎(chǔ)設(shè)施層。它通常包含一組輕量級(jí)的網(wǎng)絡(luò)代理(通常稱為 sidecar),這些代理與每個(gè)服務(wù)實(shí)例一起部署,這利用了K8s中Pod的基礎(chǔ)能力。服務(wù)網(wǎng)格負(fù)責(zé)處理服務(wù)間的通信、流量管理、安全性、監(jiān)控和彈性等功能。這種微服務(wù)治理方式也可以稱之為Proxy模式,其中SideCar即作為服務(wù)之間的Proxy。如下圖所示:

wKgaombO5bWAO9FjAAB-o68YSMY764.jpg

優(yōu)點(diǎn): 主要優(yōu)點(diǎn)是解耦業(yè)務(wù)邏輯與服務(wù)治理的能力,通過(guò)集中控制平面(control plane)簡(jiǎn)化了運(yùn)維管理。

缺點(diǎn): 增加了資源消耗,更高的運(yùn)維挑戰(zhàn)。

3. 項(xiàng)目架構(gòu)設(shè)計(jì)

有沒(méi)有一種微服務(wù)治理方案,既要有SDK架構(gòu)的高性能、多功能的好處,又要有邊車架構(gòu)的零侵入優(yōu)勢(shì), 還要方便好用?這就是項(xiàng)目設(shè)計(jì)的初衷。項(xiàng)目的設(shè)計(jì)充分考慮了上面微服務(wù)的架構(gòu)歷史,結(jié)合多活流量治理模型,進(jìn)行了重新設(shè)計(jì)。其中項(xiàng)目設(shè)計(jì)到的主要技術(shù)點(diǎn)如下,并進(jìn)行詳細(xì)解析。如下圖所示:

wKgZombO5baARujIAAE4uKO4eF0796.jpg

3.1 Proxyless模式

Proxyless模式(無(wú)代理模式)是為了優(yōu)化性能和減少資源消耗而引入的。傳統(tǒng)的微服務(wù)網(wǎng)格通常使用邊車代理(Sidecar Proxy)來(lái)處理服務(wù)之間的通信、安全、流量管理等功能。

我們選擇通過(guò)Java Agent模式實(shí)現(xiàn)Proxyless模式是一種將服務(wù)網(wǎng)格的功能(如服務(wù)發(fā)現(xiàn)、負(fù)載均衡、流量管理和安全性)直接集成到Java應(yīng)用程序中的方法。這種方式可以利用Java Agent在運(yùn)行時(shí)對(duì)應(yīng)用程序進(jìn)行字節(jié)碼操作,從而無(wú)縫地將服務(wù)網(wǎng)格功能注入到應(yīng)用程序中,而無(wú)需顯式修改應(yīng)用代碼。Java Agent模式實(shí)現(xiàn)Proxyless的優(yōu)點(diǎn)如下:

性能優(yōu)化

減少網(wǎng)絡(luò)延遲:傳統(tǒng)的邊車代理模式會(huì)引入額外的網(wǎng)絡(luò)跳數(shù),因?yàn)槊總€(gè)請(qǐng)求都需要通過(guò)邊車代理進(jìn)行處理。通過(guò)Java Agent直接將服務(wù)網(wǎng)格功能注入到應(yīng)用程序中,可以減少這些額外的網(wǎng)絡(luò)開銷,從而降低延遲。

降低資源消耗:不再需要運(yùn)行額外的邊車代理,從而減少了CPU、內(nèi)存和網(wǎng)絡(luò)資源的占用。這對(duì)需要高效利用資源的應(yīng)用非常重要。

簡(jiǎn)化運(yùn)維

統(tǒng)一管理:通過(guò)Java Agent實(shí)現(xiàn)Proxyless模式,所有服務(wù)網(wǎng)格相關(guān)的配置和管理可以集中在控制平面進(jìn)行,而無(wú)需在每個(gè)服務(wù)實(shí)例中單獨(dú)配置邊車代理。這簡(jiǎn)化了運(yùn)維工作,特別是在大型分布式系統(tǒng)中。

減少環(huán)境復(fù)雜性:通過(guò)消除邊車代理的配置和部署,環(huán)境的復(fù)雜性降低,減少了可能出現(xiàn)的配置錯(cuò)誤或版本不兼容問(wèn)題。

數(shù)據(jù)局面升級(jí):Java Agent作為服務(wù)治理數(shù)據(jù)面,天然與應(yīng)用程序解耦,這點(diǎn)是相對(duì)于SDK的最大優(yōu)點(diǎn)。當(dāng)數(shù)據(jù)面面臨版本升級(jí)迭代時(shí),可以統(tǒng)一管控而不依賴于用戶應(yīng)用的重新打包構(gòu)建。

靈活性

無(wú)需修改源代碼與現(xiàn)有生態(tài)系統(tǒng)兼容:Java Agent可以在運(yùn)行時(shí)對(duì)應(yīng)用程序進(jìn)行字節(jié)碼操作,直接在字節(jié)碼層面插入服務(wù)網(wǎng)格相關(guān)的邏輯,而無(wú)需開發(fā)者修改應(yīng)用程序的源代碼。這使得現(xiàn)有應(yīng)用能夠輕松集成Proxyless模式。

動(dòng)態(tài)加載和卸載:Java Agent可以在應(yīng)用程序啟動(dòng)時(shí)或運(yùn)行時(shí)動(dòng)態(tài)加載和卸載。這意味著服務(wù)網(wǎng)格功能可以靈活地添加或移除,適應(yīng)不同的運(yùn)行時(shí)需求。

適用性廣

支持遺留系統(tǒng):對(duì)于無(wú)法修改源代碼的遺留系統(tǒng),Java Agent是一種理想的方式,能夠?qū)F(xiàn)代化的服務(wù)網(wǎng)格功能集成到老舊系統(tǒng)中,提升其功能和性能。

通過(guò)Java Agent實(shí)現(xiàn)Proxyless模式,能夠在保持現(xiàn)有系統(tǒng)穩(wěn)定性的同時(shí),享受服務(wù)網(wǎng)格帶來(lái)的強(qiáng)大功能,是一種高效且靈活的解決方案。

3.2 微內(nèi)核架構(gòu)概述

微內(nèi)核架構(gòu)是一種軟件設(shè)計(jì)模式,主要分為核心功能(微內(nèi)核)和一系列的插件或服務(wù)模塊。微內(nèi)核負(fù)責(zé)處理系統(tǒng)的基礎(chǔ)功能,而其他功能則通過(guò)獨(dú)立的插件或模塊實(shí)現(xiàn)。這種架構(gòu)的主要優(yōu)點(diǎn)是模塊化、可擴(kuò)展性強(qiáng),并且系統(tǒng)的核心部分保持輕量級(jí)。

核心組件:框架的核心組件更多的定義核心功能接口的抽象設(shè)計(jì),模型的定義以及agent加載與類隔離等核心功能,為達(dá)到最小化依賴,很多核心功能都是基于自研代碼實(shí)現(xiàn)。具體可參見joylive-core代碼模塊。

插件化設(shè)計(jì):使用了模塊化和插件化的設(shè)計(jì),分別抽象了像保護(hù)插件,注冊(cè)插件,路由插件,透?jìng)鞑寮蓉S富的插件生態(tài),極大的豐富了框架的可擴(kuò)展性,為適配多樣化的開源生態(tài)奠定了基礎(chǔ)。具體可參見joylive-plugin代碼模塊。

3.3 插件擴(kuò)展體系

項(xiàng)目基于Java的SPI機(jī)制實(shí)現(xiàn)了插件化的擴(kuò)展方式,這也是Java生態(tài)的主流方式。

3.3.1 定義擴(kuò)展

定義擴(kuò)展接口,并使用@Extensible注解來(lái)進(jìn)行擴(kuò)展的聲明。下面是個(gè)負(fù)載均衡擴(kuò)展示例:

@Extensible("LoadBalancer")public interface LoadBalancer {

    int ORDER_RANDOM_WEIGHT = 0;

    int ORDER_ROUND_ROBIN = ORDER_RANDOM_WEIGHT + 1;

    default  T choose(List endpoints, Invocation invocation) {
        Candidate candidate = elect(endpoints, invocation);
        return candidate == null ? null : candidate.getTarget();
    }

     Candidate elect(List endpoints, Invocation invocation);}

3.3.2 實(shí)現(xiàn)擴(kuò)展

實(shí)現(xiàn)擴(kuò)展接口,并使用@Extension注解來(lái)進(jìn)行擴(kuò)展實(shí)現(xiàn)的聲明。如下是實(shí)現(xiàn)了LoadBalancer接口的實(shí)現(xiàn)類:

@Extension(value = RoundRobinLoadBalancer.LOAD_BALANCER_NAME, order = LoadBalancer.ORDER_ROUND_ROBIN)@ConditionalOnProperties(value = {
        @ConditionalOnProperty(value = GovernanceConfig.CONFIG_LIVE_ENABLED, matchIfMissing = true),
        @ConditionalOnProperty(value = GovernanceConfig.CONFIG_LANE_ENABLED, matchIfMissing = true),
        @ConditionalOnProperty(value = GovernanceConfig.CONFIG_FLOW_CONTROL_ENABLED, matchIfMissing = true)}, relation = ConditionalRelation.OR)public class RoundRobinLoadBalancer extends AbstractLoadBalancer {

    public static final String LOAD_BALANCER_NAME = "ROUND_ROBIN";

    private static final Function COUNTER_FUNC = s -> new AtomicLong(0L);

    private final Map counters = new ConcurrentHashMap();

    private final AtomicLong global = new AtomicLong(0);

    @Override
    public  Candidate doElect(List endpoints, Invocation invocation) {
        AtomicLong counter = global;
        ServicePolicy servicePolicy = invocation.getServiceMetadata().getServicePolicy();
        LoadBalancePolicy loadBalancePolicy = servicePolicy == null ? null : servicePolicy.getLoadBalancePolicy();
        if (loadBalancePolicy != null) {
            counter = counters.computeIfAbsent(loadBalancePolicy.getId(), COUNTER_FUNC);
        }
        long count = counter.getAndIncrement();
        if (count < 0) {
            counter.set(0);
            count = counter.getAndIncrement();
        }
        // Ensure the index is within the bounds of the endpoints list.
        int index = (int) (count % endpoints.size());
        return new Candidate(endpoints.get(index), index);
    }}

該類上的注解如下:

@Extension注解聲明擴(kuò)展實(shí)現(xiàn),并提供了名稱

@ConditionalOnProperty注解聲明啟用的條件,可以組合多個(gè)條件

3.3.3 啟用擴(kuò)展

在SPI文件
META-INF/services/com.jd.live.agent.governance.invoke.loadbalance.LoadBalancer中配置擴(kuò)展全路徑名

com.jd.live.agent.governance.invoke.loadbalance.roundrobin.RoundRobinLoadBalancer即達(dá)到啟用效果。

更多詳情可查閱:
https://github.com/jd-opensource/joylive-agent/blob/main/docs/cn/extension.md

3.4 依賴注入設(shè)計(jì)

說(shuō)到依賴注入估計(jì)大家會(huì)立馬想到Spring,的確這是Spring的看家本領(lǐng)。在復(fù)雜的工程中,自動(dòng)化的依賴注入確實(shí)會(huì)簡(jiǎn)化工程的實(shí)現(xiàn)復(fù)雜度。讓開發(fā)人員從復(fù)雜的依賴構(gòu)建中脫離出來(lái),專注于功能點(diǎn)設(shè)計(jì)開發(fā)。依賴注入的實(shí)現(xiàn)是基于上面插件擴(kuò)展體系,是插件擴(kuò)展的功能增強(qiáng)。并且依賴注入支持了兩類場(chǎng)景:注入對(duì)象與注入配置。該功能主要有4個(gè)注解類與3個(gè)接口構(gòu)成。

3.4.1 @Injectable

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Injectable {
    boolean enable() default true;}

這是一個(gè)非常簡(jiǎn)潔的可以應(yīng)用于類、接口(包括注解類型)或枚舉注解。其目的為了標(biāo)識(shí)哪些類開啟了自動(dòng)注入對(duì)象的要求。這點(diǎn)不同于Spring的控制范圍,而是按需注入。實(shí)例構(gòu)建完成后,在自動(dòng)注入的邏輯過(guò)程中會(huì)針對(duì)添加@Injectable注解的實(shí)例進(jìn)行依賴對(duì)象注入。

3.4.2 @Inject

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Inject {
    String value() default "";
    boolean nullable() default false;
    ResourcerType loader() default ResourcerType.CORE_IMPL;}

該注解用于自動(dòng)注入值到字段。它用于指定一個(gè)字段在運(yùn)行時(shí)應(yīng)該注入一個(gè)值,支持基于配置的注入。還可以指示被注入的值是否可以為 null,如果注入過(guò)程中無(wú)注入實(shí)例或注入實(shí)例為null,而nullable配置為false,則會(huì)拋出異常。loader定義了指定要為注釋字段加載的資源或類實(shí)現(xiàn)的類型。ResourcerType為枚舉類型,分別是:CORE,CORE_IMPL,PLUGIN。劃分依據(jù)是工程打包后的jar文件分布目錄。因?yàn)椴煌夸浀念惣虞d器是不同的(類隔離的原因,后面會(huì)講到)。所以可以簡(jiǎn)單理解,這個(gè)配置是用于指定加載該對(duì)象所對(duì)應(yīng)的類加載器。

3.4.3 @Configurable

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Configurable {
    String prefix() default "";
    boolean auto() default false;}

這個(gè)注解類似于@Injectable,用于指定哪些類啟用自動(dòng)注入配置文件的支持。prefix指定用于配置鍵的前綴。這通常意味著前綴將來(lái)自類名或基于某種約定。auto指示配置值是否應(yīng)自動(dòng)注入到注解類的所有合規(guī)字段中。默認(rèn)值為 false,這意味著默認(rèn)情況下未啟用自動(dòng)注入。

3.4.4 @Config

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Config {
    String value() default "";
    boolean nullable() default true;}

該注解用于指定字段配置詳細(xì)信息。它定義了字段的配置鍵以及配置是否為可選。此注釋可用于在運(yùn)行時(shí)自動(dòng)將配置值加載到字段中,并支持指定缺少配置(無(wú)配置)是否被允許。nullable指示字段的配置是否是可選的。如果為真,則系統(tǒng)將允許配置缺失而不會(huì)導(dǎo)致錯(cuò)誤。

下面是具體的使用示例:

@Injectable@Extension(value = "CircuitBreakerFilter", order = OutboundFilter.ORDER_CIRCUIT_BREAKER)public class CircuitBreakerFilter implements OutboundFilter, ExtensionInitializer {
    @Inject
    private Map factories;

    @Inject(nullable = true)
    private CircuitBreakerFactory defaultFactory;

    @Inject(GovernanceConfig.COMPONENT_GOVERNANCE_CONFIG)
    private GovernanceConfig governanceConfig;

    ...}@Configurable(prefix = "app")public class Application {
    @Setter
    @Config("name")
    private String name;
  
    @Setter
    @Config("service")
    private AppService service;
  
    ...}

更多細(xì)節(jié),因?yàn)槠虿辉僬归_。詳情可以了解:
https://github.com/jd-opensource/joylive-agent/blob/main/docs/cn/extension.md

3.5 字節(jié)碼增強(qiáng)機(jī)制

Java 的字節(jié)碼增強(qiáng)(Bytecode Enhancement)是一種動(dòng)態(tài)改變 Java 字節(jié)碼的技術(shù),允許開發(fā)者在類加載之前或加載過(guò)程中修改類的字節(jié)碼。這種機(jī)制在 AOP(面向切面編程)、框架增強(qiáng)、性能監(jiān)控、日志記錄等領(lǐng)域廣泛應(yīng)用。目前看此技術(shù)在APM產(chǎn)品使用較多,而針對(duì)流量治理方向的開源實(shí)現(xiàn)還是比較少的。

Java字節(jié)碼增強(qiáng)的主要方法有:

運(yùn)行時(shí)增強(qiáng):使用Java Agent在類加載時(shí)修改字節(jié)碼。

加載時(shí)增強(qiáng):在類加載到JVM之前修改字節(jié)碼。

編譯時(shí)增強(qiáng):在編譯階段修改或生成字節(jié)碼。

進(jìn)行字節(jié)碼增強(qiáng)的框架有很多,例如:JavaAssist、ASM、ByteBuddy、ByteKit等。我們針對(duì)字節(jié)碼增強(qiáng)的過(guò)程及重要對(duì)象進(jìn)行了接口抽象,并以插件化方式適配了ByteBuddy,開發(fā)了一種默認(rèn)實(shí)現(xiàn)。當(dāng)然你也可以使用其他的框架實(shí)現(xiàn)相應(yīng)的接口,作為擴(kuò)展的其他實(shí)現(xiàn)方式。下面以ByteBuddy為例,展示一個(gè)入門實(shí)例:

import net.bytebuddy.ByteBuddy;import net.bytebuddy.implementation.MethodDelegation;import net.bytebuddy.implementation.SuperMethodCall;import net.bytebuddy.matcher.ElementMatchers;import java.lang.reflect.Method;// 原始類class SimpleClass {
    public void sayHello() {
        System.out.println("Hello, World!");
    }}// 攔截器class SimpleInterceptor {
    public static void beforeMethod() {
        System.out.println("Before saying hello");
    }

    public static void afterMethod() {
        System.out.println("After saying hello");
    }}public class ByteBuddyExample {
    public static void main(String[] args) throws Exception {
        // 使用ByteBuddy創(chuàng)建增強(qiáng)類
        Class dynamicType = new ByteBuddy()
                .subclass(SimpleClass.class)
                .method(ElementMatchers.named("sayHello"))
                .intercept(MethodDelegation.to(SimpleInterceptor.class)
                        .andThen(SuperMethodCall.INSTANCE))
                .make()
                .load(ByteBuddyExample.class.getClassLoader())
                .getLoaded();

        // 創(chuàng)建增強(qiáng)類的實(shí)例
        Object enhancedInstance = dynamicType.getDeclaredConstructor().newInstance();

        // 調(diào)用增強(qiáng)后的方法
        Method sayHelloMethod = enhancedInstance.getClass().getMethod("sayHello");
        sayHelloMethod.invoke(enhancedInstance);
    }}

這個(gè)例子展示了如何使用ByteBuddy來(lái)增強(qiáng)SimpleClass的sayHello方法。讓我解釋一下這個(gè)過(guò)程:

我們定義了一個(gè)簡(jiǎn)單的SimpleClass,它有一個(gè)sayHello方法。

我們創(chuàng)建了一個(gè)SimpleInterceptor類,包含了我們想要在原方法執(zhí)行前后添加的邏輯。

在ByteBuddyExample類的main方法中,我們使用ByteBuddy來(lái)創(chuàng)建一個(gè)增強(qiáng)的類:

我們創(chuàng)建了SimpleClass的一個(gè)子類。

我們攔截了名為"sayHello"的方法。

我們使用MethodDelegation.to(SimpleInterceptor.class)來(lái)添加前置和后置邏輯。

我們使用SuperMethodCall.INSTANCE來(lái)確保原始方法被調(diào)用。

我們創(chuàng)建了增強(qiáng)類的實(shí)例,并通過(guò)反射調(diào)用了sayHello方法。

當(dāng)你運(yùn)行這個(gè)程序時(shí),輸出將會(huì)是:

Before saying hello
Hello, World!After saying hello

當(dāng)然,工程級(jí)別的實(shí)現(xiàn)是遠(yuǎn)比上面Demo的組織形式復(fù)雜的。插件是基于擴(kuò)展實(shí)現(xiàn)的,有多個(gè)擴(kuò)展組成,對(duì)某個(gè)框架進(jìn)行特定增強(qiáng),實(shí)現(xiàn)了多活流量治理等等業(yè)務(wù)邏輯。一個(gè)插件打包成一個(gè)目錄,如下圖所示:

.└── plugin
    ├── dubbo
    │   ├── joylive-registry-dubbo2.6-1.0.0.jar
    │   ├── joylive-registry-dubbo2.7-1.0.0.jar
    │   ├── joylive-registry-dubbo3-1.0.0.jar
    │   ├── joylive-router-dubbo2.6-1.0.0.jar
    │   ├── joylive-router-dubbo2.7-1.0.0.jar
    │   ├── joylive-router-dubbo3-1.0.0.jar
    │   ├── joylive-transmission-dubbo2.6-1.0.0.jar
    │   ├── joylive-transmission-dubbo2.7-1.0.0.jar
    │   └── joylive-transmission-dubbo3-1.0.0.jar

該dubbo插件,支持了3個(gè)版本,增強(qiáng)了注冊(cè)中心,路由和鏈路透?jìng)鞯哪芰?。下面介紹一下在joylive-agent中如何實(shí)現(xiàn)一個(gè)字節(jié)碼增強(qiáng)插件。

3.5.1 增強(qiáng)插件定義接口

增強(qiáng)插件(功能實(shí)現(xiàn)層面的插件)接口的定義采用了插件(系統(tǒng)架構(gòu)層面的插件)擴(kuò)展機(jī)制。如下代碼所示,定義的增強(qiáng)插件名稱為PluginDefinition。

@Extensible("PluginDefinition")public interface PluginDefinition {

    ElementMatcher getMatcher();
    
    InterceptorDefinition[] getInterceptors();}

接口共定義了兩個(gè)方法:getMatcher用于獲取匹配要增強(qiáng)類的匹配器,getInterceptors是返回要增強(qiáng)目標(biāo)類的攔截器定義對(duì)象。

3.5.2 攔截器定義接口

攔截器定義接口主要是用來(lái)確定攔截增強(qiáng)位置(也就是方法),定位到具體方法也就找到了具體增強(qiáng)邏輯執(zhí)行的位置。攔截器定義接口并沒(méi)有采用擴(kuò)展機(jī)制,這是因?yàn)榫唧w到某個(gè)增強(qiáng)目標(biāo)類后,要增強(qiáng)的方法與增強(qiáng)邏輯已經(jīng)是確定行為,不再需要通過(guò)擴(kuò)展機(jī)制實(shí)例化對(duì)象,在具體的增強(qiáng)插件定義接口實(shí)現(xiàn)里會(huì)直接通過(guò)new的方式構(gòu)造蘭機(jī)器定義實(shí)現(xiàn)。攔截器定義接口如下:

public interface InterceptorDefinition {
    
    ElementMatcher getMatcher();
    
    Interceptor getInterceptor();}

該接口同樣抽象了兩個(gè)方法:getMatcher用于獲取匹配要增強(qiáng)方法的匹配器,getInterceptor是用于返回具體的增強(qiáng)邏輯實(shí)現(xiàn),我們稱之為攔截器(Interceptor)。

3.5.3 攔截器接口

攔截器的實(shí)現(xiàn)類是具體增強(qiáng)邏輯的載體,當(dāng)我們要增強(qiáng)某個(gè)類的某個(gè)方法時(shí),與AOP機(jī)制同理,我們抽象了幾處攔截位置。分別是:方法執(zhí)行前(剛進(jìn)入方法執(zhí)行邏輯);方法執(zhí)行結(jié)束時(shí);方法執(zhí)行成功時(shí)(無(wú)異常);方法執(zhí)行出錯(cuò)時(shí)(有異常)。接口定義如下:

public interface Interceptor {
    
    void onEnter(ExecutableContext ctx);

    void onSuccess(ExecutableContext ctx);

    void onError(ExecutableContext ctx);

    void onExit(ExecutableContext ctx);}

增強(qiáng)邏輯的實(shí)現(xiàn)可以針對(duì)不同的功能目標(biāo),選擇合適的增強(qiáng)點(diǎn)。同樣,攔截點(diǎn)的入?yún)xecutableContext也是非常重要的組成部分,它承載了運(yùn)行時(shí)的上下文信息,并且針對(duì)不同的增強(qiáng)目標(biāo)我們做了不同的實(shí)現(xiàn)。如下圖所示:

wKgaombO5baAV9B4AADbYx-KnAc365.jpg

更多詳情可查看:
https://github.com/jd-opensource/joylive-agent/blob/main/docs/cn/plugin.md

3.6 類加載與類隔離

類加載的原理比較容易理解,因?yàn)樵贘ava Agent模式下,應(yīng)用啟動(dòng)時(shí)agent需要加載它所依賴的jar包。然而,如果這些類在加載后被用戶應(yīng)用的類加載器感知到,就可能導(dǎo)致類沖突甚至不兼容的風(fēng)險(xiǎn)。因此,引入類隔離機(jī)制是為了解決這個(gè)問(wèn)題。類隔離的實(shí)現(xiàn)原理并不復(fù)雜。首先,需要實(shí)現(xiàn)自定義的類加載器;其次,需要打破默認(rèn)的雙親委派機(jī)制。通過(guò)這兩步,類隔離可以實(shí)現(xiàn)多層次的隔離,從而避免類沖突和不兼容問(wèn)題。如下圖所示:

wKgaombO5buAQDEeAAE_eKKW8FM158.jpg

3.7 面向請(qǐng)求的抽象

整個(gè)框架的核心行為就是治理請(qǐng)求,而站在一個(gè)應(yīng)用的視角我們可以大體把請(qǐng)求抽象為兩類:InboundRequest與OutboundRequest。InboundRequest是外部進(jìn)入當(dāng)前應(yīng)用的請(qǐng)求,OutboundRequest是當(dāng)前應(yīng)用發(fā)往外部資源的請(qǐng)求。同樣的處理這些請(qǐng)求的過(guò)濾器也同樣分為InboundFilter與OutboundFilter。

請(qǐng)求接口

wKgZombO5b2ABvmkAAEcSg972fQ979.jpg

請(qǐng)求抽象實(shí)現(xiàn)

wKgaombO5b6AB_stAACH8dKEGsQ151.jpg

具體框架的請(qǐng)求適配,如Dubbo

wKgZombO5b-ASJ1KAABKq0AaSyg789.jpg

如上圖所示,展現(xiàn)了適配Dubbo的請(qǐng)求對(duì)象的DubboOutboundRequest與DubboInboundRequest,體現(xiàn)了一個(gè)OutboundRequest與InboundRequest的實(shí)現(xiàn)與繼承關(guān)系。整體看起來(lái)確實(shí)比較復(fù)雜。這是因?yàn)樵谡?qǐng)求抽象時(shí),不僅要考慮請(qǐng)求是Inbound還是Outbound,還要適配不同的協(xié)議框架。例如,像Dubbo和JSF這樣的私有通訊協(xié)議框架需要統(tǒng)一為RpcRequest接口的實(shí)現(xiàn),而SpringCloud這樣的HTTP通訊協(xié)議則統(tǒng)一為HttpRequest。再加上Inbound和Outbound的分類維度,整體的抽象在追求高擴(kuò)展性的同時(shí)也增加了復(fù)雜性。

4. 核心功能

下面提供的流量治理功能,以API網(wǎng)關(guān)作為東西向流量第一入口進(jìn)行流量識(shí)別染色。在很大程度上,API網(wǎng)關(guān)作為東西向流量識(shí)別的第一入口發(fā)揮了重要作用。API網(wǎng)關(guān)在接收到南北向流量后,后續(xù)將全部基于東西向流量治理。

4.1 多活模型及流量調(diào)度

應(yīng)用多活通常包括同城多活和異地多活,異地多活可采用單元化技術(shù)來(lái)實(shí)現(xiàn)。下面描述整個(gè)多活模型涉及到的概念及嵌套關(guān)系。具體實(shí)現(xiàn)原理如下圖所示:

wKgaombO5b-AYcHRAAGkJrTMGdE016.jpg

4.1.1 多活空間

在模型和權(quán)限設(shè)計(jì)方面,我們支持多租戶模式。一個(gè)租戶可以有多個(gè)多活空間,多活空間構(gòu)成如下所示:

.└── 多活空間
    ├── 單元路由變量(*)
    ├── 單元(*)
    │   ├── 分區(qū)(*)
    ├── 單元規(guī)則(*)
    ├── 多活域名(*)
    │   ├── 單元子域名(*)
    │   ├── 路徑(*)
    │   │   ├── 業(yè)務(wù)參數(shù)(*)

4.1.2 單元

單元是邏輯上的概念,一般對(duì)應(yīng)一個(gè)地域。常用于異地多活場(chǎng)景,通過(guò)用戶維度拆分業(yè)務(wù)和數(shù)據(jù),每個(gè)單元獨(dú)立運(yùn)作,降低單元故障對(duì)整體業(yè)務(wù)的影響。

單元的屬性包括單元代碼、名稱、類型(中心單元或普通單元)、讀寫權(quán)限、標(biāo)簽(如地域和可用區(qū))、以及單元下的分區(qū)。

單元分區(qū)是單元的組成部分,單元內(nèi)的邏輯分區(qū),對(duì)應(yīng)云上的可用區(qū)或物理數(shù)據(jù)中心,屬性類似單元。

4.1.3 路由變量

路由變量是決定流量路由到哪個(gè)單元的依據(jù),通常是用戶賬號(hào)。每個(gè)變量可以通過(guò)不同的取值方式(如Cookie、請(qǐng)求頭等)獲取,且可以定義轉(zhuǎn)換函數(shù)來(lái)獲取實(shí)際用戶標(biāo)識(shí)。

變量取值方式則描述如何從請(qǐng)求參數(shù)、請(qǐng)求頭或Cookie中獲取路由變量。

4.1.4 單元規(guī)則

單元規(guī)則定義了單元和分區(qū)之間的流量調(diào)度規(guī)則。根據(jù)路由變量計(jì)算出的值,通過(guò)取模判斷流量應(yīng)路由到哪個(gè)單元。它的屬性包括多活類型、變量、變量取值方式、計(jì)算函數(shù)、變量缺失時(shí)的操作、以及具體的單元路由規(guī)則。

單元路由規(guī)則定義了單元內(nèi)的流量路由規(guī)則,包括允許的路由變量白名單、前綴、值區(qū)間等。

分區(qū)路由規(guī)則定義了單元內(nèi)各個(gè)分區(qū)的流量路由規(guī)則,包括允許的變量白名單、前綴及權(quán)重。

4.1.5 多活域名

多活域名描述啟用多活的域名,用于在網(wǎng)關(guān)層進(jìn)行流量攔截和路由。支持跨地域和同城多活的流量管理,配置路徑規(guī)則以匹配請(qǐng)求路徑并執(zhí)行相應(yīng)的路由規(guī)則。

單元子域名描述各個(gè)單元的子域名,通常用于在HTTP請(qǐng)求或回調(diào)時(shí)閉環(huán)在單元內(nèi)進(jìn)行路由。

路徑規(guī)則定義了根據(jù)請(qǐng)求路徑匹配的路由規(guī)則,取最長(zhǎng)匹配路徑來(lái)選擇適用的路由規(guī)則。

業(yè)務(wù)參數(shù)規(guī)則基于請(qǐng)求參數(shù)值進(jìn)一步精細(xì)化路由,選擇特定的單元規(guī)則。

4.1.6 模型骨架

以下是多活治理模型的基本配置樣例,包括API版本、空間名稱、單元、域名、規(guī)則、變量等。

[
  {
    "apiVersion": "apaas.cos.com/v2alpha1",
    "kind": "MultiLiveSpace",
    "metadata": {
      "name": "mls-abcdefg1",
      "namespace": "apaas-livespace"
    },
    "spec": {
      "id": "v4bEh4kd6Jvu5QBX09qYq-qlbcs",
      "code": "7Jei1Q5nlDbx0dRB4ZKd",
      "name": "TestLiveSpace",
      "version": "2023120609580935201",
      "tenantId": "tenant1",
      "units": [
      ],
      "domains": [
      ],
      "unitRules": [
      ],
      "variables": [
      ]
    }
  }]

以上概念會(huì)比較晦澀難懂,更多詳情可以訪問(wèn):
https://github.com/jd-opensource/joylive-agent/blob/main/docs/cn/livespace.md

4.2 全鏈路灰度(泳道)

泳道是一種隔離和劃分系統(tǒng)中不同服務(wù)或組件的方式,類似于游泳池中的泳道劃分,確保每個(gè)服務(wù)或組件在自己的“泳道”中獨(dú)立運(yùn)作。泳道概念主要用于以下幾種場(chǎng)景:

多租戶架構(gòu)中的隔離

在多租戶系統(tǒng)中,泳道通常用于隔離不同租戶的資源和服務(wù)。每個(gè)租戶有自己的獨(dú)立“泳道”,以確保數(shù)據(jù)和流量的隔離,防止不同租戶之間的相互影響。

流量隔離與管理

泳道可以用于根據(jù)特定規(guī)則(例如用戶屬性、地理位置、業(yè)務(wù)特性等)將流量分配到不同的微服務(wù)實(shí)例或集群中。這種方式允許團(tuán)隊(duì)在某些條件下測(cè)試新版本、進(jìn)行藍(lán)綠部署、金絲雀發(fā)布等,而不會(huì)影響到其他泳道中的流量。

業(yè)務(wù)邏輯劃分

在某些場(chǎng)景下,泳道也可以代表業(yè)務(wù)邏輯的劃分。例如,一個(gè)電商平臺(tái)可能會(huì)針對(duì)不同的用戶群體(如普通用戶、VIP用戶)提供不同的服務(wù)路徑和處理邏輯,形成不同的泳道。

版本管理

泳道可以用來(lái)管理微服務(wù)的不同版本,使得新版本和舊版本可以在不同的泳道中并行運(yùn)行,從而降低升級(jí)時(shí)的風(fēng)險(xiǎn)。

開發(fā)和測(cè)試

在開發(fā)和測(cè)試過(guò)程中,不同的泳道可以用于隔離開發(fā)中的新功能、測(cè)試環(huán)境、甚至是不同開發(fā)團(tuán)隊(duì)的工作,從而減少互相干擾。

泳道的核心目的是通過(guò)隔離服務(wù)或資源,提供獨(dú)立性和靈活性,確保系統(tǒng)的穩(wěn)定性和可擴(kuò)展性。這種隔離機(jī)制幫助組織更好地管理復(fù)雜系統(tǒng)中的多樣性,尤其是在處理高并發(fā)、多租戶、或者需要快速迭代的場(chǎng)景下。功能流程如下圖所示:

wKgZombO5cCAYYNeAAFejlVBxq8274.jpg

模型定義及更多詳情可以訪問(wèn):
https://github.com/jd-opensource/joylive-agent/blob/main/docs/cn/lane.md

4.3 微服務(wù)治理策略

微服務(wù)治理策略是指在微服務(wù)架構(gòu)中,為確保服務(wù)的穩(wěn)定性、可靠性、安全性以及高效運(yùn)作而制定的一系列管理和控制措施。這些策略幫助企業(yè)有效地管理、監(jiān)控、協(xié)調(diào)和優(yōu)化成百上千個(gè)微服務(wù)的運(yùn)行,以應(yīng)對(duì)分布式系統(tǒng)的復(fù)雜性。目前我們實(shí)現(xiàn)了部分主流的微服務(wù)策略例如:負(fù)載均衡,重試,限流,熔斷降級(jí),標(biāo)簽路由,訪問(wèn)鑒權(quán)等,更多的實(shí)用策略也在陸續(xù)補(bǔ)充中。微服務(wù)框架方面已經(jīng)支持主流框架,如:Spring Cloud,Dubbo2/3,JSF,SofaRpc等。

由于篇幅原因,具體的治理策略與模型就不詳盡展開介紹了,下圖概括了服務(wù)治理的全貌。

wKgaombO5cCAFJIuAAJNRqbQEi0800.jpg

值得一提有兩點(diǎn):

策略的實(shí)現(xiàn)屏蔽了底層框架的差異性,這得益于上面提到的面向請(qǐng)求的抽象。

統(tǒng)一治理層級(jí)的劃分,多層級(jí)的策略掛載框架允許治理策略可以靈活的控制策略生效的影響半徑。

統(tǒng)一HTTP和傳統(tǒng)RPC的治理策略配置層級(jí)具體細(xì)節(jié)如下:

.└── 服務(wù)
    ├── 分組*
    │   ├── 路徑*
    │   │   ├── 方法*

服務(wù)治理策略放在分組、路徑和方法上,可以逐級(jí)設(shè)置,下級(jí)默認(rèn)繼承上級(jí)的配置。服務(wù)的默認(rèn)策略設(shè)置到默認(rèn)分組default上。

類型 服務(wù) 分組 路徑 方法
HTTP 域名 分組 URL路徑 HTTP方法
RPC 應(yīng)用級(jí)注冊(cè) 應(yīng)用名 分組 接口名 方法名
RPC 接口級(jí)注冊(cè) 接口名 分組 / 方法名

模型定義及更多詳情可以訪問(wèn):
https://github.com/jd-opensource/joylive-agent/blob/main/docs/cn/governance.md

5. 功能實(shí)現(xiàn)示例

5.1 服務(wù)注冊(cè)

5.1.1 服務(wù)注冊(cè)

在應(yīng)用啟動(dòng)過(guò)程中,注冊(cè)插件會(huì)攔截獲取到消費(fèi)者和服務(wù)提供者的初始化方法,會(huì)修改其元數(shù)據(jù),增加多活和泳道的標(biāo)簽。后續(xù)往注冊(cè)中心注冊(cè)的時(shí)候就會(huì)帶有相關(guān)的標(biāo)簽了。這是框架所有治理功能的前提基礎(chǔ)。以下是Dubbo服務(wù)提供者注冊(cè)樣例:

@Injectable@Extension(value = "ServiceConfigDefinition_v3", order = PluginDefinition.ORDER_REGISTRY)@ConditionalOnProperties(value = {
        @ConditionalOnProperty(value = GovernanceConfig.CONFIG_LIVE_ENABLED, matchIfMissing = true),
        @ConditionalOnProperty(value = GovernanceConfig.CONFIG_LANE_ENABLED, matchIfMissing = true),
        @ConditionalOnProperty(value = GovernanceConfig.CONFIG_FLOW_CONTROL_ENABLED, matchIfMissing = true)}, relation = ConditionalRelation.OR) @ConditionalOnClass(ServiceConfigDefinition.TYPE_CONSUMER_CONTEXT_FILTER)@ConditionalOnClass(ServiceConfigDefinition.TYPE_SERVICE_CONFIG)public class ServiceConfigDefinition extends PluginDefinitionAdapter {
    
    protected static final String TYPE_SERVICE_CONFIG = "org.apache.dubbo.config.ServiceConfig";

    private static final String METHOD_BUILD_ATTRIBUTES = "buildAttributes";

    private static final String[] ARGUMENT_BUILD_ATTRIBUTES = new String[]{
            "org.apache.dubbo.config.ProtocolConfig"
    };

    // ......

    public ServiceConfigDefinition() {
        this.matcher = () -> MatcherBuilder.named(TYPE_SERVICE_CONFIG);
        this.interceptors = new InterceptorDefinition[]{
                new InterceptorDefinitionAdapter(
                        MatcherBuilder.named(METHOD_BUILD_ATTRIBUTES).
                                and(MatcherBuilder.arguments(ARGUMENT_BUILD_ATTRIBUTES)),
                        () -> new ServiceConfigInterceptor(application, policySupplier))
        };
    }}
public class ServiceConfigInterceptor extends InterceptorAdaptor {

    // ......
    
    @Override
    public void onSuccess(ExecutableContext ctx) {
        MethodContext methodContext = (MethodContext) ctx;

        Map map = (Map) methodContext.getResult();
        application.label(map::putIfAbsent);

        // ......
    }}

上面例子所呈現(xiàn)的效果是,當(dāng)dubbo應(yīng)用啟動(dòng)時(shí),增強(qiáng)插件攔截dubbo框架
org.apache.dubbo.config.ServiceConfig中的buildAttributes方法進(jìn)行增強(qiáng)處理。從ServiceConfigInterceptor的實(shí)現(xiàn)中可以看出,當(dāng)buildAttributes方法執(zhí)行成功后,對(duì)該方法的返回的Map對(duì)象繼續(xù)增加了框架額外的元數(shù)據(jù)標(biāo)簽。

5.1.2 服務(wù)策略訂閱

如果注意ServiceConfigInterceptor的增強(qiáng)會(huì)發(fā)現(xiàn),在給注冊(cè)示例打標(biāo)之后,還有一部分邏輯,如下:

public class ServiceConfigInterceptor extends InterceptorAdaptor {

    @Override
    public void onSuccess(ExecutableContext ctx) {
        MethodContext methodContext = (MethodContext) ctx;

        // ......

        AbstractInterfaceConfig config = (AbstractInterfaceConfig) ctx.getTarget();
        ApplicationConfig application = config.getApplication();
        String registerMode = application.getRegisterMode();
        if (DEFAULT_REGISTER_MODE_INSTANCE.equals(registerMode)) {
            policySupplier.subscribe(application.getName());
        } else if (DEFAULT_REGISTER_MODE_INTERFACE.equals(registerMode)) {
            policySupplier.subscribe(config.getInterface());
        } else {
            policySupplier.subscribe(application.getName());
            policySupplier.subscribe(config.getInterface());
        }
    }}

policySupplier.subscribe所執(zhí)行的是策略訂閱邏輯。因?yàn)椴呗允侵С譄岣虏?shí)時(shí)生效的,策略訂閱邏輯便是開啟了訂閱當(dāng)前服務(wù)在控制臺(tái)所配置策略的邏輯。

5.2 流量控制

5.2.1 入流量攔截點(diǎn)

入流量攔截也就是攔截Inbound請(qǐng)求,攔截相關(guān)框架的入流量處理鏈的入口或靠前的處理器的相關(guān)邏輯并予以增強(qiáng)。下面以Dubbo3的攔截點(diǎn)為例。

@Injectable@Extension(value = "ClassLoaderFilterDefinition_v3")@ConditionalOnProperty(value = GovernanceConfig.CONFIG_LIVE_ENABLED, matchIfMissing = true)@ConditionalOnProperty(value = GovernanceConfig.CONFIG_LIVE_DUBBO_ENABLED, matchIfMissing = true)@ConditionalOnProperty(value = GovernanceConfig.CONFIG_REGISTRY_ENABLED, matchIfMissing = true)@ConditionalOnProperty(value = GovernanceConfig.CONFIG_TRANSMISSION_ENABLED, matchIfMissing = true)@ConditionalOnClass(ClassLoaderFilterDefinition.TYPE_CLASSLOADER_FILTER)public class ClassLoaderFilterDefinition extends PluginDefinitionAdapter {

    protected static final String TYPE_CLASSLOADER_FILTER = "org.apache.dubbo.rpc.filter.ClassLoaderFilter";
    
    private static final String METHOD_INVOKE = "invoke";

    protected static final String[] ARGUMENT_INVOKE = new String[]{
            "org.apache.dubbo.rpc.Invoker",
            "org.apache.dubbo.rpc.Invocation"
    };

    // ......

    public ClassLoaderFilterDefinition() {
        this.matcher = () -> MatcherBuilder.named(TYPE_CLASSLOADER_FILTER);
        this.interceptors = new InterceptorDefinition[]{
                new InterceptorDefinitionAdapter(
                        MatcherBuilder.named(METHOD_INVOKE).
                                and(MatcherBuilder.arguments(ARGUMENT_INVOKE)),
                        () -> new ClassLoaderFilterInterceptor(context)
                )
        };
    }}
public class ClassLoaderFilterInterceptor extends InterceptorAdaptor {

    private final InvocationContext context;

    public ClassLoaderFilterInterceptor(InvocationContext context) {
        this.context = context;
    }
    
    @Override
    public void onEnter(ExecutableContext ctx) {
        MethodContext mc = (MethodContext) ctx;
        Object[] arguments = mc.getArguments();
        Invocation invocation = (Invocation) arguments[1];
        try {
            context.inbound(new DubboInboundInvocation(new DubboInboundRequest(invocation), context));
        } catch (RejectException e) {
            Result result = new AppResponse(new RpcException(RpcException.FORBIDDEN_EXCEPTION, e.getMessage()));
            mc.setResult(result);
            mc.setSkip(true);
        }
    }}
public interface InvocationContext {

    // ......
    
    default  void inbound(InboundInvocation invocation) {
        InboundFilterChain.Chain chain = new InboundFilterChain.Chain(getInboundFilters());
        chain.filter(invocation);
    }
    }

上面展示了針對(duì)Dubbo框架的增強(qiáng)處理是選擇了
org.apache.dubbo.rpc.filter.ClassLoaderFilter的invoke方法作為攔截點(diǎn),織入我們統(tǒng)一的InboundFilterChain對(duì)象作為入流量處理鏈。我們可以根據(jù)需求實(shí)現(xiàn)不同的InboundFilter即可,我們內(nèi)置了一部分實(shí)現(xiàn)。如下所示:

wKgZombO5cGAXuz2AACbDkSpAxc045.jpg

過(guò)濾器 名稱 說(shuō)明
RateLimitInboundFilter 限流過(guò)濾器 根據(jù)當(dāng)前服務(wù)的限流策略來(lái)進(jìn)行限流
ConcurrencyLimitInboundFilter 并發(fā)過(guò)濾器 根據(jù)當(dāng)前服務(wù)的并發(fā)策略來(lái)進(jìn)行限流
ReadyInboundFilter 治理就緒過(guò)濾器 判斷治理狀態(tài),只有就緒狀態(tài)才能進(jìn)入流量
UnitInboundFilter 單元過(guò)濾器 判斷當(dāng)前請(qǐng)求是否匹配當(dāng)前單元,以及當(dāng)前單元是否可以訪問(wèn)
CellInboundFilter 分區(qū)過(guò)濾器 判斷當(dāng)前分區(qū)是否可以訪問(wèn)
FailoverInboundFilter 糾錯(cuò)過(guò)濾器 目前對(duì)錯(cuò)誤流量只實(shí)現(xiàn)了拒絕

5.2.2 出流量攔截點(diǎn)

出流量攔截也就是攔截Outbound請(qǐng)求,攔截相關(guān)框架的出流量處理鏈的入口并予以增強(qiáng)。下面以Dubbo2的攔截點(diǎn)為例。

如果只開啟了多活或泳道治理,則只需對(duì)后端實(shí)例進(jìn)行過(guò)濾,可以攔截負(fù)載均衡或服務(wù)實(shí)例提供者相關(guān)方法

@Injectable@Extension(value = "LoadBalanceDefinition_v2.7")@ConditionalOnProperties(value = {
        @ConditionalOnProperty(name = {
                GovernanceConfig.CONFIG_LIVE_ENABLED,
                GovernanceConfig.CONFIG_LANE_ENABLED
        }, matchIfMissing = true, relation = ConditionalRelation.OR),
        @ConditionalOnProperty(name = GovernanceConfig.CONFIG_FLOW_CONTROL_ENABLED, value = "false"),
        @ConditionalOnProperty(name = GovernanceConfig.CONFIG_LIVE_DUBBO_ENABLED, matchIfMissing = true)}, relation = ConditionalRelation.AND)@ConditionalOnClass(LoadBalanceDefinition.TYPE_ABSTRACT_CLUSTER)@ConditionalOnClass(ClassLoaderFilterDefinition.TYPE_CONSUMER_CLASSLOADER_FILTER)public class LoadBalanceDefinition extends PluginDefinitionAdapter {

    protected static final String TYPE_ABSTRACT_CLUSTER = "com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker";

    private static final String METHOD_SELECT = "select";

    private static final String[] ARGUMENT_SELECT = new String[]{
            "org.apache.dubbo.rpc.cluster.LoadBalance",
            "org.apache.dubbo.rpc.Invocation",
            "java.util.List",
            "java.util.List"
    };

    // ......

    public LoadBalanceDefinition() {
        this.matcher = () -> MatcherBuilder.isSubTypeOf(TYPE_ABSTRACT_CLUSTER)
                .and(MatcherBuilder.not(MatcherBuilder.isAbstract()));
        this.interceptors = new InterceptorDefinition[]{
                new InterceptorDefinitionAdapter(
                        MatcherBuilder.named(METHOD_SELECT)
                                .and(MatcherBuilder.arguments(ARGUMENT_SELECT)),
                        () -> new LoadBalanceInterceptor(context)
                )
        };
    }}

攔截器里面調(diào)用上下文的路由方法

public class LoadBalanceInterceptor extends InterceptorAdaptor {

    // ......

    @Override
    public void onEnter(ExecutableContext ctx) {
        MethodContext mc = (MethodContext) ctx;
        Object[] arguments = ctx.getArguments();
        List> invokers = (List>) arguments[2];
        List> invoked = (List>) arguments[3];
        DubboOutboundRequest request = new DubboOutboundRequest((Invocation) arguments[1]);
        DubboOutboundInvocation invocation = new DubboOutboundInvocation(request, context);
        DubboCluster3 cluster = clusters.computeIfAbsent((AbstractClusterInvoker) ctx.getTarget(), DubboCluster3::new);
        try {
            List> instances = invokers.stream().map(DubboEndpoint::of).collect(Collectors.toList());
            if (invoked != null) {
                invoked.forEach(p -> request.addAttempt(new DubboEndpoint(p).getId()));
            }
            List endpoints = context.route(invocation, instances);
            if (endpoints != null && !endpoints.isEmpty()) {
                mc.setResult(((DubboEndpoint) endpoints.get(0)).getInvoker());
            } else {
                mc.setThrowable(cluster.createNoProviderException(request));
            }
        } catch (RejectException e) {
            mc.setThrowable(cluster.createRejectException(e, request));
        }
        mc.setSkip(true);
    }}

如果開啟了微服務(wù)治理,則設(shè)計(jì)到重試,需要對(duì)集群調(diào)用進(jìn)行攔截

@Injectable@Extension(value = "ClusterDefinition_v2.7")@ConditionalOnProperty(name = GovernanceConfig.CONFIG_FLOW_CONTROL_ENABLED, matchIfMissing = true)@ConditionalOnProperty(name = GovernanceConfig.CONFIG_LIVE_DUBBO_ENABLED, matchIfMissing = true)@ConditionalOnClass(ClusterDefinition.TYPE_ABSTRACT_CLUSTER)@ConditionalOnClass(ClassLoaderFilterDefinition.TYPE_CONSUMER_CLASSLOADER_FILTER)public class ClusterDefinition extends PluginDefinitionAdapter {

    protected static final String TYPE_ABSTRACT_CLUSTER = "org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker";

    private static final String METHOD_DO_INVOKE = "doInvoke";

    private static final String[] ARGUMENT_DO_INVOKE = new String[]{
            "org.apache.dubbo.rpc.Invocation",
            "java.util.List",
            "org.apache.dubbo.rpc.cluster.LoadBalance"
    };

    // ......

    public ClusterDefinition() {
        this.matcher = () -> MatcherBuilder.isSubTypeOf(TYPE_ABSTRACT_CLUSTER)
                .and(MatcherBuilder.not(MatcherBuilder.isAbstract()));
        this.interceptors = new InterceptorDefinition[]{
                new InterceptorDefinitionAdapter(
                        MatcherBuilder.named(METHOD_DO_INVOKE)
                                .and(MatcherBuilder.arguments(ARGUMENT_DO_INVOKE)),
                        () -> new ClusterInterceptor(context)
                )
        };
    }}

攔截器里面構(gòu)造集群對(duì)象進(jìn)行同步或異步調(diào)用

public class ClusterInterceptor extends InterceptorAdaptor {

    // ......
    
    @Override
    public void onEnter(ExecutableContext ctx) {
        MethodContext mc = (MethodContext) ctx;
        Object[] arguments = ctx.getArguments();
        DubboCluster3 cluster = clusters.computeIfAbsent((AbstractClusterInvoker) ctx.getTarget(), DubboCluster3::new);
        List> invokers = (List>) arguments[1];
        List> instances = invokers.stream().map(DubboEndpoint::of).collect(Collectors.toList());
        DubboOutboundRequest request = new DubboOutboundRequest((Invocation) arguments[0]);
        DubboOutboundInvocation invocation = new DubboOutboundInvocation(request, context);
        DubboOutboundResponse response = cluster.request(context, invocation, instances);
        if (response.getThrowable() != null) {
            mc.setThrowable(response.getThrowable());
        } else {
            mc.setResult(response.getResponse());
        }
        mc.setSkip(true);
    }}

同樣,出流量攔截也是采用了責(zé)任鏈模式設(shè)計(jì)了OutboundFilterChain,用戶可以根據(jù)自己的需求擴(kuò)展實(shí)現(xiàn)OutboundFilter,目前針對(duì)已支持功能內(nèi)置了部分實(shí)現(xiàn),如下所示:

wKgaombO5cKAaB4ZAAC2q5t0g70354.jpg

過(guò)濾器 名稱 說(shuō)明
StickyFilter 粘連過(guò)濾器 根據(jù)服務(wù)的粘連策略進(jìn)行過(guò)濾
LocalhostFilter 本機(jī)過(guò)濾器 本地開發(fā)調(diào)試插件
HealthyFilter 健康過(guò)濾器 根據(jù)后端實(shí)例的健康狀態(tài)進(jìn)行過(guò)濾
VirtualFilter 虛擬節(jié)點(diǎn)過(guò)濾器 復(fù)制出指定數(shù)量的節(jié)點(diǎn),用于開發(fā)測(cè)試
UnitRouteFilter 單元路由過(guò)濾器 根據(jù)多活路由規(guī)則及微服務(wù)的多活策略,根據(jù)請(qǐng)求的目標(biāo)單元進(jìn)行過(guò)濾
TagRouteFilter 標(biāo)簽路由過(guò)濾器 根據(jù)服務(wù)配置的標(biāo)簽路由策略進(jìn)行過(guò)濾
LaneFilter 泳道過(guò)濾器 根據(jù)泳道策略進(jìn)行過(guò)濾
CellRouteFilter 分區(qū)路由過(guò)濾器 根據(jù)多活路由規(guī)則及微服務(wù)的多活策略,根據(jù)請(qǐng)求的目標(biāo)分區(qū)進(jìn)行過(guò)濾
RetryFilter 重試過(guò)濾器 嘗試過(guò)濾掉已經(jīng)重試過(guò)的節(jié)點(diǎn)
LoadBalanceFilter 負(fù)載均衡過(guò)濾器 根據(jù)服務(wù)配置的負(fù)載均衡策略進(jìn)行路由

6. 部署實(shí)踐

6.1 基于Kubernates實(shí)踐場(chǎng)景

我們開源的另一個(gè)項(xiàng)目joylive-injector是針對(duì)K8s場(chǎng)景打造的自動(dòng)注入組件。joylive-injector是基于kubernetes的動(dòng)態(tài)準(zhǔn)入控制webhook,它可以用于修改kubernete資源。它會(huì)監(jiān)視工作負(fù)載(如deployments)的CREATE、UPDATE、DELETE事件和pods的CREATE事件,并為POD添加initContainer、默認(rèn)增加環(huán)境變量JAVA_TOOL_OPTIONS、掛載configmap、修改主容器的卷裝載等操作。目前已支持的特性如下:

支持自動(dòng)將joylive-agent注入應(yīng)用的Pod。

支持多版本joylive-agent與對(duì)應(yīng)配置管理。

支持注入指定版本joylive-agent及對(duì)應(yīng)配置。

所以,針對(duì)采用K8s進(jìn)行應(yīng)用發(fā)布管理的場(chǎng)景中,集成joylive-agent變得非常簡(jiǎn)單,在安裝joylive-injector組件后,只需要在對(duì)應(yīng)的deployment文件中加入標(biāo)簽x-live-enabled: "true"即可,如下所示:

apiVersion: apps/v1kind: Deploymentmetadata:
  labels:
    app: joylive-demo-springcloud2021-provider    x-live-enabled: "true"
  name: joylive-demo-springcloud2021-providerspec:
  replicas: 1
  selector:
    matchLabels:
      app: joylive-demo-springcloud2021-provider  template:
    metadata:
      labels:
        app: joylive-demo-springcloud2021-provider        x-live-enabled: "true"
    spec:
      containers:
        - env:
            - name: CONFIG_LIVE_SPACE_API_TYPE              value: multilive            - name: CONFIG_LIVE_SPACE_API_URL              value: http://api.live.local/v1            - name: CONFIG_LIVE_SPACE_API_HEADERS              value: pin=demo            - name: CONFIG_SERVICE_API_TYPE              value: jmsf            - name: CONFIG_SERVICE_API_URL              value: http://api.jmsf.local/v1            - name: LIVE_LOG_LEVEL              value: info            - name: CONFIG_LANE_ENABLED              value: "false"
            - name: NACOS_ADDR              value: nacos-server.nacos.svc:8848
            - name: NACOS_USERNAME              value: nacos            - name: NACOS_PASSWORD              value: nacos            - name: APPLICATION_NAME              value: springcloud2021-provider            - name: APPLICATION_SERVICE_NAME              value: service-provider            - name: APPLICATION_SERVICE_NAMESPACE              value: default            - name: SERVER_PORT              value: "18081"
            - name: APPLICATION_LOCATION_REGION              value: region1            - name: APPLICATION_LOCATION_ZONE              value: zone1            - name: APPLICATION_LOCATION_LIVESPACE_ID              value: v4bEh4kd6Jvu5QBX09qYq-qlbcs            - name: APPLICATION_LOCATION_UNIT              value: unit1            - name: APPLICATION_LOCATION_CELL              value: cell1            - name: APPLICATION_LOCATION_LANESPACE_ID              value: "1"
            - name: APPLICATION_LOCATION_LANE              value: production          image: hub-vpc.jdcloud.com/jmsf/joylive-demo-springcloud2021-provider:1.1.0-5aab82b3-AMD64          imagePullPolicy: Always          name: joylive-demo-springcloud2021-provider          ports:
            - containerPort: 18081
              name: http              protocol: TCP          resources:
            requests:
              cpu: "4"
              memory: "8Gi"
            limits:
              cpu: "4"
              memory: "8Gi"
          terminationMessagePath: /dev/termination-log          terminationMessagePolicy: File      dnsPolicy: ClusterFirst      restartPolicy: Always      schedulerName: default-scheduler      securityContext: { }
      terminationGracePeriodSeconds: 30

啟動(dòng)后Pod如下圖所示即代表注入成功,隨后觀察應(yīng)用日志及功能測(cè)試即可。

wKgZombO5cOADXqWAAA39I2jXXo703.jpg

我們有更高的目標(biāo)和方向,希望更多有志于打造開源優(yōu)品的朋友加入進(jìn)來(lái),一起為開源事業(yè)貢獻(xiàn)自己的光與熱。

下一篇:KubeCon China 2024全球大會(huì)在香港舉行,京東云受邀參加探討云原生、開源及 AI

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • SDK
    SDK
    +關(guān)注

    關(guān)注

    3

    文章

    1006

    瀏覽量

    45412
  • 微服務(wù)
    +關(guān)注

    關(guān)注

    0

    文章

    126

    瀏覽量

    7303
  • 微服務(wù)架構(gòu)

    關(guān)注

    0

    文章

    23

    瀏覽量

    2943
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    微服務(wù)架構(gòu)和CQRS架構(gòu)基本概念介紹

    微服務(wù)架構(gòu)現(xiàn)在很熱,到處可以看到各大互聯(lián)網(wǎng)公司的微服務(wù)實(shí)踐的分享總結(jié)。但是,我今天的分享和微服務(wù)沒(méi)有關(guān)系,希望可以帶給大家一些新的東西。如果一定要說(shuō)微服務(wù)和CQRS架構(gòu)的關(guān)系,那我覺(jué)得
    發(fā)表于 05-22 09:03

    微服務(wù)網(wǎng)關(guān)gateway的相關(guān)資料推薦

    目錄微服務(wù)網(wǎng)關(guān) gateway 概述[路由器網(wǎng)關(guān) Zuul 概述]嵌入式 Zuul 反向代理微服務(wù)網(wǎng)關(guān) gateway 概述1、想象一下一個(gè)購(gòu)物應(yīng)用程序的產(chǎn)品詳情頁(yè)面展示了指定商品的信息:2、若是
    發(fā)表于 12-23 08:19

    什么是微服務(wù)_微服務(wù)知識(shí)點(diǎn)全面總結(jié)

    微服務(wù)是一個(gè)新興的軟件架構(gòu),就是把一個(gè)大型的單個(gè)應(yīng)用程序和服務(wù)拆分為數(shù)十個(gè)的支持微服務(wù)。一個(gè)微服務(wù)的策略可以讓工作變得更為簡(jiǎn)便,它可擴(kuò)展單個(gè)組件而不是整個(gè)的應(yīng)用程序堆棧,從而滿足
    的頭像 發(fā)表于 02-07 16:06 ?1.5w次閱讀

    微服務(wù)架構(gòu)微才合適

    大家也都認(rèn)可,隨著數(shù)據(jù)量、流量、業(yè)務(wù)復(fù)雜度的提升,服務(wù)化架構(gòu)是架構(gòu)演進(jìn)中的必由之路,今天要討論的話題是:微服務(wù)架構(gòu)“微”才合適?
    的頭像 發(fā)表于 02-07 17:14 ?3268次閱讀
    <b class='flag-5'>微服務(wù)</b>架構(gòu)<b class='flag-5'>多</b>微才合適

    java微服務(wù)架構(gòu)有哪些

    本文首先簡(jiǎn)單介紹了微服務(wù)的概念以及使用微服務(wù)所能帶來(lái)的優(yōu)勢(shì),然后結(jié)合實(shí)例介紹了幾個(gè)常見的Java微服務(wù)框架。微服務(wù)在開發(fā)領(lǐng)域的應(yīng)用越來(lái)越廣泛,因?yàn)殚_發(fā)人員致力于創(chuàng)建更大、更復(fù)雜的應(yīng)用程
    的頭像 發(fā)表于 02-09 10:34 ?8552次閱讀
    java<b class='flag-5'>微服務(wù)</b>架構(gòu)有哪些

    什么是微服務(wù)和容器?微服務(wù)和容器的作用是什么

    微服務(wù)是將應(yīng)用程序拆分為多個(gè)服務(wù)的一種架構(gòu)類型,這些服務(wù)具備構(gòu)成整個(gè)應(yīng)用程序的細(xì)粒度功能。每個(gè)微服務(wù)將具備針對(duì)您的應(yīng)用程序的不同邏輯功能。與應(yīng)用程序的所有組件和功能都在單個(gè)實(shí)例中的單體
    的頭像 發(fā)表于 01-13 10:54 ?3.2w次閱讀
    什么是<b class='flag-5'>微服務(wù)</b>和容器?<b class='flag-5'>微服務(wù)</b>和容器的作用是什么

    Dubbo 如何成為連接異構(gòu)微服務(wù)體系的最佳服務(wù)開發(fā)框架

    Dubbo 也是一款服務(wù)治理框架,它為分布式部署的微服務(wù)提供了服務(wù)發(fā)現(xiàn)、流量調(diào)度等服務(wù)
    發(fā)表于 03-12 17:04 ?895次閱讀
    Dubbo 如何成為連接異構(gòu)<b class='flag-5'>微服務(wù)</b>體系的最佳<b class='flag-5'>服務(wù)</b>開發(fā)框架

    微服務(wù)架構(gòu)有哪些_微服務(wù)架構(gòu)設(shè)計(jì)模式

    小伙伴們知道常用的微服務(wù)架構(gòu)框架有哪些嗎?上回我們介紹了一些常用的微服務(wù)架構(gòu)設(shè)計(jì)模式,這次我們就來(lái)了解一下一些常用的微服務(wù)架構(gòu)框架吧。
    的頭像 發(fā)表于 05-17 17:06 ?2.9w次閱讀
    <b class='flag-5'>微服務(wù)</b>架構(gòu)有哪些_<b class='flag-5'>微服務(wù)</b>架構(gòu)設(shè)計(jì)模式

    微服務(wù)架構(gòu)技術(shù)棧選型解讀

    一、微服務(wù)治理中心框架 Apache Dubbo分布式RPC框架 Spring Cloud Alibaba分布式應(yīng)用服務(wù)開發(fā)一站式解決方案 Spring Cloud微服務(wù)開發(fā)和
    的頭像 發(fā)表于 12-29 14:35 ?1469次閱讀

    華為云服務(wù)治理?| 微服務(wù)常見故障模式

    服務(wù)治理定義 服務(wù)治理通常是指通過(guò)限流、熔斷等手段,保障微服務(wù)的可靠運(yùn)行,即運(yùn)行時(shí)治理。更加寬泛
    的頭像 發(fā)表于 01-18 17:44 ?675次閱讀

    華為云服務(wù)治理 | 服務(wù)治理的一般性原則

    華為云 服務(wù)治理 | ** 服務(wù)治理的一般性原則** 服務(wù)治理通常是指通過(guò)限流、熔斷等手段,保障
    的頭像 發(fā)表于 01-18 18:19 ?445次閱讀

    華為云服務(wù)治理—隔離倉(cāng)的作用

    服務(wù)治理通常是指通過(guò)限流、熔斷等手段,保障微服務(wù)的可靠運(yùn)行,即運(yùn)行時(shí)治理。更加寬泛的服務(wù)治理還包
    的頭像 發(fā)表于 01-18 19:41 ?540次閱讀

    分布式政企應(yīng)用如何快速實(shí)現(xiàn)云原生的微服務(wù)架構(gòu)改造

    在以往的文章《云原生微服務(wù)治理技術(shù)朝無(wú)代理架構(gòu)的演進(jìn)之路》中,我們介紹了幾種微服務(wù)架構(gòu)模式,如下圖所示。
    的頭像 發(fā)表于 04-12 11:04 ?494次閱讀
    分布式政企應(yīng)用如何快速實(shí)現(xiàn)云原生的<b class='flag-5'>微服務(wù)</b>架構(gòu)改造

    基于Traefik自研的微服務(wù)網(wǎng)關(guān)

    數(shù)據(jù)平面主要功能是接入用戶的HTTP請(qǐng)求和微服務(wù)被拆分后的聚合。使用微服務(wù)網(wǎng)關(guān)統(tǒng)一對(duì)外暴露后端服務(wù)的API和契約,路由和過(guò)濾功能正是網(wǎng)關(guān)的核心能力模塊。另外,微服務(wù)網(wǎng)關(guān)可以實(shí)現(xiàn)攔截機(jī)制
    的頭像 發(fā)表于 04-16 11:08 ?2414次閱讀

    設(shè)計(jì)微服務(wù)架構(gòu)的原則

    微服務(wù)是一種軟件架構(gòu)策略,有利于改善整體性能和可擴(kuò)展性。你可能會(huì)想,我的團(tuán)隊(duì)需不需要采用微服務(wù),設(shè)計(jì)微服務(wù)架構(gòu)有哪些原則?本文會(huì)給你一些靈感。文章速覽:微服務(wù)設(shè)計(jì)的要素
    的頭像 發(fā)表于 11-26 08:05 ?453次閱讀
    設(shè)計(jì)<b class='flag-5'>微服務(wù)</b>架構(gòu)的原則