高性能系統(tǒng)設(shè)計:互聯(lián)網(wǎng)點贊系統(tǒng)設(shè)計及實踐

1 什么是點贊系統(tǒng)

點贊是互聯(lián)網(wǎng)中常見的交互方式,系統(tǒng)根據(jù)用戶的點贊操作來跟蹤用戶的行為议忽,并對用戶的喜好進行分析懒闷。

點贊,在互聯(lián)網(wǎng)中是一個比較簡單的操作栈幸。用戶看到自己喜歡的信息愤估,點擊“贊”按鈕,點亮“贊”操作速址,再次點擊玩焰,取消之前的“贊”操作。是不是很 easy壳繁?

點贊

但震捣,一個明星微博的點贊數(shù)可能高達幾十萬,甚至上百萬闹炉。一個熱點新聞蒿赢,可能有數(shù)千、數(shù)萬渣触、甚至數(shù)十萬用戶同時點贊羡棵,如何處理這些極端情況呢?

2 系統(tǒng)設(shè)計要點

如果要構(gòu)建一套通用點贊系統(tǒng)嗅钻,首先需要對系統(tǒng)所涉及角色皂冰、主功能進行梳理。

2.1 系統(tǒng)角色

系統(tǒng)角色主要涉及 點贊發(fā)起者點贊目標(biāo)對象养篓。

這兩個角色秃流,本質(zhì)上是對其他對象的一種引用。從領(lǐng)域設(shè)計角度柳弄,應(yīng)該是對其他限界上下文中聚合的引用舶胀。兩個角色,本身沒有唯一標(biāo)識,并根據(jù)屬性確定其相等性嚣伐。因此糖赔,符合值對象建模規(guī)范,應(yīng)該作為值對象處理轩端。

通常情況下放典,點贊發(fā)起者對應(yīng)系統(tǒng)的用戶(有的系統(tǒng)會有多個用戶系統(tǒng))。但基茵,點贊的目標(biāo)對象可能會有很多奋构,如新聞、評論耿导、帖子等等声怔。

點贊發(fā)起者&目標(biāo)

系統(tǒng)角色如下:

角色 含義 建模方式
Owner 點贊發(fā)起者 值對象
Target 點贊目標(biāo)對象 值對象

2.2 系統(tǒng)功能用例

系統(tǒng)功能,主要圍繞系統(tǒng)角色展開舱呻。

點贊發(fā)起者 Owner醋火,可以選擇一個點贊對象 Target 進行點擊操作。當(dāng)顯示目標(biāo)對象 Target 時箱吕,需要判斷該 Target 是否已經(jīng)點過贊芥驳。

對于點贊對象 Target,只有一個應(yīng)用場景茬高,就是在顯示時兆旬,獲取總的點贊數(shù)量。

用戶用例

詳細用例如下:

用例 含義
點擊 Owner 對特定 Target 進行點擊怎栽。如果沒有點贊丽猬,則點贊;如果已經(jīng)點贊熏瞄,則取消點贊
是否點贊 判斷特定 Owner 對 特定 Target 是否已經(jīng)點贊
獲取點贊數(shù)量 獲取特定 Target 總的點贊數(shù)量

2.3 贊功能設(shè)計

點贊發(fā)起者點擊“贊”按鈕脚祟,點亮“贊”操作,再次點擊强饮,取消之前的“贊”操作由桌。

2.3.1 識別建模類型

Like 可以接收點擊操作,并更新內(nèi)部狀態(tài)邮丰。同一個點贊發(fā)起者對同一個點贊目標(biāo)進行“贊”和“取消”操作時行您,針對的應(yīng)該是同一個 “Like” 實例,需要唯一標(biāo)識對操作進行跟蹤剪廉。綜上分析 “Like” 是一個實體娃循。

2.3.2 實體建模

首先,需要明確實體的名稱斗蒋,在這里淮野,我們簡單命名為 Like捧书。

行為建模

分析下 Like 的業(yè)務(wù)行為,Like 對外操作只提供一個 click 方法骤星,當(dāng)觸發(fā) click 操作時,Like 在 Submitted 和 Cancelled 之間進行切換爆哑。當(dāng) Like 狀態(tài)發(fā)生變化時洞难,需要發(fā)布對應(yīng)的內(nèi)部事件。

