RM新时代网站-首页

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

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

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

京東廣告投放平臺整潔架構(gòu)演進之路

京東云 ? 來源:jf_75140285 ? 作者:jf_75140285 ? 2024-09-18 10:26 ? 次閱讀

作者:京東零售 趙嘉鐸

前言

從去年開始京東廣告投放系統(tǒng)做了一次以領(lǐng)域驅(qū)動設(shè)計為思想內(nèi)核的架構(gòu)升級,在深入理解DDD思想的同時,我們基于廣告投放業(yè)務(wù)的本質(zhì)特征大膽地融入了自己的理解和改造。新架構(gòu)是從設(shè)計思想到落地框架都進行了徹底的革新,涉及內(nèi)容比較多,因此我們希望通過一系列文章循序漸進地闡述本次架構(gòu)升級的始末。新架構(gòu)并不是一日而成的,而是經(jīng)過了多次架構(gòu)升級的演進,因此我們將本文作為該系列的第一篇文章,先讓大家通過廣告投放平臺的架構(gòu)演進歷程來了解新架構(gòu)的設(shè)計初衷。

如前言所述,本文主要聚焦于廣告投放系統(tǒng)歷代代碼架構(gòu)的演進歷程,我們也不希望本文的篇幅過于冗長,因此對新架構(gòu)中具體框架及API的說明淺嘗輒止,我們會在本系列接下來的數(shù)篇文章中逐步給出愈加具象的描述。

什么是好的代碼架構(gòu)

大家都清楚在當(dāng)前的工作中我們所面臨的主要矛盾是“越來越多的多場景化復(fù)雜業(yè)務(wù)需求與有限的研發(fā)人力之間的矛盾”。而要解決這一矛盾,就要求我們的系統(tǒng)能做到:設(shè)計易拓展、代碼易復(fù)用、邏輯易傳承、運行更穩(wěn)定。這看起來像是一句空喊的口號,但其實每一個特性都有具體的要求:

?設(shè)計易拓展

一個好的架構(gòu)應(yīng)該能夠?qū)崿F(xiàn)業(yè)務(wù)與技術(shù)組件的分離,使設(shè)計者能夠?qū)W⒂跇I(yè)務(wù)流程,以填空的方式直接套用開箱即用的組件、框架和解決方案,不必進行大量的重復(fù)設(shè)計;另外好的架構(gòu)也能夠引導(dǎo)設(shè)計者完成最小子問題的正交分解,將設(shè)計者從錯綜復(fù)雜的上層業(yè)務(wù)邏輯中拯救出來,逐個擊破,降低需求的復(fù)雜度和理解成本。

?代碼易復(fù)用

一個好的架構(gòu)應(yīng)該有良好的分層,強調(diào)正交子模塊的拆分與封裝,同層原子模塊之間避免互相依賴和耦合,讓上層系統(tǒng)能夠輕松實現(xiàn)底層業(yè)務(wù)邏輯的組合復(fù)用,以

?的實現(xiàn)復(fù)雜度支撐

?業(yè)務(wù)復(fù)雜度;另外我們的業(yè)務(wù)邏輯是建立在數(shù)據(jù)之上的,一個封裝良好的代碼架構(gòu)在實現(xiàn)業(yè)務(wù)邏輯復(fù)用的同時應(yīng)該有健全的數(shù)據(jù)模型維護和共享機制,避免同一個數(shù)據(jù)對象的重復(fù)查詢,并能夠輕松通過批量操作降低系統(tǒng)的I/O負載。

?邏輯易傳承

我們歷史上多次嘗試通過維護文檔的方式來建立業(yè)務(wù)知識庫,但都以失敗告終了。在這個過程中我們意識到業(yè)務(wù)功能都是由我們的代碼承接的,它天然具備業(yè)務(wù)知識庫的功能。因此一個好的代碼架構(gòu)不僅能夠?qū)崿F(xiàn)業(yè)務(wù)功能,而且要承擔(dān)起傳遞業(yè)務(wù)知識的職責(zé):當(dāng)有新同學(xué)加入時,代碼能夠以最直接的方式幫助他快速建立起對整個業(yè)務(wù)的宏觀認知,而進行具體的需求開發(fā)時,又能夠按圖索驥,快速定位改動點并深入了解其業(yè)務(wù)細節(jié)。

?運行更穩(wěn)定

一個好的代碼架構(gòu)在面對多場景化的需求時,可以做到場景隔離,避免不同場景的特有邏輯之間互相耦合干擾,出現(xiàn)一個場景需求上線后影響其他業(yè)務(wù)場景的問題;除此之外,一個好的架構(gòu)應(yīng)該通過設(shè)計良好的框架和標(biāo)準模板在有益的程度上對開發(fā)者的編碼行為進行約束,把規(guī)范框架化,而不是過多的依賴人置和code review來實現(xiàn)規(guī)范統(tǒng)一。

架構(gòu)演進之路

在上一章節(jié)列舉出來的特質(zhì)也是評判一個架構(gòu)優(yōu)劣的標(biāo)準,而我們新的架構(gòu)方案也正是在一次次為了實現(xiàn)這些目標(biāo)而采取的摸索中逐漸成型的。在接下來的幾個章節(jié)中,我們將從最早期的代碼架構(gòu)開始,逐代剖析架構(gòu)演進的歷程,通過這種方式讓大家了解每一次改進背后的設(shè)計動機和思路,從而更好的理解新架構(gòu)的設(shè)計思想,也為大家推動架構(gòu)向下一代演進打好基礎(chǔ)。

