redis實現訊息佇列

2021-07-22 19:21:54 字數 2788 閱讀 4990

用redis實現乙個訊息通知系統,總結了一下技術細節,其中演示**如果沒有特殊說明,使用的都是phpredis擴充套件來實現的。

記憶體 比如要推送一條全域性訊息,如果真的給所有使用者都推送一遍的話,那麼會占用很大的記憶體,實際上不管粘性有多高的產品,活躍使用者同全部使用者比起來,都會小很多,所以如果只處理登入使用者的話,那麼至少在記憶體消耗上是相當划算的,至於未登入使用者,可以推遲到使用者下次登入時再處理,如果使用者一直不登入,就一了百了了。

佇列 當大量使用者同時登入的時候,如果全部都即時處理,那麼很容易就崩潰了,此時可以使用乙個佇列來儲存待處理的登入使用者,如此一來頂多是反應慢點,但不會崩潰。

redis的list資料型別可以很自然的建立乙個佇列,**如下:

<?php

class

redisclient

extends

redis

public

function

zrevpop

($zset)

private

function

zsetpop

($zset, $position)

if ($this->multi()->zrem($zset, $element[0])->exec())

return

$this->zsetpop($zset, $position);

}}?>

模擬實現了pop操作後,我們就可以使用zset實現佇列了,**如下:

<?php

$redis = new redisclient;

$redis->connect('/tmp/redis.sock');

$redis->zadd('msg', , );

while ($msg = $redis->zrevpop('msg'))

?>

推拉

以前微博架構中推拉選擇的問題已經被大家討論過很多次了。實際上訊息通知系統和微博差不多,也存在推拉選擇的問題,同樣答案也是類似的,那就是應該推拉結合。具體點說:在登陸使用者獲取訊息的時候,就是乙個拉訊息的過程;在把訊息傳送給登陸使用者的時候,就是乙個推訊息的過程。

速度 假設要推送一百萬條訊息的話,那麼最直白的實現就是不斷的插入,**如下:

<?php

for ($msgid = 1; $msgid

<= 1000000; $msgid )

?>

redis的速度是很快的,但是借助pipeline,會更快,**如下:

<?php

for ($i = 1; $i

<= 100; $i )

$redis->exec();

}?>

說明:所謂pipeline,就是省略了無謂的折返跑,把命令打包給服務端統一處理。

前後兩段**在我的測試裡,使用pipeline的速度大概是不使用pipeline的十倍。

查詢 我們用redis命令列來演示一下使用者是如何查詢訊息的。

先插入三條訊息,其分別是1,2,3:

redis> hmset

msg:1

title

title1

content

content1

redis> hmset

msg:2

title

title2

content

content2

redis> hmset

msg:3

title

title3

content

content3

再把這三條訊息傳送給某個使用者,其是123:

redis> sadd

usr:123

:msg 1

redis> sadd

usr:123

:msg 2

redis> sadd

usr:123

:msg 3

此時如果簡單查詢使用者有哪些訊息的話,無疑只能查到一些:

redis> smembers usr:123:msg

1) "1"

2) "2"

3) "3"

如果還需要用程式根據再來一次查詢無疑有點低效,好在redis內建的sort命令可以達到事半功倍的效果,實際上它類似於sql中的join:

redis> sort usr:123:msg get msg:*->title

1) "title1"

2) "title2"

3) "title3"

redis> sort usr:123:msg get msg:*->content

1) "content1"

2) "content2"

3) "content3"

sort的缺點是它只能get出字串型別的資料,如果你想要多個資料,就要多次get:

redis> sort usr:123:msg get msg:*->title get msg:*->content

1) "title1"

2) "content1"

3) "title2"

4) "content2"

5) "title3"

6) "content3"

很多情況下這顯得不夠靈活,好在我們可以採用其他一些方法平衡一下利弊,比如說新加乙個字段,冗餘儲存完整訊息的序列化,接著只get這個欄位就ok了。

redis實現訊息佇列

模擬生產者 消費者 生產者 往list資料型別中放入key為product的資料 public static void main string args 消費者 使用堵塞命令實時獲取product的資料 public static void main string args catch except...

redis 實現訊息佇列

redis 實現訊息佇列 測試 component public class timetask object obj null for int i 0 i 10 i 封裝redis工具類 slf4j component public class redisutil catch exception e...

Redis實現訊息佇列

佇列本身其實是個有序的列表,而redis是支援list的,可以利用redis的列表 list 來實現簡單佇列。一般有兩種方式 1 lpush 頭部插入 和rpop 尾部彈出 2 rpush 尾部插入 和lpop 頭部彈出 兩種均可,下面示例使用的是 第一種 lpush和rpop。一般開發的時候我們會...