可以利用redis的list結構來實現消息隊列功能,使用lpush、rpush來實現入隊,lpop、rpop來實現出隊列。
我們統一從左邊push、從右邊pop,即用lpush和rpop組合。
當list中沒有元素時,rpop會返回nil,這樣我們需要不斷用輪詢隊列,直到隊列中有元素,然後pop出來。
爲了避免不斷輪詢帶來的性能損耗,我們這裏使用brpop命令,brpop使用了系統提供的阻塞原語,在隊列中沒有元素時,就會一直阻塞或者超出設置時間返回,當隊列中有元素時,會執行rpop命令並返回。
- Push
list的lpush支持單個或者多個元素的push,爲了編寫更通用的方法,我們實現批量push的功能
import "github.com/garyburd/redigo/redis"
func BatchPushQueue(queueName string, keys []string) (err error) {
if len(keys) == 0 {
return
}
con := pool.Get()
defer con.Close()
_, err = con.Do("lpush", redis.Args{}.Add(queueName).AddFlat(keys)...)
return
}
- Pop
brpop會一致阻塞住直到隊列中有元素,但是它支持設置timeout,當阻塞時間超過timeout時,pop會返回nil。當timeout設置爲0時,表示阻塞時間無限制。
brpop支持監聽多個list,因此它有兩個返回值,第一個返回值是list的名稱,即key的名稱,第二個返回值是pop出來的元素。我們只是監聽一個list,因此我們會取返回值中的第二個元素。
//timeout is seconds which command 'brpop' will block when queue is empty.
func PopQueue(queueName string, timeout int) (data string, err error) {
con := pool.Get()
defer con.Close()
nameAndData, err := redis.Strings(con.Do("brpop", queueName, timeout))
if err != nil {
if err == redis.ErrNil {
err = nil
return
}
return
}
if len(nameAndData) > 1 {
data = nameAndData[1]
}
return
}