第一代:沒有架構(gòu)的架構(gòu)

最開始的時候我們的架構(gòu)如下圖所示,這也是我們目前最常見一種代碼架構(gòu)??梢钥闯鏊奶攸c就是“簡單”,沒有過多的封裝和設(shè)計,平鋪直敘,數(shù)據(jù)查詢和業(yè)務(wù)邏輯處理互相交織,是面向數(shù)據(jù)庫編程的典型案例。這種架構(gòu)在早期場景單一、需求簡單的階段可以快速實現(xiàn)功能,沒有多余的設(shè)計成本,但是隨著業(yè)務(wù)的發(fā)展,系統(tǒng)服務(wù)的場景越來越多,這套架構(gòu)就變得越來越不簡單了。

wKgZombqOmGAA3BTAAHmSr1RSj4030.png

??

問題主要體現(xiàn)在兩個方面:

1.由于大家習(xí)慣“打補丁”式的開發(fā),來了一個業(yè)務(wù)需求就在現(xiàn)有的流程中增加一個if...else分支,然后直接在新分支內(nèi)實現(xiàn)業(yè)務(wù)邏輯。當(dāng)業(yè)務(wù)流程積攢的足夠冗長時,就很容易忽視前置流程已經(jīng)查詢好的數(shù)據(jù)對象,造成數(shù)據(jù)重復(fù)查詢。同時為了實現(xiàn)邏輯的復(fù)用,我們開始把一些常用邏輯封裝為單獨的方法,然后在上層業(yè)務(wù)流程中直接調(diào)用,然而我們在封裝底層方法往往會把數(shù)據(jù)的獲取邏輯封裝下來,這進一步加劇了數(shù)據(jù)重復(fù)查詢的問題,在有循環(huán)調(diào)用的場景中這個問題會更加突出。另外這種邏輯的復(fù)用方式還會造成數(shù)據(jù)庫訪問碎片化,我們很難利用批量操作的優(yōu)勢優(yōu)化系統(tǒng)性能。在最近剛結(jié)束的大促中,我們前期暴露的幾個性能問題基本都是這中模式導(dǎo)致的。

2.除了性能問題之外,由于不同業(yè)務(wù)場景的邏輯互相交織,代碼分支判斷邏輯缺少統(tǒng)一的規(guī)劃,if分支層層嵌套,導(dǎo)致我們的代碼邏輯圈復(fù)雜度不斷飆升,本來應(yīng)該通用的邏輯對不同場景的適配性越來越低。漸漸的,我們發(fā)現(xiàn)新增需求的開發(fā)越來越“不簡單”了:在試圖復(fù)用一段看起來相似的代碼邏輯時會有很多糾結(jié)和不盡人意的地方,對代碼執(zhí)行流程的認知也不似以往那么清晰了,為了防止對舊的業(yè)務(wù)流程造成影響,我們開始增加更多的if分支,這反過來進一步加劇了情況的惡化,于是我們的代碼中充斥著重復(fù)代碼、多達5、6層的嵌套...

為了緩解舊架構(gòu)中的這些問題,我們引入了上下文機制,嘗試將數(shù)據(jù)的查詢邏輯與業(yè)務(wù)流程分離開來,由此引出了第二代基于上下文機制的代碼架構(gòu)。

第二代:略有改善的上下文機制

上下文主要是為了解決數(shù)據(jù)重復(fù)查詢問題引入的,思路特別樸素,就是把一個完整業(yè)務(wù)流程中要用到的全部數(shù)據(jù)提前在方法一開始就查詢好,并做好校驗。查詢出來的數(shù)據(jù)對象保存到一個上下文對象中,這個上下文對象會貫穿整個業(yè)務(wù)流程,業(yè)務(wù)邏輯中需要用得到底層數(shù)據(jù)實體的時候統(tǒng)一從上下文對象中獲取

wKgaombqOmKATwO4AAEgQnD9_kI102.png

??

所有的數(shù)據(jù)集中在“上下文構(gòu)造”步驟中查詢,整個業(yè)務(wù)流程運行在上下文對象中

通過上下文的引入,我們基本上解決了數(shù)據(jù)重復(fù)查詢的問題,另外我們數(shù)據(jù)的提前集中查詢也有助于啟發(fā)我們主動通過數(shù)據(jù)庫批量查詢進一步提升系統(tǒng)性能。而且上下文構(gòu)造的過程其實也是數(shù)據(jù)校驗的過程,通過上下文的提前構(gòu)建,我們在一定程度上實現(xiàn)了預(yù)校驗的邏輯,從而可以提前發(fā)現(xiàn)異常數(shù)據(jù),避免寫入臟數(shù)據(jù)和不必要的數(shù)據(jù)回滾操作。