Like 所涉及的業(yè)務(wù)方法如下:

業(yè)務(wù)方法 含義 事件 業(yè)務(wù)規(guī)則
click 用戶點擊行為
submit 點贊 LikeSubmittedEvent 當(dāng)用戶未點贊時觸發(fā)
cancel 取消點贊 LikeCancelledEvent 當(dāng)用戶已經(jīng)點贊時觸發(fā)

為了避免 Like 的臃腫揭朝,我們將 Like 的狀態(tài)進行單獨建模队贱。構(gòu)建一個單獨的值對象,并將狀態(tài)相關(guān)的操作下推到該值對象中潭袱。我們稱為 LikeStatus柱嫌。

屬性建模

Like 所關(guān)聯(lián)的對象,包括 Target屯换、Owner 和 LikeStatus编丘,并且三者都是值對象。

屬性 類型 含義
owner Owner 點贊發(fā)起者
target Target 點贊目標(biāo)對象
status LikeStatus 點贊狀態(tài)

創(chuàng)建方式建模

Like 的創(chuàng)建方式比較簡單彤悔,沒有太復(fù)雜的業(yè)務(wù)邏輯嘉抓,因此,采用靜態(tài)方法對其進行創(chuàng)建晕窑。

2.3.3 小結(jié)

Like 是一個比較簡單的聚合抑片,具體結(jié)構(gòu)如下:

Like 聚合

贊功能所涉及的對象見下表杨赤。

對象 含義 建模方式
Like 實體&聚合根
LikeStatus 贊狀態(tài) 值對象
LikeSubmittedEvent 點贊事件 內(nèi)部領(lǐng)域事件
LikeCancelledEvent 取消贊事件 內(nèi)部領(lǐng)域事件

2.4 日志功能設(shè)計

Like 代表的是當(dāng)前點贊狀態(tài)敞斋,對于多次點擊植捎,只會記錄最后的結(jié)果,而中間的過程數(shù)據(jù)丟失了说敏。

日志鸥跟,本身不屬于業(yè)務(wù)功能,但對用戶行為分析非常重要盔沫,我們應(yīng)該將用戶的所有操作保存下來医咨。我們稱這些過程數(shù)據(jù)為 LikeLogger。

2.4.1 識別建模類型

日志主要用于記錄誰(Owner)對什么(Target)進行哪個操作(Action)架诞,在創(chuàng)建后就不在改變拟淮。基本符合值對象建模條件谴忧,但很泊,我們?nèi)绾螌ζ溥M行持久化呢角虫?

一般情況下,值對象的持久化依賴于包含它的實體委造,值對象會隨著實體的持久化而持久化戳鹅。但,Logger 是個整體概念昏兆,本身不屬于任何實體枫虏。在這種情況下,我們可以將其建模成一個不變實體爬虱,一來借助實體進行持久化隶债,二來避免對實體的修改。

2.4.2 不變實體建模

LikeLogger 為不變實體跑筝,內(nèi)部所包含的屬性死讹,不允許修改。

屬性建模

LikeLogger 所包含屬性如下:

屬性 類型 含義
owner Owner 點贊發(fā)起者
target Target 點贊目標(biāo)對象
actionType ActionType 操作類型

創(chuàng)建方式建模

LikeLogger 支持 Like 和 Cancel 兩種類型的日志曲梗,可以根據(jù) ActionType 構(gòu)建靜態(tài)方法赞警,以完成各自的創(chuàng)建。

方法 含義
createLikeAction 創(chuàng)建點贊日志
createCancelAction 創(chuàng)建取消點贊日志
2.4.3 小結(jié)

LikeLogger 所涉及對象包括:

對象 含義 建模方式
LikeLogger 贊日志 不變實體
ActionType 操作類型 值對象

2.5 計數(shù)功能設(shè)計

最簡單的計數(shù)功能稀并,便是通過 SQL 對 Like 進行 “count group by” 來完成仅颇,但在高并發(fā)系統(tǒng)中,group by 是一大忌諱碘举。

