打開朋友圈,手指向下滑了幾下,又一“廣告狗”!點(diǎn)擊頭像 ---- 右上角 ---- 設(shè)置朋友圈權(quán)限 ---- 不看他的朋友圈。一套動(dòng)作下來(lái),如行云流水,動(dòng)作利索。再下拉刷新,不到一秒的時(shí)間,廣告沒(méi)了,朋友圈再度一片清新氣象~
慢著,別走!我不是標(biāo)題黨!這就奔主題!!
”不到一秒的時(shí)間“,重新刷新,剛剛屏蔽的消息就沒(méi)了,作為程序猿,當(dāng)然好奇這是如何實(shí)現(xiàn)的,腦海里冒出了一個(gè)問(wèn)題:”微信朋友圈的數(shù)據(jù)是如何存儲(chǔ)和拉取的?“
首先假設(shè)A,B,C,D的關(guān)系如下:
當(dāng)A發(fā)布了一條朋友圈,B評(píng)論了A的朋友圈,來(lái)分析下微信朋友圈的設(shè)計(jì)需求:
-
A發(fā)布的消息誰(shuí)能看?
- A的好友能查看
- 非屏蔽A的好友圈的好友能查看
- 非被A屏蔽的好友能查看
-
B在A的消息中的評(píng)論和贊誰(shuí)能看?
- A和C的共同好友能查看
帶著問(wèn)題,我想到了兩種方案:
方案一:
用最愚蠢的方法,每個(gè)用戶都有一張表來(lái)保存自己的朋友圈的消息,當(dāng)A發(fā)布一條消息時(shí),除了屏蔽的和被屏蔽的的好友,把該消息插入A的所有好友中。同理,評(píng)論和贊都插入A和B的共同好友中。
- 優(yōu)點(diǎn):易實(shí)現(xiàn);查詢快。
- 缺點(diǎn):數(shù)據(jù)量大,如果一個(gè)用戶有幾百的好友,發(fā)布一條消息就得存儲(chǔ)幾百份,單從這點(diǎn),這方案就不可取了。更新數(shù)據(jù)量龐大,如果A把消息刪除了,要通知所有好友刪除... 不愿再想下去了...
方案二:
否定了方案一后,我想到了用索引。每個(gè)用戶的朋友圈是維護(hù)了一條索引鏈和自己發(fā)布的消息表。A發(fā)布了一條消息,保存到自己的消息表中,除了屏蔽的和被屏蔽的的好友,把該消息的索引插入所有好友的索引鏈中。當(dāng)如C打開朋友圈時(shí),C按照索引從每個(gè)好友的消息表中拉取數(shù)據(jù)。同理,評(píng)論和贊也如此。
- 優(yōu)點(diǎn):相對(duì)方案一,數(shù)據(jù)量明顯減少。
- 缺點(diǎn):查詢慢,每次刷新都從好友的表中查詢,如果有幾百個(gè)好友,是不可能做到”不到一秒時(shí)間“的!
因?yàn)楫?dāng)時(shí)是憑空想的,當(dāng)然很多細(xì)節(jié)都沒(méi)考慮到,但看上去好像能這樣實(shí)現(xiàn),只是不可取而已。其中大家可以注意到我加粗的文字,我犯了一個(gè)錯(cuò)誤:把除了屏蔽的和被屏蔽的的好友與其他好友區(qū)分開來(lái),從而導(dǎo)致了數(shù)據(jù)存儲(chǔ)和加載的復(fù)雜度大大提高。我要考慮屏蔽或取消屏蔽時(shí)服務(wù)器如何處理消息與用戶的關(guān)系,并如何通知客戶端更新等等問(wèn)題,結(jié)果想的東西越來(lái)越復(fù)雜,各種數(shù)據(jù)縱橫交錯(cuò),自己都不敢再想下去了。因?yàn)橐坏?fù)雜了就是錯(cuò)誤的!這句話其實(shí)是我的好友跟我說(shuō)的:”編程時(shí),如果一個(gè)問(wèn)題你覺(jué)得很復(fù)雜,那就永遠(yuǎn)無(wú)法解決。”
其實(shí)不但是編程,任何事情都這樣,如果你先入為主地認(rèn)為它復(fù)雜,到最后你肯定解決不了這件事情。并且,如果你處理事情時(shí),使用的方法越來(lái)越復(fù)雜,這個(gè)方法肯定是錯(cuò)誤或愚蠢的!肯定有更好的方法可以優(yōu)雅地解決問(wèn)題。
但由于我的能力和知識(shí)有限,并想不出更好的方案來(lái)處理朋友圈的數(shù)據(jù)存儲(chǔ)和拉取問(wèn)題,哈哈。但我會(huì)查閱資料。直到我看到了下面這篇文章才恍然大悟,果然,很優(yōu)雅!很簡(jiǎn)單!!
看了上面的文章后,我自己也整理了一遍:
下面對(duì)上圖分析下:
關(guān)系:
A,B,C互相為好友,A與D為好友。
核心表:
- 發(fā)布表:所有用戶共用(注意,公用不代表存儲(chǔ)在同一個(gè)服務(wù)器)
- 相冊(cè)表:每個(gè)用戶都有自己獨(dú)立的相冊(cè)
- 評(píng)論或贊表:所有用戶共用,跟發(fā)布表是多對(duì)一的關(guān)系
- 時(shí)間線表:每個(gè)用戶都有自己獨(dú)立的時(shí)間線,也就是朋友圈啦
流程:
- 假設(shè)A發(fā)布了一條朋友圈,服務(wù)器會(huì)做兩件事:
- 把該消息存儲(chǔ)到發(fā)布表中
把消息插入每個(gè)好友的時(shí)間線上,不區(qū)分屏蔽或被屏蔽的好友。
B評(píng)論或贊了A的朋友圈,服務(wù)器也是做兩件事:
- 把該評(píng)論或贊存儲(chǔ)到評(píng)論表或贊表中
關(guān)聯(lián)對(duì)應(yīng)的消息(其實(shí)這步在1中做了,為了更清晰分開講)
C和D打開朋友圈
- 根據(jù)C的時(shí)間線向發(fā)布表請(qǐng)求數(shù)據(jù)
- 如果是共同好友,加載評(píng)論和贊,否則不加載
整個(gè)流程下來(lái),邏輯非常清晰,思路非常簡(jiǎn)單!當(dāng)然,實(shí)際的設(shè)計(jì)不會(huì)這么簡(jiǎn)單,還有很多細(xì)節(jié),如數(shù)據(jù)緩存,服務(wù)器部署等等要考慮和處理,這里只是簡(jiǎn)述了基本的工作流程而已。
相信聰明的你已注意到,上面的文章根本就沒(méi)討論屏蔽與非屏蔽的問(wèn)題,不是忘了,而是沒(méi)必要。后面我想了想,因?yàn)橄⒒蛴押梦覀兛梢赃x擇屏蔽或取消屏蔽,如果每次操作都要通知服務(wù)器進(jìn)行增刪,那效率不是很低?!所以應(yīng)該是消息都會(huì)存儲(chǔ)到每個(gè)用戶的時(shí)間線上(這點(diǎn)我應(yīng)該早點(diǎn)想到的...),至于是服務(wù)器查詢時(shí)跳過(guò)屏蔽的消息,還是客戶端選擇性顯示就不得而知了。
由于本人是搞客戶端的,后端的技術(shù)我也不會(huì)哈哈,上面的內(nèi)容只是突然好奇的所思與所想,所以難免會(huì)有錯(cuò)誤的論述。若有錯(cuò),歡迎指正。
低頭看下表,從開始想這個(gè)問(wèn)題到寫完這篇文章,用了5個(gè)有多的小時(shí),如果覺(jué)得有幫助或有趣的話,點(diǎn)下紅心唄~