上下文的引入其實并不算什么架構(gòu)上的改進,它主要是解決了數(shù)據(jù)對象重復(fù)查詢的問題,但是也引入了一些新的痛點,首先就是我們的數(shù)據(jù)模型中數(shù)據(jù)對象往往比較多且關(guān)系復(fù)雜,這導(dǎo)致我們的上下文構(gòu)造邏輯十分冗長。而且同一個業(yè)務(wù)域內(nèi)不同的接口使用的上下文對象中屬性有較大重疊,但是也有各自的差異,因此這些上下文對象的構(gòu)造邏輯又開始出現(xiàn)大量的重復(fù)編碼或者混亂的封裝。比如詢量單的新建接口與修改接口對應(yīng)的上下文中80%的屬性是相同的,這些屬性的查詢和關(guān)聯(lián)邏輯造成了大量的重復(fù)編碼。除了重復(fù)編碼問題之外,上下文機制也并沒有從根本上解決多場景下業(yè)務(wù)流程差異復(fù)雜度高的問題。

第三代:數(shù)據(jù)模型與業(yè)務(wù)模型的分離

在第二代架構(gòu)中我們雖然將數(shù)據(jù)對象的查詢集中到了上下文構(gòu)造步驟中執(zhí)行,但是上下文對象的定義是和接口方法綁定的。對外暴露多少服務(wù)我們就會定義多少上下文對象,甚至不同的場景也會有各自的上下文構(gòu)造邏輯,此時系統(tǒng)的數(shù)據(jù)模型依然隱藏在了具體的業(yè)務(wù)邏輯中。

在一次次的改進嘗試中,我們逐漸意識到多場景化的業(yè)務(wù)特性賦予我們一個動態(tài)的業(yè)務(wù)模型(或者說業(yè)務(wù)規(guī)則集),但是我們的數(shù)據(jù)模型卻是靜態(tài)的,數(shù)據(jù)模型的多場景化程度遠小于業(yè)務(wù)規(guī)則的多場景化程度,即:同一個功能模塊在不同場景下的業(yè)務(wù)規(guī)則存在差異,但卻始終在操作同一套數(shù)據(jù)模型。有些同學(xué)可能會對這一結(jié)論產(chǎn)生質(zhì)疑:在不同的場景下我們對數(shù)據(jù)對象的構(gòu)造也是不同的,比如只有快車的單元下才會有關(guān)鍵詞,京X的單元上綁定的是應(yīng)用集,而直投單元上綁定的是流量包等等,這些例子是不是都說明我們的數(shù)據(jù)模型也在隨業(yè)務(wù)規(guī)則一起動態(tài)變化著呢?對于這個問題我們需要“細品”一下:“數(shù)據(jù)對象屬性值的設(shè)置和校驗”到底是屬于業(yè)務(wù)模型的范疇還是數(shù)據(jù)模型的范疇?其實我們所說的數(shù)據(jù)模型指的是實體及實體之間的關(guān)系, 不論某個產(chǎn)品線或計劃類型是否會去設(shè)置某個子屬性的值,只要我們的數(shù)據(jù)模型完成了定義,那么在任何場景下數(shù)據(jù)模型的中實體的定義及實體之間的關(guān)系都是不變的,實體只要定義出來,它會一直在那,只是某些場景下其屬性值為null而已。而實體屬性值的設(shè)置邏輯則是典型的業(yè)務(wù)模型的范疇。

在明確了“多場景化的動態(tài)業(yè)務(wù)模型是建立在一個相對靜態(tài)的數(shù)據(jù)模型之上”這一本質(zhì)之后,為了解決上下文對象構(gòu)造復(fù)雜度高及重復(fù)編碼的問題,我們需要做的就是數(shù)據(jù)模型的分離和下沉,為此我們引入了領(lǐng)域驅(qū)動設(shè)計思想中的“聚合”概念。在這篇文章里我們不需要教條地引用DDD中關(guān)于聚合的定義,它的含義可以通俗的理解為:一組關(guān)聯(lián)密切且關(guān)系明確的實體或值對象的集合,一個聚合通常會支撐著一個功能極其內(nèi)聚的上層業(yè)務(wù)模塊。一個聚合中會定義唯一個聚合根對象,聚合根是整個聚合中實體操作的中心,聚合中的全部實體都可以通過聚合根直接或間接的訪問到。聚合根通常并不難確定,比如計劃聚合的聚合根自然就是Campaign實體,我們可以直接通過Campaign聚合根對象直接引用到計劃下的預(yù)算、投放時段等子實體信息

將聚合的概念落地到代碼架構(gòu)中我們需要做以下升級:

1.根據(jù)業(yè)務(wù)流程設(shè)計合理的數(shù)據(jù)模型,需要注意的是數(shù)據(jù)模型中的實體并不一定要與底層的庫表一一對應(yīng),而是應(yīng)該從業(yè)務(wù)本質(zhì)出發(fā)完成實體劃分和定義,另外在模型中也需要體現(xiàn)實體之間的關(guān)聯(lián)關(guān)系。

2.在業(yè)務(wù)流程和底層數(shù)據(jù)庫之間增加一個聚合層,在這一層中將第一步設(shè)計的數(shù)據(jù)模型定義為Java對象,其中實體之間的關(guān)系則轉(zhuǎn)化為類與屬性的關(guān)系。比如AdGroup領(lǐng)域?qū)ο髢?nèi)屬性除了體現(xiàn)ad_group表中定義的字段之外,也定義了單元下的人群、流量包、創(chuàng)意列表等子實體對應(yīng)的屬性。

3.上層的業(yè)務(wù)流程對聚合中實體的訪問和修改都是通過聚合根實現(xiàn)的,而要想獲取聚合根則必須通過聚合層暴露出來的Repository接口。

