redis儲存微博按讚的人,如何儲存?
怪我咯
怪我咯 2017-04-22 08:59:23
0
3
1106

比如說有一個微博的TID是1。 UID為1,2,3,4,5,6,7,8,9的用戶都給這個微博點讚了。用redis緩存框架存儲的話如何存儲。微博可能有幾十萬個。如果用

key->set(value) 這種形式的話 key是微博ID的標示 value是 [1,2,3,4,5,6,7,8,9]這種形式,這樣的話有多少個微博就有多少個K-V存儲。我想知道這樣會有什麼弊端嗎?或者有什麼更好的方法嗎?

怪我咯
怪我咯

走同样的路,发现不同的人生

全部回覆(3)
刘奇

可以採用多個HashSet儲存。每一條微博只是HashSet內的一個子key。增加讚的數量可以採用HIncrBy命令。把TID分塊,使得每個HashSet內的key不超過100個。官方文件表示HashSet在內部元素小於一百個的時候採用線性儲存與掃描,跟同資料規模下樹狀結構相比效率更高,更省記憶體。

例如:TID為123456的微博存在z:1234的HashSet中,其key為56。假設最新的微博活躍程度也較高,那麼絕大多數情況下被呼叫的HashSet只有區區幾個,對CPU的快取很友善。

如果要管理讚的用戶,可以自訂資料格式。在用戶數量少的時候把用戶列表整個內嵌到HashSet的值域中。用戶超過例如50人後單獨整理出一個Set,在HashSet裡保存Set的key。例:

bash# 内嵌UID的情况
hget z:1234 56
> "1,2,3,4"...

# 使用set的情况
hget z:1234 56
> "UIDlist:10"
smembers UIDlist:10
> 1) "1"
> 2) "2"
> ...

由於絕大多數微博讚的用戶均比較少,HashSet可以節省出不少全域空間的key(全域key比HashSet的key更耗記憶體)。

關於 @賣掉內褲去上網 的回答:
若採用in-place quicksort,50個用戶的手動排序效率非常高,因為在這個資料規模下資料緊密存放帶來的快取友善度遠勝於Redis ZSet相對於手動排序帶來的提升。而讚的用戶升上去後就會自動適應成set或zset,確保演算法時間複雜度。如果還擔心效率,可以把排序好的UID清單重新寫回HashSet的一個value中,以後沒有資料改變的話直接使用。

究竟採用set還是zset還是要看樓主的需求。 set加入一個成員的複雜度為O(1),zset是O(log N),但set就沒有排序功能了。

大家讲道理

不太推薦LS用HASH來儲存按讚的資料. 因為沒辦法進行排序(如果需要的話. 我想一定需要)

目前 我們是這樣處理的.

可以使用ZSET有序集合進行存儲. 理論上說一個ZSET中, 10W以內的數量並無任何鴨梨. 也就是說一條微博點讚的人數再10W以內(這是不可能的).

php$redis->ZADD("t:$tid:liked", time(), $uid); //$tid 为你的微博ID, $uid 为你的点赞人的UID


//取出点赞的人(支持按照点赞时间来排序的哦:)).. 按照LSD的说的 HASH取出来的值没有任何顺序的.
$uids = $redis->ZREVRANGE("t:$tid:liked", $offset, $max, TRUE); //倒序取值
$uids = $redis->ZRANGE("t:$tid:liked", $offset, $max, TRUE); //顺序取值

//$offset 和 $max 这样来算
$pagesize = 20;
$offset = ($page > 1) ? ($page - 1) * $pagesize : 0;
$max = ($page * $pagesize) - 1;

//一次性取出所有的这样取.
$total = $redis->ZCARD("t:$tid:liked");
$uids = $redis->ZREVANGE("t:$tid:liked", 0, $total - 1, TRUE);

//拿到的$uids 是一个array 哦..

//判断一个用户是否点赞了这一来哦
$redis->ZSCORE("t:$tid:liked", $uid);
//取消赞这样来
$redis->ZREM("t:$tid:liked", $uid);

//批量取消某短时间内的点赞这样操作
$redis->ZREMRANGEBYSCORE("t:$tid:liked", $start_timestamp, $end_timestamp);

//诸如此类的操作, 要比HASH强很多. 

恩再PS一下!!!

如果需要用到NOSQL這樣的資料庫來儲存類似微博的資料的話, 可以這樣儲存:).

php$pipe = $redis->MULTI(Redis::PIPELINE);
$pipe->SET("t:$tid", json_encode($data)) //json这种格式存储貌似有点废物. 如果能想到更好的格式的话,不要用JSON, 因为JSON太大了.. 比如MSGPACK这个个是就比JSON要好很多
     ->ZADD("t:scores", time(), $tid);
$pipe->EXEC();

//PIPE 这样的操作赞爆了. 如果你的REDIS支持事务的话, PIPE就不是一个原子性的操作了

//取出数据的话就很好取出了!! 
$tid = $reids->ZREVRANGE("t:scores", 0, 100);
$pipe = $redis->MULTI(Redis::PIPELINE); 
foreach($tid as $key=> $value){
    $pipe->GET("t:$value");
}
$list = $pipe->EXEC();

//$list就是你的数据啦

再PS一下, 微博評論也是類似的儲存方法. 只是需要約定$redis KEYS的名稱. 例如:
c: 怎麼跟微博資料關聯起來可以這樣:

t:$tid:comments:scores (ZSET timestmap 評論ID);

這樣取資料的時候就用PIPELINE方便很多了.

最後囉嗦一句, NOSQL這種資料庫的 KEY 一定要設定好.

刘奇
  1. 保存每個uid是否有必要,還是你覺得新浪微博就是這麼搞的?大多數情況,其實大家只是專注在一個數字,如果這樣的話,那麼用一個數字來儲存就可以了{tid->count}

  2. 如果要保存,建議還是用{tid->set(uid)}來保存

  3. 有個優化就是你可以設定一個閾值,比如超過100人點贊,就不再往裡面加東西了,而僅僅加一個數字(當然這裡需要你再存一個{tid->count})。因為超過1w的微博點贊,沒人回去逐一把每個點讚的人都點開的。 。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板