云開(kāi)發(fā) 連接Redis數(shù)據(jù)庫(kù)

2020-07-21 17:55 更新

Redis 是一個(gè)開(kāi)源高性能基于key-value的NoSQL 數(shù)據(jù)庫(kù),支持多種類(lèi)型的數(shù)據(jù)結(jié)構(gòu),如字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted set)等而且對(duì)數(shù)據(jù)的操作都是原子性的。Redis運(yùn)行在內(nèi)存中,所以具有極高的讀寫(xiě)速度,同時(shí)也支持?jǐn)?shù)據(jù)的持久化,將內(nèi)存中的數(shù)據(jù)保存在磁盤(pán)中。

一、Redis與私有網(wǎng)絡(luò)

1、Redis應(yīng)用場(chǎng)景

  • 計(jì)數(shù)器:因?yàn)镽edis操作是原子性的,通過(guò)原子遞增或遞減來(lái)做高并發(fā)用戶(hù)的數(shù)據(jù)計(jì)數(shù),比如點(diǎn)贊數(shù)、收藏?cái)?shù)、分享數(shù)、商品搶購(gòu)時(shí)的庫(kù)存量、商品文章總數(shù)、評(píng)論數(shù)量等

  • 排行榜:Redis支持集合和有序集合的數(shù)據(jù)結(jié)構(gòu),且運(yùn)行在內(nèi)存中,因此可以存儲(chǔ)一些類(lèi)似于排行榜的數(shù)據(jù),比如最近、最熱、點(diǎn)擊率最高、活躍度最高、評(píng)論最多等等的文章、商品、用戶(hù)等;

  • 哈希表:用戶(hù)粉絲列表、用戶(hù)點(diǎn)贊列表、用戶(hù)收藏列表、用戶(hù)關(guān)注列表等;

  • 自動(dòng)排序:存儲(chǔ)時(shí)間戳,隨著時(shí)間的變化,按照用戶(hù)關(guān)注用戶(hù)的最新動(dòng)態(tài)列表等自動(dòng)排序;

  • 會(huì)話(huà)緩存:使用Redis進(jìn)行會(huì)話(huà)緩存,將web session存放在Redis中。

  • 全頁(yè)緩存FPC:可以將服務(wù)端渲染結(jié)果的緩存在Redis中;

  • 記錄用戶(hù)操作信息:用戶(hù)是否點(diǎn)贊、用戶(hù)是否收藏、用戶(hù)是否分享等;

2、創(chuàng)建Redis

在創(chuàng)建了上??捎脜^(qū)的私有網(wǎng)絡(luò)之后(可以參考上一節(jié)的內(nèi)容),我們可以購(gòu)買(mǎi)騰訊云在上??捎脜^(qū)的Redis服務(wù),網(wǎng)絡(luò)類(lèi)型找到你創(chuàng)建的私有網(wǎng)絡(luò)以及相應(yīng)的子網(wǎng)即可。

在騰訊云網(wǎng)頁(yè)云開(kāi)發(fā)控制臺(tái)中,找到需要配置的云函數(shù),比如函數(shù)名為redis,點(diǎn)擊右上角編輯進(jìn)入配置界面,在函數(shù)配置界面中,修改網(wǎng)絡(luò)配置為Redis所在的同一私有網(wǎng)絡(luò)子網(wǎng)。

二、使用ioredis操作redis

為了連接和操作 Redis 實(shí)例,我們需要一個(gè) Redis 客戶(hù)端,推薦使用ioredis(類(lèi)似的還有node_redis、tedis等)。使用開(kāi)發(fā)者工具打開(kāi)云函數(shù)目錄中的 package.json ,新增最新版ioredis 依賴(lài),右鍵云函數(shù)目錄選擇在終端中打開(kāi)輸入命令npm install安裝依賴(lài)::

  1. "dependencies": {
  2. "wx-server-sdk":"latest",
  3. "ioredis":"latest"
  4. }