第三步提到的Repository層接口是完全面向數(shù)據(jù)模型定義的,幾乎與業(yè)務(wù)無關(guān),通常不會為某個特殊的業(yè)務(wù)場景定義專用的數(shù)據(jù)查詢或?qū)懭敕椒?,它定義的都是通用的數(shù)據(jù)訪問接口,讓上層業(yè)務(wù)以聲明式的方法獲取所需的聚合根對象(或集合)。Repository的將數(shù)據(jù)對象的查詢和實體關(guān)系的組裝邏輯屏蔽在其接口實現(xiàn)中,上層業(yè)務(wù)不需要再次執(zhí)行聚合根下子實體對象的查詢和關(guān)聯(lián)邏輯。

?

wKgZombqOmSAQDujAAD_ngRB9LU016.png

??

引入聚合后上下文的構(gòu)造和數(shù)據(jù)的寫入流程得以極大地簡化

?

從上圖可以看出,由于上下文中的很多數(shù)據(jù)對象都被轉(zhuǎn)移到了聚合中,之前繁瑣的數(shù)據(jù)查詢和關(guān)聯(lián)邏輯被分離下沉到了Repository的實現(xiàn)中,業(yè)務(wù)模型中不同的服務(wù)接口可以直接復(fù)用Repository中沉淀的數(shù)據(jù)查詢和組裝邏輯,上下文構(gòu)造得以極大的精簡,重復(fù)編碼問題也得到了根本性的解決,體現(xiàn)了我們架構(gòu)目標(biāo)中“代碼易復(fù)用”的要求。

除了更加靈活和優(yōu)雅的復(fù)用數(shù)據(jù)查詢和組裝邏輯之外,聚合的引入讓我們實現(xiàn)了數(shù)據(jù)模型和業(yè)務(wù)模型的分離,聚合層幾乎與業(yè)務(wù)流程無關(guān),直接體現(xiàn)數(shù)據(jù)模型的完整全貌。當(dāng)有新同學(xué)加入的時候,可以通過閱讀聚合層代碼獲取最全、最準確的數(shù)據(jù)模型定義,不再需要從代碼中四處搜集對象關(guān)聯(lián)關(guān)系的蛛絲馬跡,這體現(xiàn)了我們架構(gòu)目標(biāo)中“邏輯易傳承”的要求。

wKgaombqOmWAODoAAANJB1tT8YQ274.png

??

RE降級后的補數(shù)邏輯一直是一件令人頭痛的事情,聚合的引入可以極大地簡化這一流程

本文主要探討的是我們引入聚合的動機,關(guān)于數(shù)據(jù)模型的設(shè)計、Repository接口的實現(xiàn)和使用相關(guān)的實戰(zhàn)內(nèi)容只是點到為止,關(guān)于這部分的詳細內(nèi)容屬于多體系架構(gòu)中的數(shù)據(jù)模型管理體系,我們將在該體系的設(shè)計中進行深入的探討。 其實就我個人的實踐經(jīng)驗而言,在實現(xiàn)架構(gòu)升級所作出的眾多嘗試中,聚合的引入是給我?guī)硇腋8凶顝姷囊豁椄倪M,但是我始終沒能找到一種合適的表達方式將我之所感無所保留地傳遞給大家,所言之語總是蒼白,或許聚合引入帶來的收益只有讓大家在實踐中去親身感受了。 另外熟悉領(lǐng)域驅(qū)動設(shè)計的同學(xué)可能已經(jīng)從上面的設(shè)計中嗅到了一絲DDD的味道,但是可能又會覺得沒有那么DDD,關(guān)于這個問題限于當(dāng)前陳述上下文的原因還不好直接給予解答,容筆者在這里賣個關(guān)子,在后面的系列文章中我們會詳細闡明這種設(shè)計的細節(jié)和考量。

第四代:領(lǐng)域能力拆分與編排

通過引入聚合我們基本上解決了數(shù)據(jù)查詢邏輯復(fù)用的問題,但是由于多平臺、多維度和多場景化帶來的業(yè)務(wù)復(fù)雜度的問題卻依然存在。而解決這個問題的基本思路其實祖師爺已經(jīng)給我們準備好了,那就是組合復(fù)用原則。

作為一個典型的2B的平臺,我們的業(yè)務(wù)特點就是流程冗長復(fù)雜,一個業(yè)務(wù)流程通常由多個流程節(jié)點組成,比如單元新建流程,可以分為:基礎(chǔ)信息設(shè)置、單元名稱設(shè)置、投放周期設(shè)置、投放位置設(shè)置、定向設(shè)置、出價設(shè)置、關(guān)鍵詞設(shè)置等多個節(jié)點組成。這些節(jié)點再疊加上不同產(chǎn)品線(展位、快車、觸點)、站外不同媒體(頭、騰、百、快、京X)、不同的投放平臺(京準通、流量貨幣化、京易投)以及不同的站點(國內(nèi)、泰國、印尼、出海)等多維度的業(yè)務(wù)場景,就使系統(tǒng)具備了

?業(yè)務(wù)復(fù)雜度,其中

?為不同業(yè)務(wù)細分維度下的場景復(fù)雜度,而組合復(fù)用原則就是專門為解決這一問題而生的。

