Java架構直通車——點贊功能用Mysql還是Redis?

引入

最近遇到一個需求,就是做聯盟鏈做存證上,部分交易對外公開,或者是對指定人可見。之前一直在思考用Mysql怎麼存合適,想來想去也沒找出個合適的辦法。
點贊功能場景和上面的需求是一樣的,我就借這個簡單一些的點贊功能來理清下思路把。

我們先看點贊功能的需求:

  • 顯示點贊數量
  • 判斷用戶是否點過贊,用於去重,必須的判斷
  • 顯示個人點贊列表,一般在用戶中心
  • 顯示微博/文章的點贊列表

在這裏插入圖片描述
微博這是頭部的頂級流量,後端肯定是有複雜架構的,我們今天暫時只討論大衆化的方案。

使用Mysql實現點贊功能

採用mysql做點贊功能的記錄的話,一般是要三個表:

  1. 用戶表。
  2. 文章表。
  3. 用戶-文章關聯表(點贊表)。

那麼點贊功能常用的查詢就是:

  • 查詢某一篇文章的點讚的用戶:
    select user_id from star where post_id=?
  • 查詢某一用戶點贊過的文章:
    select post_id from star where user_id=?

雖然我們這裏討論的是大衆化的方案,但不是說的數據量小,只是說的架構簡單。

我們思考下,如果使用單表查詢,一個表肯定是支撐不住的,即使建立了兩個索引數據庫表的壓力也是很大的。
這時只能考慮分庫分表,那麼怎麼分表成爲了一個難題:是按照用戶id分還是文章id分呢?因爲不用的查詢,有時涉及到分表後的單表,有時涉及到多表。這樣Hash起來是有衝突的
那麼只能考慮做兩個分表的冗餘,不過這增加了存儲空間和維護工作量,還可能有一致性問題。

所以,使用mysql來做點贊功能,不是很好。

使用Redis實現點贊功能

由於點贊這種動作很隨意,很多人看到大拇指就想點,所以數據量增長很快,數據規模上來後,對mysql讀寫都有很大的壓力,這時就要考慮redis了。

採用redis有兩種用途,一種是storage,一種是cache

使用什麼數據格式最合適?

Redis具有豐富的數據類型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。

在這裏插入圖片描述

Redis 內部使用一個 redisObject 對象來表示所有的 key 和 value。type 表示一個 value 對象具體是何種數據類型,encoding 是不同數據類型在 Redis 內部的存儲方式。

比如:type=string 表示 value 存儲的是一個普通字符串,那麼 encoding 可以是 raw 或者 int。

  • String 是 Redis 最基本的類型,一個 Key 對應一個 Value。Value 不僅是 String,也可以是數字,也可以是對象的序列化。
  • Hash是一個鍵值(key-value)的集合。Redis 的 Hash 是一個 String 的 Key 和 Value 的映射表,Hash 特別適合存儲對象。
  • List,List 列表是簡單的字符串列表,按照插入順序排序。Redis 提供了 List 的 Push 和 Pop 操作,還提供了操作某一段的 API,可以直接查詢或者刪除某一段的元素。
  • Set和ZSet不做贅述。當你需要一個有序的並且不重複的集合列表,那麼可以選擇 Sorted Set 結構。

我們可以看到使用點贊列表,最合適的方式還是Hash或者List了。如果需要記錄點贊人和被點贊人,還有點贊狀態(點贊、取消點贊),還要固定時間間隔取出 Redis 中所有點贊數據,使用Hash能夠保存key和value,算是更合適的了。

關於底層編碼的實現方案,我以後的文章會做介紹。

方案


  • 使用redis作爲storage的方案:

場景a :顯示點贊數量
在點讚的地方,只是顯示一個點贊數量,能區分用戶是否點贊過,一般用戶不關心這個列表,這個場景只要一個數字就可以了,當數量比較大時,一般顯示爲"7k" ,“10W” 這樣。

以文章id爲key。

//以文章id=888爲例 
127.0.0.1:6379[2]> set star:tid:888 898 //設置點贊數量 
OK 
127.0.0.1:6379[2]> incr star:tid:888 //實現數量自增 (integer) 
899

場景b:點贊去重,避免重複點贊
要實現這個需求,必須有文章點讚的uid列表,以tid爲key。

場景c:一般在用戶中心,可以看到用戶自己的點贊列表
這個需求和上面的差不多。

場景d:文章的點贊列表
類似場景b,以文章id爲key。

//以文章id=888爲例 
127.0.0.1:6379[2]> sadd star:list:tid:888 123 456 789  //點贊uid列表 (integer) 
3 
127.0.0.1:6379[2]> sismember star:list:tid:888 456  //判斷是否點贊 (integer) 
1

redis作爲storage使用時,一定要做好數據的持久化,必須開啓 rdb 和 aof,這會導致業務只能使用一半的機器內存,所以要做好容量的監控,及時擴容。


  • 使用redis做爲cache的方案:

基於 SpringCloud, 用戶發起點贊、取消點贊後先存入 Redis 中,再每隔兩小時從 Redis 讀取點贊數據寫入數據庫中做持久化存儲。

這一點,以後有機會再做詳細介紹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章