然后在index.js里輸入以下代碼,里面涉及redis多個(gè)命令行,其中zadd命令是往redis里添加有序集合,zscore命令返回有序集合元素相應(yīng)的分?jǐn)?shù)值,zrevrank命令返回有序集合元素的排名(Redis有多種數(shù)據(jù)結(jié)構(gòu),不同的數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)的增刪改查都有著相應(yīng)的命令,這里就不多介紹了):

  1. const cloud = require('wx-server-sdk')
  2. cloud.init({
  3. env: cloud.DYNAMIC_CURRENT_ENV,
  4. })
  5. const Redis = require('ioredis')
  6. const redis = await new Redis({
  7. port: 6379,
  8. host: '10.168.0.11',
  9. family: 4, // 4 (IPv4) 或 6 (IPv6)
  10. password: 'cloudbase2020',//redis的密碼
  11. db: 0,
  12. })
  13. exports.main = async (event, context) => {
  14. await redis.zadd('Score',145,'user1')
  15. await redis.zadd('Score',134,'user2')
  16. await redis.zadd('Score',117,'user3')
  17. await redis.zadd('Score',147,'user4')
  18. await redis.zadd('Score',125,'user5')
  19. const score = await redis.zscore('Score','user3')
  20. console.log('用戶(hù)3的分?jǐn)?shù)',score)
  21. const rank = await redis.zrevrank('Score','user5')
  22. console.log('用戶(hù)5的排名',rank)
  23. return {'用戶(hù)3的分?jǐn)?shù)':score,'用戶(hù)5的排名':rank}
  24. }

三、Redis數(shù)據(jù)類(lèi)型和數(shù)據(jù)的存儲(chǔ)

Redis常用的數(shù)據(jù)類(lèi)型有五種:字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted set),而JavaScript和云開(kāi)發(fā)數(shù)據(jù)庫(kù)的數(shù)據(jù)類(lèi)型主要有字符串(String)、數(shù)字(Number)、布爾值(Boolean)、數(shù)組(Array)、對(duì)象(Object)。當(dāng)我們要將云數(shù)據(jù)庫(kù)或JavaScript的數(shù)組和對(duì)象這種比較復(fù)雜的數(shù)據(jù)類(lèi)型存儲(chǔ)到Redis時(shí),應(yīng)該怎么做呢?下面我們只粗略討論一下Redis與JavaScript以及云開(kāi)發(fā)數(shù)據(jù)庫(kù)之間的關(guān)聯(lián)關(guān)系。

Redis常用數(shù)據(jù)類(lèi)型

字符串Strings

Redis的字符串是二進(jìn)制安全的,在傳輸數(shù)據(jù)時(shí),保證二進(jìn)制數(shù)據(jù)的信息安全,也就是不被篡改、破譯等,也不會(huì)對(duì)這些數(shù)據(jù)進(jìn)行編碼、序列化等。字符串存儲(chǔ)的結(jié)構(gòu)為key:value,可以用于存儲(chǔ)JavaScript的字符串、數(shù)值類(lèi)型,通常也用于存儲(chǔ)HTML的節(jié)點(diǎn)或者網(wǎng)頁(yè)。當(dāng)然也可以用于存儲(chǔ)圖片等,盡管一個(gè)key的存儲(chǔ)上限為512M,但是通常不建議存儲(chǔ)的值過(guò)長(zhǎng)(比如不要超過(guò)1024 bytes,不然內(nèi)存成本和key的比對(duì)成本太高)也不建議太短(只是建議)。

我們還能給字符串的值設(shè)置過(guò)期時(shí)間,以及如果值為整數(shù)(Redis沒(méi)有專(zhuān)門(mén)的整數(shù)類(lèi)型,所以key儲(chǔ)存的值在執(zhí)行原子操作命令時(shí)會(huì)被解釋為十進(jìn)制 64 位有符號(hào)整數(shù))可以對(duì)數(shù)值進(jìn)行類(lèi)似于云開(kāi)發(fā)數(shù)據(jù)庫(kù)的原子操作,比如INCR storage就是給字符串storage(表示商品庫(kù)存)原子增加1,而DECRBY storage 30,就是給庫(kù)存原子減少30。