組合復(fù)用原則強調(diào)復(fù)雜問題的拆分,拆分出來的最小子問題可以互不干擾地進行獨立的迭代。在此基礎(chǔ)上,上層模塊可以通過對最小子問題的組合編排實現(xiàn)一項完整的業(yè)務(wù)功能。由于最小子問題之間彼此正交,我們獨立維護各個最小子問題的編碼復(fù)雜度就可以降級為

??;谠撍枷耄覀冊谛录軜?gòu)中引入了領(lǐng)域能力拆分與編排機制。

領(lǐng)域能力的識別與拆分

在新架構(gòu)中我們會將一個完整的業(yè)務(wù)流程正交分解為多個“能力節(jié)點”。這里所說的“正交分解”是指拆分出來的各個子模塊之間互不干擾,可以獨立進行迭代。舉個例子來說,在早期大家進行能力梳理的時候,有同學(xué)從單元新建流程中拆分出了“出價信息校驗”和“出價設(shè)置”兩個能力節(jié)點,這其實是不合理的。因為出價信息的校驗和出價屬性的設(shè)置并不正交,他們互相依賴,我們應(yīng)該這兩段邏輯合并到一起,抽象為一個“出價設(shè)置”節(jié)點。

能力節(jié)點主要定義了系統(tǒng)中各個原子模塊的功能范圍。一般來說,一個能力節(jié)點通常包含一個能力門面和0到多個能力實例。能力門面并不承接具體的業(yè)務(wù)邏輯,它的作用是對外暴露統(tǒng)一的調(diào)用入口及請求轉(zhuǎn)發(fā),具體的業(yè)務(wù)邏輯則由能力門面下的能力實例承接。比如出價設(shè)置節(jié)點下會按照出價類型劃分為:手動出價、tCPA智能出價、MC智能出價、eCPC智能出價幾個具體的領(lǐng)域能力實例,而在人群定向設(shè)置節(jié)點下則有京選店鋪人群設(shè)置、樂高人群設(shè)置和自定義人群設(shè)置幾個領(lǐng)域能力實例。

能力編排與請求路由

將整個系統(tǒng)劃分為多個獨立的能力節(jié)點之后,接下來就需要通過能力編排將這些能力節(jié)點串聯(lián)到一起組裝成一個完成的服務(wù)。如下圖所示,所謂的能力編排就是將業(yè)務(wù)流程中所需要的原子模塊對應(yīng)的能力節(jié)點串聯(lián)起來,定義好他們之間數(shù)據(jù)傳遞的方式和編排規(guī)則。需要注意的是,能力編排操作的是能力節(jié)點而不是能力實例,在處理服務(wù)請求時,每一個能力節(jié)點負責(zé)將請求路由到正確的領(lǐng)域能力實例中進行處理。之所以這樣設(shè)計是因為我們的業(yè)務(wù)流程相對穩(wěn)定,系統(tǒng)對外提供的服務(wù)流程中業(yè)務(wù)節(jié)點及節(jié)點間的執(zhí)行順序很少會發(fā)生變化,需求迭代往往是對某個能力節(jié)點進行橫向的拓展,也就是對具體的領(lǐng)域能力實例進行增刪或者修改。通過能力節(jié)點的抽象及路由機制的引入,我們將動態(tài)變化著的部分從相對穩(wěn)定的業(yè)務(wù)流程中分離出去,從而保障核心流程的穩(wěn)定性不被頻繁變化著的需求所影響,這一點與我們當(dāng)時做數(shù)據(jù)模型與業(yè)務(wù)模型分離的動機是一致的,本質(zhì)上都是在隔離變化。

wKgZombqOmaASKgBAAKW_rfzHQQ682.png

??

一個能力編排示例(點擊放大查看)

除了能力編排框架之外,能力實例的路由機制也是實現(xiàn)復(fù)雜度降維的關(guān)鍵。如下圖所示,路由機制通過將能力門面及門面下用于承接不同場景下具體業(yè)務(wù)規(guī)則的能力實例打包到一起,同時也將原子業(yè)務(wù)模塊內(nèi)的場景復(fù)雜度封裝屏蔽在了模塊內(nèi)部,使上層的業(yè)務(wù)流程定義只需要關(guān)注一次完整的請求需要使用哪些原子業(yè)務(wù)模塊(也就是能力節(jié)點),而無需關(guān)注這個節(jié)點下具體的能力實例,當(dāng)請求到來時,處理流程流經(jīng)相應(yīng)的能力節(jié)點時,將通過當(dāng)前請求上下文中的參數(shù)自動識別業(yè)務(wù)身份并將請求路由到相應(yīng)的能力實例上進行處理。

wKgaombqOmeAEJ76AADRb5ci8Nw049.png

??

能力編排操作的是能力節(jié)點而不是領(lǐng)域能力實例,這樣可以讓能力實例更靈活的進行橫向拓展(點擊放大查看)

上文提到了能力編排和路由機制都已經(jīng)在新工程中提供了框架化的實現(xiàn),本文主要是為了分享我們架構(gòu)設(shè)計的動機,所以不會介紹這些功能的實現(xiàn)原理和使用方法,對此感興趣的同學(xué)可以觀看能力編排框架專門的視頻教程:https://cf.jd.com/pages/viewpage.action?pageId=954674772?

標(biāo)準的業(yè)務(wù)執(zhí)行模版

