上回寫了使用Redis實現(xiàn)關(guān)注關(guān)系,這次說說使用Redis實現(xiàn)Timeline。
Timeline的實現(xiàn)一般有推模式、拉模式、推拉結(jié)合這幾種。
推模式:某人發(fā)布內(nèi)容之后推送給所有粉絲,空間換時間,瓶頸在寫入;
拉模式:粉絲從自己的關(guān)注列表中讀取內(nèi)容,時間換空間,瓶頸在讀??;
推拉結(jié)合:某人發(fā)布內(nèi)容后推送給活躍粉絲
,不活躍粉絲則使用拉取。
目前只討論推模式,考慮單個feed內(nèi)容實體存入散列(hashes)、每個用戶的timeline列表存入列表(lists)。
1、發(fā)布
發(fā)布者發(fā)布內(nèi)容后,生成唯一feedID,以feedID為key存入hashes。
首先從發(fā)布者的粉絲表里獲取所有粉絲,再進(jìn)行推送。
邏輯如下:
// 使用Redis INCR操作,生成唯一postID
$feedID = $redis->INCR("global:postID");
// 存入Hashes
$feedData = [
'userID' => 1,
'timestamp' => '1458680000',
'content' => '這是一條tweet',
'platform' => 'web',
];
$redis->HSET($feedID, $feedData);
// 寫入發(fā)布者自己的已發(fā)布列表
$redis->LPUSH("{$userID}:tweets", $feedID);
// 寫入發(fā)布者自己的timeline
$redis->LPUSH("{$userID}:timeline", $feedID);
// 獲取發(fā)布者粉絲列表
$follwerIDs = $redis->SMEMBERS("1:followers");
// 寫入
foreach ($follwerIDs as $followerID) {
$redis->LPUSH("{$followerID}:timeline", $feedID);
}
2、讀取
某用戶登陸之后,獲取timeline Lists中的值,再從Hashes取數(shù)據(jù)進(jìn)行處理。
$feedIDs = $redis->LRANGE("{$userID}:timeline", 0, 30); //取30條數(shù)據(jù)
foreach ($feedIDs as $feedID) {
$feedData = $redis->HGETALL($feedID);
// TODO:進(jìn)一步進(jìn)行處理、整合等操作。
}
3、刪除
當(dāng)發(fā)布者刪除某條消息后,循環(huán)所有粉絲列表,并執(zhí)行刪除操作。
// 從發(fā)布者自己的已發(fā)布刪除掉
$redis->LREM("{$userID}:tweets", 1, $feedID);
// 從發(fā)布者自己的timeline刪除掉
$redis->LREM("{$userID}:timeline", 1, $feedID);
// 獲取發(fā)布者粉絲列表
$follwerIDs = $redis->SMEMBERS("1:followers");
// 刪除
foreach ($follwerIDs as $followerID) {
$redis->LREM("{$followerID}:timeline", 1, $feedID);
}
timeline從某種角度來說是臨時性的,如果年代久遠(yuǎn),可不必操作粉絲的timeline。
后記
Timeline系統(tǒng)說起來會很復(fù)雜,也不可能只靠Redis去實現(xiàn)。本文只是一個大體的思路,應(yīng)對小數(shù)據(jù)量基本足夠。
博客:http://blog.lovemydeer.com/2016/03/19/redis-timeline.html