亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

如何處理有依賴的消息

Tony / 3662人閱讀

摘要:生產(chǎn)者生產(chǎn)的消息要滿足不了消費者才行。可以看到一個有依賴的消息我們在處理的過程,會多一次查詢操作,性能多少會受點影響。如果沒有的消息進來,孤兒院里是醬紫的。收到之后再處理,緊接著又找到的條消息,再出來,讓去處理。

在項目中踏完一系列坑后總結(jié)出來,消息的處理有兩個要務:

消費一定要快,我們喜歡供小于求的市場。生產(chǎn)者生產(chǎn)的消息要滿足不了消費者才行。

任何消息都不能丟,因為這都是數(shù)據(jù)啊,即使處理不了也得找地方存著。最好每次的消息都存著,之后就變成了event sourcing(另一個大坑)。

要實現(xiàn)上述2點,其實要解決很多問題。一個字就不是那么做到的。業(yè)務系統(tǒng)收到消息有可能會觸發(fā)一連串的,并且包裹著事務的邏輯。因為通常我們希望如果這一連串的處理失敗的話,可以把ack退回給MQ。一旦業(yè)務邏輯過于復雜,work消費消息的速度也會變慢。這就需要開發(fā)人員去做權(quán)衡了,是不是有些非常heavy的操作可以先記一筆,等業(yè)務不繁忙的時候再做。具體實現(xiàn)不在這篇討論。

問題

回到主題,有一類消息最讓人頭疼,就是消息之間有依賴,關(guān)系一般為單向的父子關(guān)系。舉個栗子,Product和SKU的關(guān)系,一個Product包含多個SKU。比如我們的業(yè)務邏輯是要監(jiān)聽這兩個消息組成一顆樹放到索引中??上攵?,這棵樹肯定是至少兩層結(jié)構(gòu),第一級是Product,下面掛著一個或多個SKU。

一般來說,子結(jié)構(gòu)如果是個多帶帶的消息肯定會有個字段說明自己的parent id是什么。那么很自然的,我們在某一刻只收到一個SKU的Create事件,會去通過parent id找到索引中對應的Product,然后上去。問題來了,要是索引中沒有對應的Product怎么辦,消息是沒有順序的,可能是Product的Create事件還沒處理到,或者是生產(chǎn)者出了bug消息沒發(fā)出來造成的。這時SKU的消息就成了孤兒消息。

解決思路一

比較近粗暴的方式,就是利用SKU上的parent id虛擬出一個只有id的Product,由處理SKU事件的worker來幫忙創(chuàng)建這個Product。等下次Product的Create消息進來做一次更新就好了。(處理消息應該不要區(qū)分這是Create還是Update還是Delete,消費者就都當Update來做比較好,可以想想為什么)。

當然這個思路一看就有點bad smell,從單一職責的角度上來看,處理SKU的worker應該只關(guān)注SKU,不應該關(guān)注Product。如果Product也是個孤兒怎么辦呢?這個worker可能會越寫越復雜。

改進的話可以把創(chuàng)建虛擬Product的這個事情放到SKU這個對象中去做,實現(xiàn)以下setProduct這個方法。那么即使Product也有依賴,那Product自己也得有個setParent的方法,這樣就可以遞歸下去了。(之后想了一下無法處理多級關(guān)系,因為Product的消息沒來,我們不知道它的parent id,父節(jié)點根本建不出來。所以思路一只能處理一個層級的依賴。)

總結(jié)一下,思路一是一種不管三七二十一,誰也不能阻止我消費的路線,大不了自下而上的創(chuàng)建虛擬父節(jié)點。

解決思路二

相對思路一而言,這種思路還是比較優(yōu)雅的,但是優(yōu)雅不等于性能好。

既然SKU是個孤兒,那么我們先收下來放孤兒院好了。新建一張孤兒院表:

id parent_type parent_id
101010 Product 1010
101011 Product 1010

上面兩條數(shù)據(jù)就是SKU的,然后為了提升一點性能我們得對對象分個類,一類是有依賴的,一類是無依賴的。沒有依賴的直接消費就好,像Product,SKU這種有依賴的,都得打上標簽(就是對象里寫個isDependency)。例如一個SKU(101010)的消息進來,worker發(fā)現(xiàn)這是一個有依賴的消息,那么先拿parent id (1010)去找Product, 發(fā)現(xiàn)Product找不到就把這個SKU丟到孤兒院表里去。如果你是用OO的語言,這里其實可以抽象一下。一個BaseWorker,一個SKUWorker,BaseWork負責寫個abstract的findParent(),SKUWorker去實現(xiàn)找Product的邏輯就好了。