在第二、三代架構(gòu)中,系統(tǒng)處理請求時會先執(zhí)行全部參數(shù)的校驗,校驗通過后再將單元新建處理所需的全部數(shù)據(jù)對象查詢出來。在這個過程中可以充分利用批量查詢接口提升系統(tǒng)性能,同時也會對查詢出來的數(shù)據(jù)對象進行校驗,如果存在不合法的數(shù)據(jù)則終止處理流程,如果數(shù)據(jù)對象查詢一切正常,則執(zhí)行后續(xù)的數(shù)據(jù)組裝和處理邏輯,最后批量執(zhí)行數(shù)據(jù)的持久化。盡管會存在上文分析的一些問題,但是這種模式所帶來的收益依然具備十分重要的意義。

然而在新架構(gòu)中我們將原先連貫的業(yè)務(wù)邏輯打散,按照邏輯的內(nèi)聚性將他們重組到一個能力實例中,然后在領(lǐng)域服務(wù)中通過能力編排將這些能力實例組裝成一個完整的業(yè)務(wù)流程。這雖然貫徹了組合復(fù)用的原則,但是如果我們只是簡單地通過順序執(zhí)行多個能力實例來組裝領(lǐng)域服務(wù),那么由于每個能力內(nèi)部又依次執(zhí)行與一小撮業(yè)務(wù)屬性相關(guān)的參數(shù)校驗、依賴數(shù)據(jù)查詢、邏輯處理乃至數(shù)據(jù)持久化操作,從代碼邏輯的執(zhí)行流程上看我們又回退到了“數(shù)據(jù)訪問與邏輯處理互相交織”的第一代架構(gòu)上。除此之外,雖然服務(wù)之間邏輯上互相獨立,但是他們可能會依賴相同的數(shù)據(jù)對象,比如人群包的綁定與預(yù)算調(diào)整兩個能力都會依賴AdGroup對象,如果框架只是簡單地串聯(lián)執(zhí)行這兩個能力,那么必然會造成數(shù)據(jù)的重復(fù)查詢。

為了解決上述問題,我們引入了標(biāo)準的業(yè)務(wù)流程Executor模板,它把業(yè)務(wù)業(yè)務(wù)流程抽象為:參數(shù)校驗、上下文初始化、上下文校驗、業(yè)務(wù)邏輯處理、數(shù)據(jù)持久化、發(fā)布事件幾個標(biāo)準步驟,不論是領(lǐng)域能力的封裝還是領(lǐng)域服務(wù)的實現(xiàn)都必須繼承該模板。標(biāo)準業(yè)務(wù)執(zhí)行模板的引入一方面能夠規(guī)范開發(fā)者的設(shè)計和實現(xiàn),另一方面也將代碼邏輯的串聯(lián)執(zhí)行權(quán)從開發(fā)者手中轉(zhuǎn)移到了能力編排框架中,讓框架能夠?qū)崿F(xiàn)邏輯的自動重組和執(zhí)行,而開發(fā)者專注于業(yè)務(wù)邏輯并進行填空式開發(fā)。而框架在獲取到了代碼邏輯的串聯(lián)執(zhí)行權(quán)之后就可以在領(lǐng)域服務(wù)的每個標(biāo)準步驟中按照能力編排執(zhí)行圖組裝調(diào)用的各個能力實例中相應(yīng)標(biāo)準步驟,從而將打散到不同能力實例中的業(yè)務(wù)邏輯次按照標(biāo)準步驟的類別還原回連貫完整的業(yè)務(wù)邏輯,如下圖所示:

wKgZombqOmiAYH2MAALceIjaN5s990.png

??

標(biāo)準業(yè)務(wù)流程模版的引入讓框架進行業(yè)務(wù)流程還原成為可能

除了實現(xiàn)業(yè)務(wù)邏輯按標(biāo)準步驟自動還原之外,由于標(biāo)準流程模板對每一個標(biāo)準步驟方法的執(zhí)行參數(shù)、依賴的上下文及返回值對象都進行了通用化的抽象,能力編排框架也得以在各個能力標(biāo)準步驟調(diào)用之間插入?yún)?shù)及上下文的映射和傳遞邏輯,從而在不同能力之間以及能力與領(lǐng)域服務(wù)之間實現(xiàn)數(shù)據(jù)分發(fā)和共享。需要說明的是盡管這些流程都可以采用默認的自動處理規(guī)則,開發(fā)者也可以通過能力編排框架提供的DSL對默認的串聯(lián)執(zhí)行、數(shù)據(jù)傳遞、異常處理等規(guī)則進行修改

在我們新架構(gòu)中,我們通過領(lǐng)域能力拆分將復(fù)雜的問題域正交分解為多個互相獨立的最小問題域,讓設(shè)計者可以分而治之,逐個擊破,降低了問題的復(fù)雜度和設(shè)計成本,同時單個能力節(jié)點下不同業(yè)務(wù)場景下的業(yè)務(wù)邏輯被分離到了不同的領(lǐng)域能力實例中,避免出現(xiàn)不同業(yè)務(wù)場景互相交織,便于快速梳理業(yè)務(wù)邏輯,定位改動點,這些都體現(xiàn)了“設(shè)計易拓展”的設(shè)計目標(biāo)。