我們可以在云函數(shù)里使用ioredis、node-redis等依賴(lài),通過(guò)redis.set key valueredis.mset key1 value1 key2 value2設(shè)置一個(gè)或多個(gè)key,獲取時(shí)通過(guò)redis.get keyredis.mget key1 key2獲取redis數(shù)據(jù)庫(kù)中已有的key的值,字符串在redis的結(jié)構(gòu)如下:

  1. SecretId "AKIDpZ9Wp1pyhFdqrioDF5dmDkMoQ7oVF2shUOE" //用于存儲(chǔ)一些key、token等數(shù)據(jù)
  2. openId "oUL-m5FuRmuVmxvbYOGuXbuEDsn8" //可以存儲(chǔ)云開(kāi)發(fā)經(jīng)常用到的openID
  3. storage 1017 //表示商品庫(kù)存為1017,執(zhí)行原子操作命令會(huì)被解釋為十進(jìn)制有符號(hào)(正負(fù))整數(shù)

關(guān)于字符串string的命令,有SET、GET、MSET、MGET、INCR、DECR、INCRBY、DECRBY等命令,具體可以閱讀Redis技術(shù)文檔。

散列哈希表Hashes

Redis的散列哈希表 Hashes是一個(gè) string 類(lèi)型的 field 和 value 的映射表,特別適合用于存儲(chǔ)JavaScript的對(duì)象,因此也是使用非常頻繁的一個(gè)數(shù)據(jù)類(lèi)型。Redis 中每個(gè) hash 可以存儲(chǔ)的鍵值對(duì)沒(méi)有上限(除非內(nèi)存的量不允許)。

當(dāng)我們使用JavaScript創(chuàng)建一個(gè)對(duì)象或者要往云開(kāi)發(fā)數(shù)據(jù)庫(kù)里獲取/傳入數(shù)據(jù)時(shí),就會(huì)涉及到如下的數(shù)據(jù)樣式(下面是一篇文章的數(shù)據(jù)),那我們應(yīng)該怎么把這樣的數(shù)據(jù)存儲(chǔ)到Redis呢?

  1. {
  2. "title": "為什么狗會(huì)如此親近人類(lèi)?",
  3. "id": 9717547,
  4. "url": "https://daily.zhihu.com/story/9717547",
  5. "image": "https://pic4.zhimg.com/v2-60f220ee6c5bf035d0eaf2dd4736342b.jpg",
  6. "body": "<p>讓狗從兇猛的野獸變成忠實(shí)的愛(ài)寵...</p>"
  7. }

我們可以使用Redis哈希表的hmset命令HMSET key field value,我們把key的值設(shè)置為post-${id},而對(duì)象里的屬性和值對(duì)應(yīng)的寫(xiě)法如下:

  1. hmset post-9717547 title "為什么狗會(huì)如此親近人類(lèi)?" id 9717547 url "https://daily.zhihu.com/story/9717547" image "https://pic4.zhimg.com/v2-60f220ee6c5bf035d0eaf2dd4736342b.jpg" body "<p>讓狗從兇猛的野獸變成忠實(shí)的愛(ài)寵...</p>"

