在Golang中使用Redis的方法示例
周五上班的主要任務(wù)是在公司老平臺上用redis處理一個隊(duì)列問題,順便復(fù)習(xí)了一下redis操作的基礎(chǔ)知識,回來后就想著在自己的博客demo里,用redis來優(yōu)化一些使用場景,學(xué)習(xí)一下golang開發(fā)下redis的使用。
Redis簡單介紹
簡介
關(guān)于Redis的討論,其實(shí)在現(xiàn)在的后臺開發(fā)中已經(jīng)是個老生常談的問題,基本上也是后端開發(fā)面試的基本考察點(diǎn)。其中 Redis的背景介紹和細(xì)節(jié)說明在這里就不贅述。不管怎么介紹,核心在于Redis是一個基于內(nèi)存的key-value的多數(shù)據(jù)結(jié)構(gòu)存儲,并可以提供持久化服務(wù)?;趦?nèi)存的特性決定了Redis天然適合高并發(fā)的數(shù)據(jù)讀寫緩存優(yōu)化,同時也帶來了內(nèi)存開銷過大的問題。所以在一些特定情景下,Redis是一把無往不利的大殺器,值得深入學(xué)習(xí)。
學(xué)習(xí)Redis的一個難點(diǎn)或者說入門點(diǎn),我個人感覺在于對象存儲理念的轉(zhuǎn)變。剛接觸 Redis 時,我剛從大學(xué)畢業(yè),腦子里基本都是關(guān)系型數(shù)據(jù)存儲的理念,使用時總想著靠數(shù)據(jù)內(nèi)的關(guān)系來建立數(shù)據(jù)之間的聯(lián)系,用起來很不順手。后來慢慢入門了才感受到了一些操作的好處。舉個栗子,比如查詢用戶在某個文章下的評論,用 sql 的思路就是搜索評論表里面用戶ID和文章ID匹配的數(shù)據(jù),有時還需要聯(lián)合查詢出其他信息,但是如果是 Redis 操作,以'前綴:文章ID:用戶ID'為key,比如'comment:666:888'就可以快速取出用戶評論,十分方便。 Redis 的強(qiáng)大遠(yuǎn)不僅如此,可以在實(shí)踐中慢慢體會。
主要數(shù)據(jù)結(jié)構(gòu)
Redis主要有五種基本數(shù)據(jù)結(jié)構(gòu),滿足了絕大多數(shù)緩存結(jié)構(gòu)的需要,如果你在使用一種結(jié)構(gòu)存儲時感覺別扭時,很有可能是選錯了存儲結(jié)構(gòu),可以考慮一下其他結(jié)構(gòu)的正確實(shí)現(xiàn)。
- String ,可以是字符串、整數(shù)和浮點(diǎn)數(shù)。如果是序列化數(shù)據(jù),并涉及到修改操作的話,不推薦用 string ,可以考慮用 Hash
- Hash, key-value 對象,可以存放對象數(shù)據(jù),比如用戶信息之類。
- List,有序數(shù)據(jù)集合,元素可以重復(fù),用
LPUSH
、LPOP
、RPUSH
、RPOP
等指令組合可以實(shí)現(xiàn)棧和隊(duì)列操作。 - Set,無序集合,元素唯一。
- Sorted Set,Sort的有序版,可以設(shè)定 Score 值來決定元素排序,適合用戶排名這樣的業(yè)務(wù)場景。
常見使用場景
- 高并發(fā)下數(shù)據(jù)緩存。 比如在某個場景下,大量日志同時寫入數(shù)據(jù)庫會給服務(wù)器帶來巨大壓力,這時可以先將數(shù)據(jù)寫入 redis 中,再由 redis 寫入數(shù)據(jù)庫,減輕同時寫入壓力。
- 熱點(diǎn)信息快速顯示。假設(shè)現(xiàn)在有一個新聞首頁,需要快速顯示各欄目前20條熱點(diǎn)新聞,如果直接查詢數(shù)據(jù)庫,在大量用戶同時訪問下,會消耗極大數(shù)量的數(shù)據(jù)庫請求。這時就可以用 redis 來優(yōu)化,在新聞錄入的時候?qū)?biāo)題、時間和來源寫入 redis 中,客戶端訪問時,可以從內(nèi)存中一次性取出當(dāng)天熱單新聞列表,極大地提高請求速度和節(jié)約了服務(wù)器開銷。
- 保存會話信息??梢詫⒌卿浐笥脩粜畔⒕彺嫒?redis 并同時設(shè)置 key 過期時間,這樣后臺 api 過濾請求時,就可以從內(nèi)存中讀取用戶信息,而且 redis 的過期機(jī)制,天然支持用戶身份有效期校驗(yàn),用起來十分方便。
- 統(tǒng)計(jì)計(jì)數(shù)。比如系統(tǒng)中常見一個功能是限制同一用戶固定時間段內(nèi)的登錄次數(shù)或者所有請求次數(shù),這時就可以以用戶id為key,次數(shù)值為value,將計(jì)數(shù)信息緩存起來,并且有 INCRBY 命令原生支持。
- 其他。Redis的應(yīng)用場景十分廣發(fā),隊(duì)列、發(fā)布訂閱、統(tǒng)計(jì)分析等等,可以看看其他文章的介紹說明。
Golang連接Redis
使用 Golang 開發(fā)的一大直觀感受就是,基本上你日常遇到的開發(fā)問題,都有官方或者第三方包幫你輔助實(shí)現(xiàn),同時這些包都是開源的,只要你感興趣,都可以深入到包的內(nèi)部實(shí)現(xiàn)去學(xué)習(xí)理解包的實(shí)現(xiàn)思路和方法。當(dāng)然這也有利有弊,第三包的不穩(wěn)定和質(zhì)量參差不齊也增加了一些開發(fā)成本,目前還是感受利大于弊。研究好的包源碼實(shí)現(xiàn),也是目前我的一個學(xué)習(xí)方向。
garyburd/redigo 包簡介
garyburd/redigo
包是網(wǎng)上很多博文都在推薦使用的一個高Star的 Redis 連接包,但是當(dāng)我自己去 Github 的項(xiàng)目地址 garyburd/redigo 上查看 API 時,發(fā)現(xiàn)這個項(xiàng)目目前是歸檔狀態(tài),項(xiàng)目已經(jīng)遷移到了 gomodule/redigo ,同時包的獲取也理所當(dāng)然地改成了 go get github.com/gomodule/redigo/redis
,這已經(jīng)不是我第一次感受了第三方包的不穩(wěn)定,之前用 dep 進(jìn)行包管理時,就遇到過 dep 拉取的包版本和本地包版本 API 沖突的問題,這個有時間單獨(dú)再說??傊瑫簳r不管這兩個包的詳細(xì)區(qū)別,以下就以新包為準(zhǔn),介紹下 redigo 包使用。
建立連接池
Redigo Pool 結(jié)構(gòu)維護(hù)一個 Redis 連接池。應(yīng)用程序調(diào)用 Get 方法從池中獲取連接,并使用連接的 Close 方法將連接的資源返回到池中。一般我們在系統(tǒng)初始化時聲明一個全局連接池,然后在需要操作 redis 時獲得連接,執(zhí)行指令。
pool := &redis.Pool{ MaxIdle: 3, /*最大的空閑連接數(shù)*/ MaxActive: 8, /*最大的激活連接數(shù)*/ Dial: func() (redis.Conn, error) { c, err := redis.Dial("tcp", '鏈接地址,例如127.0.0.1:6379', redis.DialPassword('密碼')) if err != nil { return nil, err } return c, nil } } c:=pool.Get() defer c.Close()
執(zhí)行指令
查看源碼,發(fā)現(xiàn) Conn
接口有一個執(zhí)行 Redis 命令的通用方法:
``` //gomodule/redigo/redis/redis.go // Conn represents a connection to a Redis server. type Conn interface { // Close closes the connection. Close() error // Err returns a non-nil value when the connection is not usable. Err() error // Do sends a command to the server and returns the received reply. Do(commandName string, args ...interface{}) (reply interface{}, err error) // Send writes the command to the client's output buffer. Send(commandName string, args ...interface{}) error // Flush flushes the output buffer to the Redis server. Flush() error // Receive receives a single reply from the Redis server Receive() (reply interface{}, err error) } ```
http://redis.io/commands 中的 Redis 命令參考列出了可用的命令。 do 的參數(shù)和 redis-cli 命令參數(shù)格式一致,比如 SET key value EX 360
對應(yīng)函數(shù)調(diào)用為 Do("SET", "key", "value","EX",360)
,常用的命令示例有:
c:=pool.Get() defer c.Close() //存值, _, err := c.Do("SET", "key", "value") //設(shè)置過期時間 _, err := c.Do("SET", "key", "value","EX",360) //存int _, err := c.Do("SET", "key", 2) //取值 v,err:=redis.String(c.Do("GET","key")) bytes, err := redis.Bytes(c.Do("GET", "key"))
總結(jié)
golang 中連接使用 redis 相對比較簡單,所以暫時也沒什么其他好說的,如果后面自己使用過程中發(fā)現(xiàn)有遺漏再進(jìn)行補(bǔ)充,關(guān)鍵還是在于熟悉 redis-cli
原生的指令操作。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Go Resiliency庫中timeout實(shí)現(xiàn)原理及源碼解析
Go-Resiliency庫中的timeout是一種基于協(xié)程的超時機(jī)制,通過創(chuàng)建協(xié)程來執(zhí)行任務(wù)并設(shè)置超時時間,若任務(wù)執(zhí)行時間超時則中止協(xié)程并返回錯誤,需要詳細(xì)了解可以參考下文2023-05-05golang實(shí)現(xiàn)簡單工廠、方法工廠、抽象工廠三種設(shè)計(jì)模式
這篇文章介紹了golang實(shí)現(xiàn)簡單工廠、方法工廠、抽象工廠三種設(shè)計(jì)模式的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04Go語言基本的語法和內(nèi)置數(shù)據(jù)類型初探
這篇文章主要介紹了Go語言基本的語法和內(nèi)置數(shù)據(jù)類型,是golang入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-10-10Golang處理gRPC請求/響應(yīng)元數(shù)據(jù)的示例代碼
前段時間實(shí)現(xiàn)內(nèi)部gRPC框架時,為了實(shí)現(xiàn)在服務(wù)端攔截器中打印請求及響應(yīng)的頭部信息,便查閱了部分關(guān)于元數(shù)據(jù)的資料,因?yàn)橹形木W(wǎng)絡(luò)上對于該領(lǐng)域的信息較少,于是在這做了一些簡單的總結(jié),需要的朋友可以參考下2024-03-03go語言實(shí)現(xiàn)Elasticsearches批量修改查詢及發(fā)送MQ操作示例
這篇文章主要為大家介紹了go語言實(shí)現(xiàn)Elasticsearches批量修改查詢及發(fā)送MQ操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04自己動手用Golang實(shí)現(xiàn)約瑟夫環(huán)算法的示例
這篇文章主要介紹了自己動手用Golang實(shí)現(xiàn)約瑟夫環(huán)算法的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12詳解golang中的結(jié)構(gòu)體編解碼神器Mapstructure庫
mapstructure是GO字典(map[string]interface{})和Go結(jié)構(gòu)體之間轉(zhuǎn)換的編解碼工具,這篇文章主要為大家介紹一下Mapstructure庫的相關(guān)使用,希望對大家有所幫助2023-09-09