public abstract class BaseWorker {
    
    public void handle(T t) {
        if (t.isDependency() && findParent(t) == null) {
            // 送到孤兒院
            takeToOrphanage(t);
            return;
        }
    }
    
    abstract Entity findParent(T t);
    
    protected void takeToOrphanage(T t) {
    }
    
}

消息記錄下來以后,Worker的工作就終止,等待下一條消息進來。過了幾分鐘,Product(1010)的消息過來了,這時候我們需要給BaseWorker再添加一些代碼。

public void handle(T t) {
        if (t.isDependency() && findParent(t) == null) {
            // 送到孤兒院
            takeToOrphanage(t);
            return;
        }
    
        // 正常業(yè)務...
    
        // 正常業(yè)務處理之后
        if (t.isDependency()) {
            List children = findChildren(t);
            if (children != null) {
                children.forEach(child -> {
                    sendAsMessage(child);
                });
            }
        }
    
    }
    
    abstract List findChildren(T t);

我們增加一個findChildren方法,讓ProductWorker去實現(xiàn)具體邏輯。handle()中增加的代碼含義是,當Product這個消息消費完了以后,去孤兒院轉(zhuǎn)一圈看看是不是有等待認領的孩子,簡單的利用parent_typeparent_id就能查到。查到以后別直接處理,仍然是以消息的形式發(fā)出,讓SKUWorker自己去handle,然后可以delete/soft-delete孤兒院中的記錄。

可以看到一個有依賴的消息我們在處理的過程,會多一次查詢操作,性能多少會受點影響。之前的那次findParent查詢其實思路一也有的,目的就是掛靠。

再多一個層級看看是不是罩得住,Category --> Product --> SKU 三層。

如果沒有Category的消息進來,孤兒院里是醬紫的。

id parent_type parent_id
101010 Product 1010
101011 Product 1010
1010 Category 10

某一時刻Category的消息進來,CategoryWorker會先到表里查到一條1010的Product消息,把它send出來。ProductWorker收到之后再處理,緊接著又找到SKU的2條消息,再send出來,讓SKUWorker去處理。可以看到,自帶遞歸,多層級只要是單向依賴的肯定搞的定。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/66305.html

相關(guān)文章

  • 何處理Docker錯誤消息:please add——insecure-registry

    摘要:本地安裝時,遇到如下的錯誤消息解決方案點擊的菜單點擊標簽頁,在里維護記錄將錯誤信息里提到的維護進點擊按鈕重新啟動之后錯誤消息消失。 本地安裝Kubernetes時,遇到如下的錯誤消息: pleade add --insecure-registry gcr.io to daemons arguments showImg(https://segmentfault.com/img/remot...

    jsdt 評論0 收藏0
  • 白話RabbitMQ(六): RPC

    摘要:因為消費消息是在另外一個進程中,我們需要阻塞我們的進程直到結(jié)果返回,使用阻塞隊列是一種非常好的方式,這里我們使用了長度為的,的功能是檢查消息的的是不是我們之前所發(fā)送的,如果是,將返回值返回到。 推廣 RabbitMQ專題講座 https://segmentfault.com/l/15... CoolMQ開源項目 我們利用消息隊列實現(xiàn)了分布式事務的最終一致性解決方案,請大家圍觀。可以參考...

    KevinYan 評論0 收藏0
  • 何處理Docker錯誤消息request canceled:Docker代理問題

    摘要:在本地安裝時,遇到錯誤消息這個原因是應用沒有正確設置代理。在上設置代理非常方便選擇即手動設置。設置完之后,點擊按鈕之后在里使用命令行可以成功把鏡像下載到本地。 在本地安裝Kubernetes時,遇到錯誤消息: request canceled while waiting for connection(Client.Timeout exceeded while awaiting head...

    qianfeng 評論0 收藏0
  • 為Java程序員金三銀四精心挑選300余道Java面試題與答案

    摘要:為程序員金三銀四精心挑選的余道面試題與答案,歡迎大家向我推薦你在面試過程中遇到的問題我會把大家推薦的問題添加到下面的常用面試題清單中供大家參考。 為Java程序員金三銀四精心挑選的300余道Java面試題與答案,歡迎大家向我推薦你在面試過程中遇到的問題,我會把大家推薦的問題添加到下面的常用面試題清單中供大家參考。 前兩天寫的以下博客,大家比較認可,熱度不錯,希望可以幫到準備或者正在參加...

    tomorrowwu 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<