而當(dāng)我們要獲取哈希表的值以及要對(duì)哈希表里的數(shù)據(jù)進(jìn)行增刪改查時(shí),相應(yīng)的操作命令如下(只是列舉了部分,更多內(nèi)容請(qǐng)查看技術(shù)文檔):

  1. //HGETALL以列表形式返回哈希表的字段及字段值
  2. hgetall post-9717547
  3. //HMGET命令返回哈希表中一個(gè)或多個(gè)給定字段的值,比如獲取2個(gè)key title和id的值;HGET是只返回一個(gè)
  4. hmget post-9717547 title id
  5. hget post-9717547 body
  6. //HMSET同時(shí)將多個(gè)鍵值對(duì)設(shè)置到哈希表中,比如我們同時(shí)設(shè)置兩個(gè)鍵值對(duì),HSET是只設(shè)置一個(gè);如果key相同就會(huì)覆蓋
  7. hmset post-9717547 author "李東bbsky" city "深圳"
  8. hset post-9717547 position "雜役"

還有刪除哈希表字段的hdel、查看字段是否存在的hexists、為指定字段的整數(shù)原子添加增量(可以為正或負(fù))的hincrby、獲取字段數(shù)量的hlen、獲取所有字段的hkeys等等,這些具體可以看文檔??傊?,有了哈希表,我們就可以用來(lái)存儲(chǔ)一些簡(jiǎn)單的對(duì)象(沒(méi)有嵌套和嵌套數(shù)組)了。

列表Lists

Redis的列表類(lèi)型可以用來(lái)存儲(chǔ)多個(gè)有序的字符串,列表里的值是可以重復(fù)的,有點(diǎn)類(lèi)似于JavaScript的數(shù)組(還是有很多不同的哦),主要的應(yīng)用場(chǎng)景是用戶(hù)最新的動(dòng)態(tài)信息、最新博客、朋友圈最新動(dòng)態(tài)。在Redis中,可以對(duì)列表兩端插入(push)和彈出(pop),也可以獲取指定范圍的元素列表以及指定索引下標(biāo)的元素等,可以充當(dāng)棧和隊(duì)列的角色。

  1. //rpush在列表的尾部(右邊)添加一個(gè)或多個(gè)值,類(lèi)似于數(shù)組方法里的push;lpush在列表的頭部(左邊)添加一個(gè)或多個(gè)值,類(lèi)似于數(shù)組方法里的unshift
  2. rpush code "Python" "JavaScript" "Java" "C++" "Golang" "Dart" "C" "C#"
  3. //rpop移除并返回列表最后一個(gè)元素,類(lèi)似于數(shù)組方法里的pop;lpop移除并返回列表第一個(gè)元素,類(lèi)似于數(shù)組方法里的shift
  4. rpop code
  5. //llen返回列表的長(zhǎng)度,有點(diǎn)類(lèi)似于數(shù)組的屬性length
  6. llen code
  7. //lindex通過(guò)索引獲取列表中的元素,有點(diǎn)類(lèi)似于數(shù)組的array[n]獲取數(shù)組第n+1位的元素
  8. lindex code 3
  9. //lrange返回列表中指定區(qū)間內(nèi)的元素,有點(diǎn)類(lèi)似于數(shù)組方法里的slice
  10. lrange code 2 5
  11. //linsert key before|after pivot value,在列表的元素前或者后插入元素。當(dāng)指定元素不存在于列表中時(shí),不執(zhí)行任何操作,如下方式是把SQL插入到Dart前,數(shù)組的slice方法可以在指定位置插入元素
  12. linsert code before "Dart" "SQL"
  13. //lset通過(guò)索引來(lái)設(shè)置元素的值,有點(diǎn)類(lèi)似于數(shù)組的array[n]=""
  14. lset code 4 "Go"

集合Sets

