閒魚商品選投實時性優化

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"馬赫是閒魚的選品和投放系統,閒魚業務中多數商品都是孤品即單庫存商品,所以商品的實時變更需要即刻反饋到選品和投放鏈路中,爲了滿足業務訴求馬赫設計之初就把實時性作爲最重要的技術目標,隨着系統的運行數據的膨脹實時性也遇到了瓶頸,本文將介紹近一年來在提升馬赫實時性上的相關工作,目標是選品實時性延遲控制在秒級別。如果有對馬赫不瞭解的同學可以回顧公衆號內馬赫相關文章。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"選投實時鏈路"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"馬赫整個選品和投放的過程中數據流轉如下圖所示主要分爲三個部分,第一部分是選品數據接入,數據是馬赫選品的根本,數據的實時是整個馬赫流程能有效運轉的基礎。第二部分是選品規則計算,規則計算是馬赫的核心,計算的實時性保證了馬赫能把選品結果同步到各個下游節點。第三部分是商品投放,商品投放是與用戶距離最近的部分,實時的反饋能給用戶帶來更好的體驗。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/37\/375295b07e40432ca2c298cae5a2a105.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"馬赫實時性性能優化也是從這三部分入手,下面將針優化過程進行詳細介紹。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"選品數據實時性能優化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"馬赫選品依賴的選品寬表數據,主要由兩類數據構成,一類是商品基礎數據,商品基礎數據指用戶發佈的商品信息包括:商品類型、商品狀態、商品價格、商品描述、商品圖片;該類數據通過訂閱商品數據庫的變更已經實現了實時性。另外一類是基於商品衍生出的統計和預測數據,這類的數據一般都是通過ODPS(阿里內部離線計算平臺)離線計算,產出時間與商品基礎相比大多是天級別或小時級別延遲,該類數據原有的接入方案如下,無論是小時級別延遲還是天級別延遲產出的數據,都是進行統一的處理,每天把所有的數據JOIN到一起後輸出到一個離線數據表中,然後把該數據通過BLINK 和 MetaQ消息通道與馬赫的數據統一接入層對接。該方案的優點是所有的離線產出數據只需要處理一次方便運維,同時每天一次迴流整個過程的數據量可控。缺點也是顯而易見,首先每天彙總數據產出時間取決於上游耗時最長的數據,如果有數據延遲將會影響整個流程的耗時,其次明明是H+1產出的數據卻要等到T+1纔可使用,這嚴重影響了選品能力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/69\/69e3cec804795daa5cfd0f56a1042fcc.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"問題已經明確那剩下來的就是解法,首先要解決的彙總數據依賴上游最長耗時的問題,常規的解法是彙總數據定時產出,到了定時時間,上游各個節點數據已經產出那麼就使用,如果沒有產出就使用上一次產出的數據,最初解決時也確實採用了該方案,該方案會造成部分數據要T+2纔可以進入選品寬表。雖然不是很好的解法但是解法簡單,作爲過渡方案在馬赫裏面也運行了一段時間。下面介紹這個問題馬赫採用的最終解法,如下圖所示:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a0\/a0a6a570d304e739e1e424de78c0040a.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先把數據按照產出週期進行分類,H+1產出的數據量級在萬,T+1產出的數據量級在億,對於H+1的數據直接利用BLINK讀取後,利用MetaQ數據通道輸出到數據統一接入層,保證了數據產出即用。對於T+1的數據同樣直接利用BLINK讀取,由於該部分數據過大,如果直接輸出QPS將會達到百萬級別對於下游壓力過大,所以馬赫利用BLINK的滑動窗口的聚合能力,把商品ID作爲KEY對窗口內的數據進行聚合,聚合後再輸出到馬赫數據統一接入層。滑動窗口越小那麼實時性將會越高,但是同樣系統壓力也會越大,目前馬赫的滑動窗口時間爲6個小時。該方案解決了商品算法和統計數據接入實時性的問題,但整個系統流量增加了4倍,這也是設計系統時候常常糾結的時間成本與空間成本的權衡問題,在本次優化中選擇了用空間換時間並有節制的控制了兩個的平衡,優化後效果從天級別延遲縮短至小時級別。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"選品規則計算實時性優化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"選品規則計算包含兩個部分一部分是運營創建選品規則時在馬赫選品寬表中運算選併產出結果集稱爲離線選品規則執行引擎,另一部分是當商品信息變更時需要重新計算當前商品命中的選品規則稱爲在線選品規則執行引擎。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先介紹第一部分離線選品規則執行引擎的優化,運營創建的選品規則會映射成SQL在馬赫選品寬表ADB上進行執行,ADB是全索引數據表這裏主要是用空間去換時間,但是有一類問題很難解決就是文本的全字段匹配,舉一個例子選品寬表中有個從商品基本數據表中映射字段ATTRIBUTE,從名字就不難看出該字段是當時商品設計中預留出的擴展字段,其內容以kv對分號分隔的形式進行存儲,運營在進行選品時最終映射到該字段的規則SQL是用LIKE關鍵字進行在十幾億的數據中檢索在其性能可想而知。所以針對該類字段做了多值映射即把kv對映射成數字進行存儲,該方案雖然不復雜但是解決了創建規則時商品量計算以及商品預覽的時效性問題不做過多贅述,優化後商品計算從6分鐘級別降至30秒,具體效果如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/78\/78f509d90cdfb5ed74f4aa77c6df2eb7.jpeg","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面介紹第二部分在線規則執行引擎的優化,在線引擎是在BLINK中實現的,商品的變更信息作爲輸入源,在執行引擎中計算出當前商品命中的商品池,把商品和對應命中的商品池作爲結果輸出到下游。原有的流程如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/4e\/4eb2ade2a743461a486ac635e2c8a2cb.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在BLINK中主要完成了馬赫關鍵的MERGE 和 DIFF操作,MERGE是把BLINK內存中的數據與輸入進來的數據取字段上的最大的更新時間戳爲最新數據把商品信息整合。然後把整合後的數據在所有的選品規則上運行,運行結果與上一次結果做對比,篩選出兩次結果不同的數據作爲結果輸出這步操作稱爲DIFF。這樣做的好處是內存存儲商品最新數據減少讀取的IO減少時間消耗,同時輸出結果時只輸出DIFF,減少數據量的傳輸再次節省時間。該方案也有着明顯的弊端整個數據都在內存中存儲,如果發生不可預期的異常內存中的數據將會丟失,從系統開始運行到優化前從沒有停機過,其中付出的運維成本可想而知,同時不可停機導致系統無法升級和使用新版本的BLINK能力。下面針對不可停機問題進行如下解法:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/99\/99a105d19613f958eb61b59f9e68e3c4.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在BLINK接受到商品信息時首先從本地拉取數據,如果拉取不到則從商品信息庫中讀取對應數據,在結果輸出時在輸出原有的信息同時增加輸出商品信息與全量的規則命中信息,作爲備份存儲方便停機恢復,其中爲了減少存儲空間和數據的IO在傳輸和存儲過程中對數據都進行了壓縮處理。最終方案整個邏輯不是很複雜,複雜的是如何從原有的方案平滑切換到現在的方案,其中涉及到數據同步、數據轉換、數據校對,這裏面踩了不少坑,該部分不是本文的重點就不贅述了。最終在解決不可停機的問題同時也升級了BLINK版本,升級後數據延遲從原有的2分鐘降低至2秒,讓整個在線規則引擎運行更快更平穩。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"商品投放的實時優化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"商品投放是與用戶側距離最近的能力,運營圈選商品後形成商品池,然後利用商品池搭建頁面投放給用戶,在用戶請求時把商品從商品池中召回然後展現給用戶,具體流程如下圖所示。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1d\/1de8fddd5b2a7aee10066e2119c9c4ba.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這個過程中與馬赫發生深層關係的是在召回的部分,目前馬赫支持搜索召回和算法召回兩種召回方式,搜索召回中把商品池的實時變更同步給搜索引擎做增量的迭代,天然支持實時召回的能力只需要保證增量的穩定即可;算法召回利用的是用戶屬性召回相關商品,用戶和商品的關係是T+1產出,這與馬赫場景中強調的實時性相悖,爲了解決算法召回的實時性問題,馬赫做出如下解法:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/06\/061a92e68c022a1e3926d422baad59ae.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先我們看一下召回流程:當接受到一個用戶請求,我們會得到兩個信息一個是用戶的ID和商品池的ID,首先利用用戶ID查詢用戶與商品關係表進行個性化召回,然後利用商品池的ID查詢選品池與商品關係數據表進行通用性召回,最後把兩部分數據進行去重合並這裏統稱爲個性召回,召回後的數據JOIN商品與商品池關係表,只保留符合該商品池ID下的商品這裏稱爲召回過濾,如果此時商品數量滿足召回要求則返回,如果不滿足召回要求則查詢商品池與商品關係數據表召回的兜底數據這裏統稱爲兜底召回,通過召回流程後再經過RANK和信息補充就把數據呈現給用戶了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面流程中提到多個數據表,那麼這些數據表是如何產出又爲什麼這麼設計下面詳細介紹。首先介紹在個性召回中使用的BE用戶和商品關係數據表的產出邏輯,這部分數據不依賴馬赫的任何信息,僅僅是通過用戶在閒魚的點擊瀏覽等用戶偏好行爲對用戶喜歡的商品進行預測,每個用戶相關商品規模在2000個是T+1產出。然後介紹個性召回中使用的BE選品池和商品關係數據,這部分數據是依賴馬赫離線引擎同步產出的,這裏的產出邏輯是首先根據各項指標對選品池中的商品進行排序,排序後保留前5000個作爲通用召回是T+1產出,使用依賴這兩個表完成了個性召回步驟。然後是召回過濾中BE商品與選品池關係數據,這部分數據是利用在線同步引擎實時更新的,之所以設計這步召回過濾是爲了防止個性召回的T+1的商品,當前已經不在商品池中了。所以理所當然的就有了召回兜底邏輯,該部分數據是由馬赫的同步引擎保證實時更新存儲在IGRAPH中,可以用商品池的ID召回當前池子中最新的2000個商品作爲兜底。通過以上的邏輯保證了用戶在算法進行召回時的實時性。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文從馬赫選品到馬赫投放實時性優化做了全面的介紹,每一步優化呈現的都是最終方案,爲了保證系統的平滑過渡優化中中踩了很多坑不過最終都平穩落地,優化後的馬赫從選品到投放整個實時鏈路時延有一個質的變化,選品數據從T+1變爲H+1,選品流程從6分鐘變爲30秒,投放流程從2分鐘變爲2秒,系統更健壯也更實時,從整體功能看馬赫還是屬於一個工具級別系統,還遠沒有達到產品級別系統級。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/74\/74873203f0d4204636ce5b17dfc64336.png","alt":"圖片","title":"null","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上圖所示,未來會把重點放在選品能力與整體運維能力上,在優化原有系統的同時增加新的能力,逐步把馬赫打造成產品化系統。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文轉載自:閒魚技術(ID:XYtech_Alibaba)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"},{"type":"link","attrs":{"href":"https:\/\/mp.weixin.qq.com\/s\/G9cAXV2T_QETD7VCRoO7_Q","title":"xxx","type":null},"content":[{"type":"text","text":"閒魚商品選投實時性優化"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章