從單一職責(zé)原則角度忘瓦,Like 承載了過多的責(zé)任,將統(tǒng)計功能強加到服務(wù)于業(yè)務(wù)的 Like 也非常不合適引颈。因此耕皮,我們對計數(shù)功能進行獨立的業(yè)務(wù)建模。 我們稱為 TargetCount蝙场。

2.5.1 識別建模類型

TargetCount 需要根據(jù)點贊和取消點贊對計數(shù)進行增減操作凌停。對于同一個 Target,需要持續(xù)跟蹤其數(shù)量變化售滤》D猓可見,TargetCount 是一個實體完箩。

2.5.2 實體建模

行為建模

TargetCount 的操作赐俗,主要有 incrdecr 兩個業(yè)務(wù)操作。在進行 count 更新時弊知,存在一個業(yè)務(wù)規(guī)則阻逮,及 count 不能小于零。

業(yè)務(wù)方法 含義 事件 業(yè)務(wù)規(guī)則
incr 增加點贊數(shù)
decr 減少點贊數(shù) count 不能小于零

屬性建模

TargetCount 的屬性包括:

屬性 類型 含義
target Target 點贊目標(biāo)對象
count Long 總的點贊數(shù)

創(chuàng)建方式建模

TargetCount 的創(chuàng)建方式比較簡單秩彤,因此叔扼,采用靜態(tài)方法對其進行創(chuàng)建事哭。

2.5.3 小結(jié)

計數(shù)功能所涉及對象包括:

對象 含義 建模方式
TargetCount 點贊目標(biāo)計數(shù) 實體

2.6 用例走查

用例走查,主要從用例角度瓜富,驗證當(dāng)前設(shè)計是否滿足業(yè)務(wù)需要鳍咱。

用例 支持方式
點擊 由 Like 聚合的 click 方法進行支持
是否點贊 由 Like 聚合的 LikeStatus 進行支持
獲取點贊數(shù)量 由 TargetCount 的計數(shù)進行支持

LikeLogger 不直接服務(wù)于業(yè)務(wù),仍舊有很大意義食呻。

2.7 架構(gòu)設(shè)計

到現(xiàn)在流炕,整個系統(tǒng)的核心組件就設(shè)計完成了,接下來仅胞,我們需要將其組裝起來乳幸,以形成一個可用系統(tǒng)拭嫁。

這設(shè)計架構(gòu)前站楚,有幾個非功能性需求需要考慮逻淌。

  • 點擊行為的高并發(fā)
  • 獲取計數(shù)的高并發(fā)
  • Like 與 Logger兆沙、 Count 的數(shù)據(jù)一致性
2.7.1 點擊行為的高并發(fā)

點擊行為是典型的寫操作材鹦,需要對寫操作進行優(yōu)化蔗喂。

對于寫操作優(yōu)化再姑,常見的策略包括:

  • 數(shù)據(jù)散列胳岂。也就是我們常說的分庫分表编整,將寫操作分散到多個數(shù)據(jù)庫實例中,從而提升系統(tǒng)的整體吞吐乳丰。
  • 先入隊列掌测,后臺消費。將用戶請求添加到隊列产园,啟動后臺線程汞斧,從隊列中獲取請求,并挨個消費什燕。這種策略的最大特點就是可以起到消峰的作用粘勒,將瞬間巨大的請求緩存起來,不會對后臺服務(wù)造成很大沖擊屎即。

對于一致性要求高的業(yè)務(wù)場景(比如支付)庙睡,數(shù)據(jù)散列是唯一解決方案;對于一致性要求不高的業(yè)務(wù)場景(比如咱們的點贊系統(tǒng))技俐,隊列方案是最佳解決方案乘陪。

在此,我們使用隊列方案來應(yīng)對點擊行為的高并發(fā)虽另。即用戶提交點擊請求并不會直接調(diào)用業(yè)務(wù)方法暂刘,而是將請求放入消息隊列;后臺消費線程從消息隊列中獲取請求捂刺,并調(diào)用業(yè)務(wù)方法執(zhí)行業(yè)務(wù)邏輯谣拣。

2.7.2 獲取計數(shù)的高并發(fā)

獲取計數(shù)是典型的讀操作募寨,需要對讀操作進行優(yōu)化。

對讀操作的優(yōu)化森缠,主要是使用緩存進行訪問加速拔鹰。我們使用 Redis 來加速訪問。