由于拆分出來的各個能力節(jié)點彼此正交,內(nèi)部邏輯十分內(nèi)聚,因此可以在各自的維度上進行迭代,比如同樣是在單元維度下的出價設(shè)置和人群設(shè)置能力就分別在出價類型和人群類型這兩個場景維度上各自進行路由,避免了不同場景互相交織帶來的圈復(fù)雜度上升問題,也能夠更加靈活在不同的業(yè)務(wù)場景中實現(xiàn)能力復(fù)用。同時由于我們的業(yè)務(wù)本質(zhì)上就是對物料的創(chuàng)編,物料新建流程中的能力往往可以直接在物料修改流程中復(fù)用。還有一個特殊的場景就是批量物料操作類型的請求,借助能力編排框架提供的循環(huán)編排和數(shù)據(jù)共享機制,我們可以在領(lǐng)域服務(wù)的開始先批量完成所需數(shù)據(jù)的查詢,然后通過循環(huán)編排機制循環(huán)復(fù)用單個請求處理能力中的純內(nèi)存調(diào)用的數(shù)據(jù)校驗及數(shù)據(jù)處理邏輯,最后在批量操作領(lǐng)域服務(wù)中批量完成聚合根對象集合的寫入,在實現(xiàn)邏輯復(fù)用的同時又能保證數(shù)據(jù)準確性及性能,以上特性都體現(xiàn)了“代碼易復(fù)用”的設(shè)計目標(biāo)。

領(lǐng)域能力的編排邏輯提供了一個業(yè)務(wù)流程的全景視圖,當(dāng)有新同學(xué)加入時,可以迅速通過閱讀能力編排邏輯快速建立起對業(yè)務(wù)的宏觀認知,再結(jié)合在第三代架構(gòu)中引入的聚合機制,可以讓新同學(xué)快速熟悉數(shù)據(jù)模型與業(yè)務(wù)流程。同時通過路由機制系統(tǒng)中全部的業(yè)務(wù)規(guī)則打包拆分成數(shù)量有限邊界清晰的能力節(jié)點,當(dāng)需要快速梳理需求點對應(yīng)業(yè)務(wù)規(guī)則時,可以由粗及細,先確定需求點歸屬的能力節(jié)點,然后根據(jù)場景定位到具體的能力實例,進而可以從代碼中獲取業(yè)務(wù)規(guī)則,這些特性都體現(xiàn)了“邏輯易傳承”的設(shè)計目標(biāo)。

wKgaombqOmqAJOqIAAKYRXumues084.png

??

基于能力拆分與編排的代碼架構(gòu),最顯著的收益就是同一個能力可以在不同的領(lǐng)域服務(wù)中直接復(fù)用(點擊放大查看)

總結(jié)

以上便是我們?yōu)閷崿F(xiàn)新架構(gòu)所進行的種種嘗試,這些設(shè)計是否正確我們也正在通過需求實戰(zhàn)來進行驗證,把他們發(fā)出來不是要說服大家認同,而是想通過對架構(gòu)演進歷程的推演幫助大家更好的理解我們新架構(gòu)中各項功能的設(shè)計動機,從而更快的上手進行開發(fā);另一方面也希望能夠激發(fā)大家的思考和討論,哪怕是對上述方案的質(zhì)疑和批判,一個好的架構(gòu)一定是在一次次批評聲中改進出來的,我至今還在懷念當(dāng)初摸索新架構(gòu)時那些與永亮(我的良師益友,部門內(nèi)探索中臺化及領(lǐng)域驅(qū)動設(shè)計思想的第一人)爭論到凌晨2、3點的日子。

審核編輯 黃宇

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

    關(guān)注

    2

    文章

    58

    瀏覽量

    38293
  • 數(shù)據(jù)模型
    +關(guān)注

    關(guān)注

    0

    文章

    49

    瀏覽量

    10001
  • 架構(gòu)
    +關(guān)注

    關(guān)注

    1

    文章

    513

    瀏覽量

    25468
