歡迎大家回到網(wǎng)易云音樂評(píng)論技術(shù)探秘之旅色难,上一篇我們介紹了云音樂評(píng)論的業(yè)務(wù)場(chǎng)景和基礎(chǔ)架構(gòu)泼舱,這一篇將圍繞云音樂評(píng)論的核心功能:評(píng)論發(fā)表、評(píng)論獲取和評(píng)論點(diǎn)贊進(jìn)行剖析探秘莱预。
評(píng)論發(fā)表
首先我們先看上圖柠掂,這是我們把評(píng)論功能抽象出來最核心的數(shù)據(jù)庫表結(jié)構(gòu),為了更好地理解后文依沮,我們先解釋一下字段含義
先看一下右邊評(píng)論表【Comment】:
- id:評(píng)論記錄主鍵
- resourceId:評(píng)論所屬的資源
- contents:評(píng)論內(nèi)容
- time:評(píng)論時(shí)間
- likedCount:評(píng)論被點(diǎn)贊次數(shù)(這里會(huì)有行鎖競(jìng)爭(zhēng)的問題需要處理)
- status:數(shù)據(jù)狀態(tài)
- userId:評(píng)論用戶ID
- version:版本號(hào)涯贞,用樂觀鎖控制數(shù)據(jù)并發(fā)操作
接下來我們看評(píng)論與資源關(guān)聯(lián)表【CommentResource】,對(duì)資源不太理解的同學(xué)可以翻閱上篇危喉。
- id:評(píng)論與資源關(guān)聯(lián)表的主鍵宋渔,這里沒有使用自增ID,而是使用資源類型和資源ID組合辜限,這樣在處理業(yè)務(wù)邏輯時(shí)就可以根據(jù)主鍵ID按照規(guī)則拆解出資源ID從而可以方便的取到資源信息
- resourceInfo:資源基本信息
- resourceType:資源類型皇拣,如歌單、歌曲薄嫡、動(dòng)態(tài)氧急、電臺(tái)等
- CommentCount:記錄資源評(píng)論數(shù)量,類似上表的likedCount都是計(jì)數(shù)字段毫深,同樣有行鎖競(jìng)爭(zhēng)的問題需要處理
評(píng)論發(fā)表流程
介紹完評(píng)論數(shù)據(jù)模型之后吩坝,我們開始進(jìn)入評(píng)論發(fā)表流程,整體流程圖如下:
從上圖可以看到從客戶端發(fā)起評(píng)論到后臺(tái)服務(wù)會(huì)先經(jīng)過網(wǎng)關(guān)哑蔫,上一篇我們也提到了網(wǎng)關(guān)的重要性钉寝,它為后臺(tái)服務(wù)提供了流控、鑒權(quán)等全局能力闸迷。接下來就進(jìn)入應(yīng)用服務(wù)嵌纲,應(yīng)用服務(wù)首先會(huì)進(jìn)行前置的邏輯判斷,包含三部分分別是:一是反作弊判斷腥沽,主要是安全性方面的判斷逮走;二是資源合法性判斷,比如資源已經(jīng)不存在了今阳,或者設(shè)置不允許評(píng)論等言沐;最后是評(píng)論鑒權(quán)邓嘹,有可能資源作者拉黑了某些用戶酣栈,那么這些在黑名單的用戶就不能對(duì)該資源進(jìn)行評(píng)論了险胰。
經(jīng)過上述前置校驗(yàn)通過后,可以看到這里進(jìn)行了異步化的處理矿筝,將評(píng)論放到異步消息隊(duì)列成功時(shí)即返回客戶端評(píng)論成功起便,再由消息消費(fèi)者異步進(jìn)行持久化處理。
對(duì)于評(píng)論來說窖维,其內(nèi)容合法性是至關(guān)重要的榆综,這個(gè)大家都懂,因此在進(jìn)行真正持久化處理之前需要進(jìn)行反垃圾處理铸史,將不合適的內(nèi)容優(yōu)(he)化(xie)一下鼻疮,對(duì)于反垃圾如何實(shí)現(xiàn)這個(gè)就比較復(fù)雜了,一般都是有專門的部門和系統(tǒng)提供中臺(tái)化平臺(tái)琳轿,常見的做法是構(gòu)建內(nèi)容中心判沟、策略引擎、舉報(bào)懲罰中心崭篡、數(shù)據(jù)中心和引入人工標(biāo)注挪哄,這個(gè)都可以單獨(dú)再寫一篇了,這里暫不贅述琉闪。接下來進(jìn)行真正的持久化迹炼,添加評(píng)論并更新評(píng)論計(jì)數(shù),到此評(píng)論本身的處理就結(jié)束了颠毙,然后將該事件寫到消息隊(duì)列斯入,通知其他關(guān)聯(lián)業(yè)務(wù)處理。
接下來重點(diǎn)說一下上述流程在前置校驗(yàn)和后置持久化中間進(jìn)行異步化處理蛀蜜,主要有以下兩個(gè)好處:
- 熱門資源可能會(huì)在短時(shí)間產(chǎn)生大量評(píng)論刻两,如果不進(jìn)行異步化對(duì)突發(fā)流量削峰會(huì)導(dǎo)致在短時(shí)間內(nèi)有大量評(píng)論更新同一資源的評(píng)論計(jì)數(shù),即更新CommentResource表的CommentCount字段涵防,會(huì)存在行鎖競(jìng)爭(zhēng)問題
- 評(píng)論本身從請(qǐng)求發(fā)出到數(shù)據(jù)落地所需要處理的邏輯相對(duì)評(píng)論讀取要復(fù)雜很多闹伪,通過異步消息隊(duì)列將流程解耦可以快速響應(yīng)用戶,提升用戶體驗(yàn)壮池。
當(dāng)然引入異步化也增加了系統(tǒng)復(fù)雜度偏瓤,需要正確使用,否則會(huì)引起其他問題椰憋。那么異步化需要關(guān)注的點(diǎn)有哪些呢厅克?
- 消息有序性:從評(píng)論這個(gè)業(yè)務(wù)場(chǎng)景來看,對(duì)消息有序性沒有那么高的要求橙依,消息不需要邏輯有序证舟,或者說即使消息亂序了硕旗,用戶感知并不明顯,而且消息體已包含評(píng)論發(fā)表時(shí)間女责,可以確保評(píng)論顯示的時(shí)間與用戶發(fā)表時(shí)間一致漆枚。
- 消息冪等性:不同消息中間件提供的機(jī)制有所不同,有的是保證最多消費(fèi)一次抵知,這可能會(huì)導(dǎo)致消息丟失墙基;有的是最少消費(fèi)一次,這可能導(dǎo)致重復(fù)消費(fèi)刷喜;對(duì)于這個(gè)場(chǎng)景來說残制,肯定是要優(yōu)先保證消息不丟失,即允許消息存在重復(fù)掖疮,消息重復(fù)引來另一個(gè)問題就是要實(shí)現(xiàn)消息冪等初茶,否則后果可想而知。這里可以在消息異步化之前生成評(píng)論主鍵作為消息體的一部分浊闪,通過成熟的數(shù)據(jù)庫唯一性約束保證消息唯一恼布,相對(duì)來說是比較容易也是成本較低的實(shí)現(xiàn)方式。
- 消息延遲:異步化的另一個(gè)共性問題就是消息可能會(huì)延遲规揪,在這個(gè)場(chǎng)景中我們看到在消息進(jìn)入隊(duì)列之前已經(jīng)返回客戶端成功桥氏,此時(shí)客戶端可以將當(dāng)前用戶評(píng)論顯示在評(píng)論列表上,但是其他人刷新列表時(shí)不一定能同時(shí)看到猛铅,需要等到數(shù)據(jù)持久化之后字支,正常情況下客戶感知不明顯,但在消息堆積比較嚴(yán)重的情況下會(huì)存在一定時(shí)間差奸忽。
評(píng)論反垃圾
對(duì)于所有互聯(lián)網(wǎng)UCG相關(guān)的場(chǎng)景都避免不了反垃圾處理堕伪,對(duì)于反垃圾處理在實(shí)現(xiàn)上有以下要求:
首先要做到數(shù)據(jù)可恢復(fù),因?yàn)橛行?shù)據(jù)有可能一開始會(huì)被系統(tǒng)認(rèn)為有問題栗菜,后續(xù)又經(jīng)過審核把“有問題”的給恢復(fù)回來欠雌,因此要求數(shù)據(jù)資產(chǎn)可恢復(fù),不能做物理刪除疙筹,實(shí)際上不僅僅評(píng)論數(shù)據(jù)富俄,從公司數(shù)據(jù)資產(chǎn)角度來說對(duì)于所有的數(shù)據(jù)都不建議物理刪除。另外而咆,如上文所述反垃圾服務(wù)一般是獨(dú)立于業(yè)務(wù)系統(tǒng)存在的霍比,跨系統(tǒng)協(xié)作不可避免會(huì)存在請(qǐng)求或響應(yīng)沒收到的情況,這樣會(huì)導(dǎo)致整個(gè)鏈路不完整暴备,因此需要有類似對(duì)賬機(jī)制悠瞬,確保請(qǐng)求被接收,響應(yīng)被處理,即ACK機(jī)制浅妆,所以這個(gè)地方要求反垃圾記錄做持久化處理望迎,做到可追溯。
評(píng)論點(diǎn)贊
評(píng)論點(diǎn)贊功能很好理解凌外,場(chǎng)景比較簡(jiǎn)單辩尊,喜歡可以點(diǎn)贊,點(diǎn)了贊的也可以取消趴乡。但它與評(píng)論計(jì)數(shù)有個(gè)類似的問題对省,熱門資源的熱門評(píng)論有可能會(huì)有很多人同時(shí)點(diǎn)贊從而產(chǎn)生計(jì)數(shù)行鎖競(jìng)爭(zhēng),這里我們同樣采用異步的方式進(jìn)行削峰晾捏,但這里與評(píng)論有個(gè)不同點(diǎn)是這里異步化要重點(diǎn)解決的是消息有序性,因?yàn)橥粋€(gè)用戶如果先點(diǎn)贊后取消哀托,但后臺(tái)接收到的消息卻是先取消后點(diǎn)贊惦辛,這樣就會(huì)導(dǎo)致最終的結(jié)果跟實(shí)際操作不符,顯然這里消息有序性比消息不重復(fù)更重要仓手。
那如何保證消息嚴(yán)格有序呢胖齐?消息有序既要求消息有序生產(chǎn),也要求消息被有序消費(fèi)嗽冒。
如上圖呀伙,我們都知道使用kafka中間件,同一個(gè)partition可以保證消息有序添坊,因此我們可以按照用戶維護(hù)剿另,讓同一個(gè)用戶的點(diǎn)贊和取消點(diǎn)贊操作都寫到同一個(gè)partition,這可以解決生產(chǎn)端消息有序贬蛙;然后在消費(fèi)端雨女,我們使用單線程消費(fèi)同一個(gè)partition,這樣可以保證消費(fèi)端有序消費(fèi)阳准;但是單線程消費(fèi)有可能會(huì)帶來性能問題導(dǎo)致消息積壓氛堕,因此我們需要考慮擴(kuò)展更多的partition使消息更分散,這樣消費(fèi)的線程也同樣得到相應(yīng)的擴(kuò)展野蝇。
評(píng)論讀取
前面我們了解到評(píng)論讀取的并發(fā)是非常高的讼稚,因此首先我們要考慮該場(chǎng)景下要保護(hù)的核心資源:數(shù)據(jù)庫。為了保護(hù)數(shù)據(jù)庫同時(shí)為了提供滿足業(yè)務(wù)要求的性能绕沈,我們進(jìn)行了多級(jí)緩存的設(shè)計(jì)锐想,具體如下圖:
從下往上看我們可以看到在數(shù)據(jù)庫之上有Memcached緩存,這是跟數(shù)據(jù)庫表一一對(duì)應(yīng)的七冲,我們可以理解為DAO層緩存痛倚;再往上是數(shù)據(jù)組裝服務(wù),處理評(píng)論相關(guān)聯(lián)的數(shù)據(jù)組裝澜躺;接著是使用Redis實(shí)現(xiàn)的業(yè)務(wù)層緩存蝉稳,這里存放的就是經(jīng)過業(yè)務(wù)組裝的數(shù)據(jù)抒蚜;最上層就是應(yīng)用服務(wù)了,這一層我們也使用了本地緩存耘戚,它的特點(diǎn)是快嗡髓,但容量小,因此只能放少量熱門的數(shù)據(jù)收津,但這部分最熱門數(shù)據(jù)的緩存可以緩解Redis熱點(diǎn)問題饿这,避免最熱門數(shù)據(jù)都打到同一個(gè)Redis節(jié)點(diǎn),但本地緩存有一個(gè)問題撞秋,就是緩存難以同時(shí)清除长捧,不同于分布式緩存,使用一個(gè)命令就可以把緩存清掉吻贿,本地緩存在每個(gè)服務(wù)器上面都存了一份串结,這個(gè)要同時(shí)清理還是比較困難的。
另一個(gè)需要注意的是冷熱數(shù)據(jù)的處理舅列,因?yàn)閿?shù)據(jù)庫和內(nèi)存緩存的容量級(jí)別存在較大差異肌割,我們不可能把所有的數(shù)據(jù)都緩存起來,因此緩存一般存的都是相對(duì)較熱的數(shù)據(jù)帐要,冷數(shù)據(jù)則從數(shù)據(jù)庫直接加載把敞。
接下來我們重點(diǎn)看一下業(yè)務(wù)層緩存的設(shè)計(jì),這里相對(duì)比較復(fù)雜榨惠。上面提到了這里緩存的是業(yè)務(wù)組裝之后的數(shù)據(jù)奋早,除了評(píng)論數(shù)據(jù)本身,還會(huì)讀取其他模塊比如用戶數(shù)據(jù)冒冬,但其他模塊的數(shù)據(jù)更新又不會(huì)通知到評(píng)論模塊伸蚯,所以怎么更新這一層緩存呢?這里我們采用的策略不是去訂閱其他服務(wù)的變更來同步更新緩存简烤,而是采用短時(shí)間緩存自動(dòng)失效后重新拉取數(shù)據(jù)的方式剂邮。從下圖可以看到短時(shí)間緩存過了2秒之后就需要重新調(diào)用數(shù)據(jù)組裝服務(wù),這2秒鐘對(duì)前端體驗(yàn)來說基本無損横侦,但緩存失效之后會(huì)造成大量請(qǐng)求去調(diào)用組裝服務(wù)挥萌,為了避免對(duì)下層服務(wù)造成太大壓力這里加了一層分布式鎖,即某個(gè)緩存失效了之后枉侧,在大量請(qǐng)求該緩存數(shù)據(jù)的線程中引瀑,只有一個(gè)線程可以調(diào)用數(shù)據(jù)組裝服務(wù),其他的請(qǐng)求轉(zhuǎn)到長(zhǎng)時(shí)間緩存(24小時(shí))榨馁,當(dāng)數(shù)據(jù)組裝完成后會(huì)同時(shí)更新短時(shí)間緩存和長(zhǎng)時(shí)間緩存憨栽,這樣長(zhǎng)短緩存結(jié)合的設(shè)計(jì)既保護(hù)了核心資源,也不犧牲服務(wù)性能,同時(shí)可以解決數(shù)據(jù)組裝問題屑柔,可以說是一個(gè)比較巧妙的設(shè)計(jì)屡萤。
以上就是云音樂評(píng)論的核心功能評(píng)論發(fā)表、評(píng)論獲取和評(píng)論點(diǎn)贊的實(shí)現(xiàn)思路掸宛,包含了基礎(chǔ)的邏輯架構(gòu)死陆,處理流程,以及關(guān)鍵功能點(diǎn)實(shí)現(xiàn)技巧唧瘾。