具體的操作如下:

  • 首先從 Redis 中獲取計數(shù)信息贵涵,如果命中列肢,直接返回
  • 如果 Redis 未命中,從數(shù)據(jù)庫中獲取計數(shù)宾茂,將結(jié)果添加到 Redis 中瓷马,然后返回
  • 當(dāng)計數(shù)發(fā)生變化時,清理 Redis 的過期數(shù)據(jù)
2.7.3 Like 與 Logger跨晴、 Count 的數(shù)據(jù)一致性

在系統(tǒng)中 Like欧聘、Logger、Count 是三個聚合根端盆,我們需要保證三者的數(shù)據(jù)一致性怀骤。

系統(tǒng)的操作入口只有 Like 聚合,當(dāng) Like 發(fā)生變化時焕妙,Logger 和 Count 都需要跟著聯(lián)動起來蒋伦。Like 與 Count、Logger 具有很強的因果關(guān)系焚鹊,這也是領(lǐng)域事件建模的重要信號痕届。

在常規(guī)操作中,我們會在操作 Like 后寺旺,直接調(diào)用 Logger爷抓、Count 相關(guān)接口進行業(yè)務(wù)操作。但在 DDD 中阻塑,是絕對不允許的蓝撇,一個操作只能對一個聚合根進行處理,聚合根之間的同步只能基于事件通過最終一致性解決陈莽。

我們可以基于內(nèi)存總線和內(nèi)部事件渤昌,通過訂閱 Like 相關(guān)事件在內(nèi)存中完成與 Logger、Count 的業(yè)務(wù)同步走搁;也可以使用專用消息隊列和外部事件独柑,完成多個系統(tǒng)間的數(shù)據(jù)同步。

考慮到系統(tǒng)讀寫的擴展性私植,在此忌栅,我們使用消息隊列和外部事件完成數(shù)據(jù)一致性保障。

Like 在執(zhí)行完業(yè)務(wù)操作后曲稼,將內(nèi)部領(lǐng)域事件直接發(fā)布到內(nèi)存總線(EventBus)索绪,Exporter 組件從內(nèi)存總線中獲取領(lǐng)域事件湖员,將其轉(zhuǎn)換為外部事件,并發(fā)送到消息隊列中瑞驱。Consumer 組件負責(zé)從消息隊列中獲取事件娘摔,調(diào)用 Logger、Count 相關(guān)業(yè)務(wù)接口以完成業(yè)務(wù)操作唤反。

2.7.4 小結(jié)

綜上分析凳寺,我們的最終架構(gòu)如下:

還有 80% 的精彩內(nèi)容
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
支付 ¥14.99 繼續(xù)閱讀
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市彤侍,隨后出現(xiàn)的幾起案子肠缨,更是在濱河造成了極大的恐慌,老刑警劉巖盏阶,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怜瞒,死亡現(xiàn)場離奇詭異,居然都是意外死亡般哼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門惠窄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒸眠,“玉大人,你說我怎么就攤上這事杆融±憧ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵脾歇,是天一觀的道長蒋腮。 經(jīng)常有香客問我,道長藕各,這世上最難降的妖魔是什么池摧? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮激况,結(jié)果婚禮上作彤,老公的妹妹穿的比我還像新娘。我一直安慰自己乌逐,他們只是感情好竭讳,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浙踢,像睡著了一般绢慢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洛波,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天胰舆,我揣著相機與錄音骚露,去河邊找鬼。 笑死思瘟,一個胖子當(dāng)著我的面吹牛荸百,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播滨攻,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼够话,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了光绕?” 一聲冷哼從身側(cè)響起女嘲,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诞帐,沒想到半個月后欣尼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡停蕉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年愕鼓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慧起。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡菇晃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蚓挤,到底是詐尸還是另有隱情磺送,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布灿意,位于F島的核電站估灿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏缤剧。R本人自食惡果不足惜馅袁,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞭执。 院中可真熱鬧司顿,春花似錦、人聲如沸兄纺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽估脆。三九已至钦奋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背付材。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工朦拖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厌衔。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓璧帝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親富寿。 傳聞我的和親對象是個殘疾皇子睬隶,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容