收藏 人收藏

    評論

    相關(guān)推薦

    java的IO演進之路概述

    第一章 java的IO演進之路
    發(fā)表于 07-24 16:53

    DSP系統(tǒng)的技術(shù)架構(gòu)

      1. 技術(shù)架構(gòu)概要  如圖7-22所示,DSP系統(tǒng)從技術(shù)架構(gòu)上涉及:投放平臺投放設(shè)置用戶交互模塊(setup UI)、報表(Repor
    發(fā)表于 11-30 17:50

    京東IM工具的架構(gòu)演進

    咚咚是什么?咚咚之于京東相當(dāng)于旺旺之于淘寶,它們都是服務(wù)于買家和賣家的溝通工具。 自從京東開始為第三方賣家提供入駐平臺服務(wù)后,咚咚也就隨之誕生了。我們首先看看它誕生之初是什么樣的。 1.0 誕生
    發(fā)表于 10-12 16:39 ?0次下載
    <b class='flag-5'>京東</b>IM工具的<b class='flag-5'>架構(gòu)</b><b class='flag-5'>演進</b>

    代碼質(zhì)量和其整潔度成正比有什么道理如何進行代碼整潔教材免費下載

    。軟件質(zhì)量,不但依賴于架構(gòu)及項目管理,而且與代碼質(zhì)量緊密相關(guān)。這一點,無論是敏捷開發(fā)流派還是傳統(tǒng)開發(fā)流派,都不得不承認。《代碼整潔之道》提出一種觀念:代碼質(zhì)量與其整潔度成正比。干凈的代碼,既在質(zhì)量上較為可靠,也為后
    發(fā)表于 11-28 08:00 ?1次下載

    AI“理性”邏輯,如何幫助廣告營銷實現(xiàn)精準投放

    用戶注意力的必要條件。千人千面的潛在邏輯是精準投放,更多應(yīng)用于電商和信息流廣告當(dāng)中,而實現(xiàn)品效合一,就需要廣告內(nèi)容和形式上的創(chuàng)新引發(fā)用戶關(guān)注,最終通過AI實現(xiàn)精準營銷。以視頻廣告為例,
    的頭像 發(fā)表于 07-29 18:13 ?1421次閱讀

    人工智能算法如何為廣告服務(wù)

    投放廣告廣告主來說,平臺越大用戶越多,還有就是算法越強大,其尋找目標(biāo)客戶的的能力越強,投放效果越好。
    發(fā)表于 03-05 16:16 ?974次閱讀

    Google將不會投放任何與選舉相關(guān)的廣告

    谷歌在同一封電子郵件中表示,同樣將禁止使用與選舉相關(guān)的字詞(包括特定候選人的姓名)來定位目標(biāo)人群的廣告。Axios報告該政策適用于公司投放廣告的所有平臺,包括YouTube。
    的頭像 發(fā)表于 09-27 17:34 ?1350次閱讀

    京東金融APP就短視頻廣告爭議正式致歉

    近日,京東金融官方推出了多條短視頻廣告為其APP做推廣。和其他廣告走紅的方式不同,其廣告因為存在嚴重的價值觀問題而受到了諸多網(wǎng)友批評。隨著事情持續(xù)發(fā)酵,12月15日,
    的頭像 發(fā)表于 12-16 10:45 ?3324次閱讀

    京東再次為低俗廣告道歉 京東金融低俗借貸廣告被吐槽

    京東金融低俗借貸廣告再次處于風(fēng)口浪尖上,此事或者就正說明資本的根源深處的文化就是圍繞錢而來的。京東則再次為低俗廣告道歉。 京東集團發(fā)布聲明,
    的頭像 發(fā)表于 12-18 09:10 ?4296次閱讀

    蘋果iPhone隱私保護功能或限制廣告投放

    據(jù)媒體報道,蘋果公司將為iPhone用戶提供一個隱私選項,讓其可以分享自己的廣告ID(IDFA),并在打開應(yīng)用程序時將它放在顯著位置上。系統(tǒng)會要求用戶先啟用跟蹤功能,然后應(yīng)用才能跟蹤用戶數(shù)據(jù)以投放
    的頭像 發(fā)表于 01-06 16:54 ?1995次閱讀

    液晶廣告機的投放優(yōu)勢?

    近年來,隨著大數(shù)據(jù)技術(shù)的發(fā)展和市場競爭的日益激烈,廣告商對效應(yīng)提出了更高的要求,以增加其市場份額。消費者群體的分割和標(biāo)簽已成為廣告策略的重點。那么,廣告如何實現(xiàn)準確的營銷呢?鵬云視界液晶廣告
    發(fā)表于 12-10 17:48 ?554次閱讀

    ES 集群架構(gòu)演進之路

    ES 集群架構(gòu)演進之路 1、初始階段 2、集群隔離階段 3、節(jié)點副本調(diào)優(yōu)階段 4、主從集群調(diào)整階段 5、現(xiàn)今:實時互備雙集群階段 ES 訂單數(shù)據(jù)的同步方案 遇到的一些坑 1、實時性要求高的查詢走DB
    的頭像 發(fā)表于 11-05 10:47 ?1585次閱讀

    廣告投放公司運用大數(shù)據(jù)分析,實現(xiàn)精準投放

    廣告投放公司運用大數(shù)據(jù)分析,實現(xiàn)精準投放 隨著大數(shù)據(jù)技術(shù)的不斷發(fā)展,廣告投放行業(yè)正經(jīng)歷著一場深刻的變革。傳統(tǒng)的
    的頭像 發(fā)表于 04-11 11:23 ?925次閱讀

    特斯拉在馬斯克的社交平臺X平臺投放廣告

    眾所周知,馬斯克一貫對廣告持排斥態(tài)度。特斯拉此前從未聘請明星代言或投放廣告(盡管曾有例外)。盡管特斯拉的支持者和投資者多次建議其嘗試廣告策略,但馬斯克始終堅決反對,甚至公開表示“厭惡”廣告
    的頭像 發(fā)表于 04-18 10:20 ?400次閱讀

    大促高并發(fā)系統(tǒng)性能優(yōu)化實戰(zhàn)--京東聯(lián)盟廣告推薦系統(tǒng)

    的流量洪峰也對京東各系統(tǒng)提出了嚴峻考驗。 京東聯(lián)盟是京東的聯(lián)盟營銷平臺,主要通過投放站外CPS廣告
    的頭像 發(fā)表于 08-14 10:41 ?318次閱讀
    大促高并發(fā)系統(tǒng)性能優(yōu)化實戰(zhàn)--<b class='flag-5'>京東</b>聯(lián)盟<b class='flag-5'>廣告</b>推薦系統(tǒng)
    RM新时代网站-首页