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