Redis的集合是字符串類(lèi)型的無(wú)序集合,集合里的元素是無(wú)序且唯一的,不能出現(xiàn)重復(fù)的數(shù)據(jù)。Redis支持集合內(nèi)元素的增刪改查,還支持多個(gè)集合的交集、并集、差集以及跨集合移動(dòng)元素,特別適合社交系統(tǒng)、電商系統(tǒng)、視頻App里等常見(jiàn)的打標(biāo)簽,比如你最感興趣的人、話(huà)題、項(xiàng)目等,網(wǎng)站和App會(huì)根據(jù)用戶(hù)的興趣點(diǎn)來(lái)推薦不同的內(nèi)容。

  1. //sadd 將一個(gè)或多個(gè)成員元素加入到集合中,已經(jīng)存在于集合的成員元素將被忽略
  2. sadd cloudbase "云函數(shù)" "云數(shù)據(jù)庫(kù)" "云存儲(chǔ)" "云接入" "云應(yīng)用" "云調(diào)用"
  3. //smembers返回集合中的所有成員
  4. smembers cloudbase
  5. //scard返回集合中元素的數(shù)量
  6. scard cloudbase
  7. //srandmember返回集合中一個(gè)或多個(gè)隨機(jī)數(shù),spop移除集合中的指定的一個(gè)或多個(gè)隨機(jī)元素,移除后會(huì)返回移除的元素
  8. srandmember cloudbase 2
  9. spop cloudbase
  10. //sismember判斷元素是否在集合中,在則返回1,不在返回0
  11. sismember cloudbase "云調(diào)用"

Redis處理跨集合的命令如求并集sunion,存儲(chǔ)并集sunionstore,交集sinter、存儲(chǔ)交集sinterstore,差集sdiff、存儲(chǔ)差集sdiffstore,跨集合移動(dòng)元素smove,等等這里就不一一舉例了。

有序集合Sorted sets

Redis的有序集合和集合一樣也字符串類(lèi)型元素且元素不重復(fù)的集合,不同的是,有序集合多了一個(gè)排序?qū)傩詓core(分?jǐn)?shù)),也就是每個(gè)存儲(chǔ)元素由兩個(gè)值構(gòu)成,一個(gè)是元素值,一個(gè)是排序值。有序集合的元素是唯一的,但分?jǐn)?shù)(score)卻可以重復(fù)。有序集合特別適合做排行榜系統(tǒng),比如點(diǎn)贊排名、銷(xiāo)量最多、播放最多、成績(jī)最好、分?jǐn)?shù)排名等。

下面我們把文章的閱讀量以及文章的id寫(xiě)入到Redis的有序集合里,我們可以很方便的將文章按一些要求來(lái)排序:

  1. //zadd命令用于將一個(gè)或多個(gè)元素及分?jǐn)?shù)值加入到有序集中。如果元素已經(jīng)存在,會(huì)更新這個(gè)元素的分?jǐn)?shù)值,并通過(guò)重新插入這個(gè)元素,來(lái)保證該元素在正確的位置上。
  2. zadd read:rank 9932 post-323 3211 post-123 1234 post-77 987 post-33 532 post-21
  3. //zrange把元素按分?jǐn)?shù)遞增來(lái)排序,0為第一位,-1為最后一位,0,-1會(huì)把所有元素都排序;而1,3則是取排序的第2、4位;zrevrange則是遞減
  4. zrange read:rank 0 -1 withscores
  5. zrange read:rank 1 3 withscores
  6. zrevrange read:rank 1 3 withscores
  7. //zcount顯示分?jǐn)?shù)score在 min 和 max 之間的元素的數(shù)量
  8. zcount read:rank 1000 3000
  9. //zrank返回有序集合指定元素的排名(排名以0為底),按分?jǐn)?shù)值遞增(從小到大)順序排列;zrevrank是從大到小
  10. zrank read:rank post-323
  11. zrevrank read:rank post-987

和連接MySQL一樣,建議在云函數(shù)中使用Redis時(shí),把同一個(gè)Redis實(shí)例的增刪改查等操作都集中寫(xiě)在一個(gè)云函數(shù)里,這樣會(huì)減少云函數(shù)冷啟動(dòng)的概率以及減少對(duì)數(shù)據(jù)庫(kù)連接數(shù)的占用,而將增刪改查的處理集中到一個(gè)云函數(shù),我們可以使用到云函數(shù)路由tcb-router,后面會(huì)有介紹。

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)