Redis

Redis

redis中文文檔https://www.redis.net.cn/tutorial/3501.html

面試題https://www.cnblogs.com/jasontec/p/9699242.html

Redis基本

Redis安裝

1、安裝gcc運行環(huán)境,由于redis是由c語言寫的,所以這里必須先安裝gcc環(huán)境才可以安裝redis。

yum -y install gcc automake autoconf libtool make

2、下載redis

可以在官網(wǎng)下載redis的壓縮包。也可以通過linux進行在線安裝。

$ wget http://download.redis.io/releases/redis-5.07.tar.gz//下載壓縮包
$ tar zxvf redis-5.0.8.tar.gz -C /opt  //解壓安裝包到opt的路徑下
$ cd /opt/redis-5.0.8 && make MALLOC=libc//解壓并且編譯

3、安裝redis

make PREFIX=/usr/local/redis install//安裝到指定目錄下

4、進入到/usr/local/下,查看有沒有redis,如果有繼續(xù)進入,在bin目錄下可以看到以下結(jié)構(gòu):

查看有無redis安裝

運行服務(wù)端和客戶端

./redis-server

運行服務(wù)端。

運行服務(wù)端的redis

可以看到端口號是:6379。

退出輸入:Ctrl+c。

運行客戶端標準寫法。

redis-cli -h IP地址 -p 端口

也可簡便直接進行運行,相當于端口號ip地址都默認了。

./bin/redis-cli
運行客戶端,基礎(chǔ)測試

這里注意客戶端和服務(wù)端同時打開!我們可以在客戶端進行存值取值,就代表服務(wù)端啟動成功了。

查看當前redis運行的端口號:

ps -ef | grep -i redis
查看運行redis的端口號

Redis配置

Redis默認定義了很多配置,但是在實際開發(fā)中,一般都是我們通過手動配置完成。

回到解壓文件下,我們可以看到redis.conf,這個就是配置文件。我們需要把它復(fù)制到安裝目錄下。

cp /opt/redis-5.0.8/redis.conf /usr/local/redis
Redis配置文件

進入這個配置文件

用vim編輯器打開配置文件

這里我們可以看到bind 127.0.0.1這個代表只允許本機訪問

port端口號6379.

Redis配置文件文檔4.0

前10個:

redis.conf 配置項說明如下:
1. Redis默認不是以守護進程的方式運行,可以通過該配置項修改,使用yes啟用守護進程
  daemonize no
2. 當Redis以守護進程方式運行時,Redis默認會把pid寫入/var/run/redis.pid文件,可以通過pidfile指定
  pidfile /var/run/redis.pid
3. 指定Redis監(jiān)聽端口,默認端口為6379,作者在自己的一篇博文中解釋了為什么選用6379作為默認端口,因為6379在手機按鍵上MERZ對應(yīng)的號碼,而MERZ取自意大利歌女Alessia Merz的名字
  port 6379
4. 綁定的主機地址
  bind 127.0.0.1
5.當 客戶端閑置多長時間后關(guān)閉連接,如果指定為0,表示關(guān)閉該功能
  timeout 300
6. 指定日志記錄級別,Redis總共支持四個級別:debug、verbose、notice、warning,默認為verbose
  loglevel verbose
7. 日志記錄方式,默認為標準輸出,如果配置Redis為守護進程方式運行,而這里又配置為日志記錄方式為標準輸出,則日志將會發(fā)送給/dev/null
  logfile stdout
8. 設(shè)置數(shù)據(jù)庫的數(shù)量,默認數(shù)據(jù)庫為0,可以使用SELECT <dbid>命令在連接上指定數(shù)據(jù)庫id
  databases 16
9. 指定在多長時間內(nèi),有多少次更新操作,就將數(shù)據(jù)同步到數(shù)據(jù)文件,可以多個條件配合
  save <seconds> <changes>
  Redis默認配置文件中提供了三個條件:
  save 900 1
  save 300 10
  save 60 10000
  分別表示900秒(15分鐘)內(nèi)有1個更改,300秒(5分鐘)內(nèi)有10個更改以及60秒內(nèi)有10000個更改。
 
10. 指定存儲至本地數(shù)據(jù)庫時是否壓縮數(shù)據(jù),默認為yes,Redis采用LZF壓縮,如果為了節(jié)省CPU時間,可以關(guān)閉該選項,但會導(dǎo)致數(shù)據(jù)庫文件變的巨大
  rdbcompression yes

我們?nèi)绻枰薷模梢允褂胠inux正常模式下的查找:

/daemonize

注意,帶#是注釋!不要混淆了。

中間10個:

11. 指定本地數(shù)據(jù)庫文件名,默認值為dump.rdb
  dbfilename dump.rdb
12. 指定本地數(shù)據(jù)庫存放目錄
  dir ./
13. 設(shè)置當本機為slav服務(wù)時,設(shè)置master服務(wù)的IP地址及端口,在Redis啟動時,它會自動從master進行數(shù)據(jù)同步
  slaveof <masterip> <masterport>
14. 當master服務(wù)設(shè)置了密碼保護時,slav服務(wù)連接master的密碼
  masterauth <master-password>
15. 設(shè)置Redis連接密碼,如果配置了連接密碼,客戶端在連接Redis時需要通過AUTH <password>命令提供密碼,默認關(guān)閉
  requirepass foobared
16. 設(shè)置同一時間最大客戶端連接數(shù),默認無限制,Redis可以同時打開的客戶端連接數(shù)為Redis進程可以打開的最大文件描述符數(shù),如果設(shè)置 maxclients 0,表示不作限制。當客戶端連接數(shù)到達限制時,Redis會關(guān)閉新的連接并向客戶端返回max number of clients reached錯誤信息
  maxclients 128
17. 指定Redis最大內(nèi)存限制,Redis在啟動時會把數(shù)據(jù)加載到內(nèi)存中,達到最大內(nèi)存后,Redis會先嘗試清除已到期或即將到期的Key,當此方法處理 后,仍然到達最大內(nèi)存設(shè)置,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis新的vm機制,會把Key存放內(nèi)存,Value會存放在swap區(qū)
  maxmemory <bytes>
18. 指定是否在每次更新操作后進行日志記錄,Redis在默認情況下是異步的把數(shù)據(jù)寫入磁盤,如果不開啟,可能會在斷電時導(dǎo)致一段時間內(nèi)的數(shù)據(jù)丟失。因為 redis本身同步數(shù)據(jù)文件是按上面save條件來同步的,所以有的數(shù)據(jù)會在一段時間內(nèi)只存在于內(nèi)存中。默認為no
  appendonly no
19. 指定更新日志文件名,默認為appendonly.aof
   appendfilename appendonly.aof
20. 指定更新日志條件,共有3個可選值: 
  no:表示等操作系統(tǒng)進行數(shù)據(jù)緩存同步到磁盤(快) 
  always:表示每次更新操作后手動調(diào)用fsync()將數(shù)據(jù)寫到磁盤(慢,安全) 
  everysec:表示每秒同步一次(折衷,默認值)
  appendfsync everysec
 
21. 指定是否啟用虛擬內(nèi)存機制,默認值為no,簡單的介紹一下,VM機制將數(shù)據(jù)分頁存放,由Redis將訪問量較少的頁即冷數(shù)據(jù)swap到磁盤上,訪問多的頁面由磁盤自動換出到內(nèi)存中(在后面的文章我會仔細分析Redis的VM機制)
   vm-enabled no
22. 虛擬內(nèi)存文件路徑,默認值為/tmp/redis.swap,不可多個Redis實例共享
   vm-swap-file /tmp/redis.swap
23. 將所有大于vm-max-memory的數(shù)據(jù)存入虛擬內(nèi)存,無論vm-max-memory設(shè)置多小,所有索引數(shù)據(jù)都是內(nèi)存存儲的(Redis的索引數(shù)據(jù) 就是keys),也就是說,當vm-max-memory設(shè)置為0的時候,其實是所有value都存在于磁盤。默認值為0
   vm-max-memory 0
24. Redis swap文件分成了很多的page,一個對象可以保存在多個page上面,但一個page上不能被多個對象共享,vm-page-size是要根據(jù)存儲的 數(shù)據(jù)大小來設(shè)定的,作者建議如果存儲很多小對象,page大小最好設(shè)置為32或者64bytes;如果存儲很大大對象,則可以使用更大的page,如果不 確定,就使用默認值
   vm-page-size 32
25. 設(shè)置swap文件中的page數(shù)量,由于頁表(一種表示頁面空閑或使用的bitmap)是在放在內(nèi)存中的,,在磁盤上每8個pages將消耗1byte的內(nèi)存。
   vm-pages 134217728
26. 設(shè)置訪問swap文件的線程數(shù),最好不要超過機器的核數(shù),如果設(shè)置為0,那么所有對swap文件的操作都是串行的,可能會造成比較長時間的延遲。默認值為4
   vm-max-threads 4
27. 設(shè)置在向客戶端應(yīng)答時,是否把較小的包合并為一個包發(fā)送,默認為開啟
  glueoutputbuf yes
28. 指定在超過一定的數(shù)量或者最大的元素超過某一臨界值時,采用一種特殊的哈希算法
  hash-max-zipmap-entries 64
  hash-max-zipmap-value 512
29. 指定是否激活重置哈希,默認為開啟(后面在介紹Redis的哈希算法時具體介紹)
  activerehashing yes
30. 指定包含其它的配置文件,可以在同一主機上多個Redis實例之間使用同一份配置文件,而同時各個實例又擁有自己的特定配置文件
  include /path/to/local.conf

Redis內(nèi)存維護策略

由于Redis作為緩存,本質(zhì)就是在內(nèi)存中讀寫,會非常占用內(nèi)存,我們應(yīng)該及時的整理內(nèi)存,維持系統(tǒng)性能。

解決方法一:為數(shù)據(jù)設(shè)置超時時間

相關(guān)應(yīng)用:短信驗證碼。

命令查看數(shù)據(jù)時間

這里我們可以看到,我們設(shè)置的兩個key的有效值,都是永久有效。這里的-1代表永久有效。

expire name 1500

這里相當于設(shè)置這個key在內(nèi)存中的時間,設(shè)置name1500有效。

設(shè)置key在內(nèi)存中的保存時間

如果過了1500s,就會出先-2,代表已經(jīng)不存在內(nèi)存中。

-2代表該數(shù)據(jù)已不存在內(nèi)存中

解決方法二:采用LRU算法動態(tài)將不用的數(shù)據(jù)刪除

LRU算法刪除不用的數(shù)據(jù)

這個LRU算法在配置文件中設(shè)置,默認全部注釋了。

1.volatile-lru:從設(shè)置了過期時間的數(shù)據(jù)集中,選擇最近最久未使用的數(shù)據(jù)釋放

2.allkeys-lru:從數(shù)據(jù)集中(包括設(shè)置過期時間以及未設(shè)置過期時間的數(shù)據(jù)集中),選擇最近最久未使用的數(shù)據(jù)釋放,

前兩種是經(jīng)場用的。

3.volatile-random:從設(shè)置了過期時間的數(shù)據(jù)集中,隨機選擇一個數(shù)據(jù)進行釋放

4.allkeys-random:從數(shù)據(jù)集中(包括了設(shè)置過期時間以及未設(shè)置過期時間)隨機選擇一個數(shù)據(jù)進行入釋放

5.volatile-ttl:從設(shè)置了過期時間的數(shù)據(jù)集中,選擇馬上就要過期的數(shù)據(jù)進行釋放操作

6.noeviction:不刪除任意數(shù)據(jù)(但redis還會根據(jù)引用計數(shù)器進行釋放呦~),這時如果內(nèi)存不夠時,會直接返回錯誤
7、
8、(7,8是4版本以上才有的)

自定義配置Redis

將redis改為守護進程啟動

首先打開redis.conf文件,搜索daemonize進行更改。

改成守護進程.png

將bind 127.0.0.1注釋掉,允許本機以外的機器訪問redis

在配置文件中設(shè)置redis外網(wǎng)也可以訪問

需要為我們的redis設(shè)置密碼

為什么?

因為redis速度相當快,在一臺比較好的服務(wù)器,一個外部用戶可以在一秒以內(nèi)進行15w次的密碼嘗試,這意味著你需要設(shè)定更加強大的密碼來防止暴力解鎖。

requirepass 設(shè)置密碼 設(shè)置數(shù)據(jù)庫密碼 (有些情況下不設(shè)定密碼是無法進行遠程訪問的)
配置密碼
進入客戶端輸入配置文件中設(shè)置的密碼

注意**:如果自定義配置了redis.conf,在啟動服務(wù)端的時候,也要寫上配置文件。

./bin/redis-server ./redis.conf

加載配置文件后,我們進行啟動。

查看是否已守護進程啟動

可以看到,redis的服務(wù)端已經(jīng)按配置文件中的守護進程打開。

關(guān)閉Redis

非正常模式關(guān)閉:關(guān)閉后臺進程,斷電。

如果以非正常模式進行關(guān)閉,redis客戶端存入的數(shù)據(jù)也沒有默認情況下保存(900s更新一次),那么數(shù)據(jù)就會丟失。

shutdown

在客戶端輸入shutdown,是正常模式關(guān)閉,可以保存redis的數(shù)據(jù)。

遠程連接

Redis可視化工具:Redis Desktop Manager.

步驟:

1、下載Redis Desktop Manager工具

2、打開阿里云服務(wù)器安全組的redis端口號

3、在redis的配置文件中修改非本機訪問(bind),添加密碼

4、在linux上啟動redis的服務(wù)端

5、在windwos上啟動工具,進行連接。

使用Docker進行安裝Redis

//目前對docker使用還不太好

1、探索redis

docker search redis

2、下載鏡像

docker pull redis

3、創(chuàng)建并且運行


常用的指令

  • keys * 返回滿足的所有鍵,還可以模糊匹配

  • del key 刪除一個key

  • exists key:檢查key是否存在,存在返回1,不存在返回0

  • expire key second:為key設(shè)定過期時間

EXPIRE key second的使用場景:
1、限時的優(yōu)惠活動
2、網(wǎng)站數(shù)據(jù)緩存
3、手機驗證碼
4、限制網(wǎng)站訪客頻率


* ttl key  返回key剩余時間,當key不存在的時候,返回-2.

* PERSIST key:移除key的過期時間,key將持久保存

* select: 選擇數(shù)據(jù)庫,redis默認16個數(shù)據(jù)庫

* move key db:移動key至指定數(shù)據(jù)庫中

* random key:隨機返回一個key

* rename key newkey:修改key的名稱

* each:打印命令

* dump key:序列化給定key,返回被序列化的值

* type key:返回key所儲存的值的類型

* key pattern:查詢所有符號給定模式的key

* flushdb:清空當前數(shù)據(jù)庫

* flushall:清空所有數(shù)據(jù)庫

* info:查看數(shù)據(jù)庫信息

### key的命名建議

1. key不要太長,盡量不要超過1024字節(jié)。不僅消耗內(nèi)存,也會降低查找的效率
2. key不要太短,太短可讀性會降低
3. 在一個項目中,key最好使用統(tǒng)一的命名模式,如user:123:password
4. key區(qū)分大小寫

由于redis是非關(guān)系數(shù)據(jù)庫,所以最好遵循以上的命名建議。

## Redis中的數(shù)據(jù)類型

### string類型(字符串)

* string類型是Reds最基本的數(shù)據(jù)類型,一個鍵最大能存儲512MB
* string數(shù)據(jù)結(jié)構(gòu)是簡單的 key-value類型,vaue其不僅是 string,也可以是數(shù)字,是包含很多種類型的特殊類型string類型是二進制安全的。意思是reds的 string可以包含任何數(shù)據(jù)
* 比如序列化的對象進行存儲,比如一張圖片進行二進制存儲,比如一個簡單的字符串數(shù)值等等。

基本使用方法

```bash
127.0.0.1:6379> set k1 v1 # 創(chuàng)建
OK
127.0.0.1:6379> get k1 # 獲取
"v1"
127.0.0.1:6379> keys * # 獲取所有
1) "k1"
127.0.0.1:6379> EXISTS l #l 是否存在
(integer) 0
127.0.0.1:6379> EXISTS k1
(integer) 1
127.0.0.1:6379> STRLEN k1 # 返回k1的長度
(integer) 2
127.0.0.1:6379> APPEND k1 hahah # 向k1后添加字符串長度
(integer) 7
127.0.0.1:6379> get k1
"v1hahah"  # 這里我們發(fā)現(xiàn)k1后已經(jīng)添加了hahah
127.0.0.1:6379> APPEND k2 hahah # 如果我們追加的字符串并不存在,則自動創(chuàng)建
(integer) 5
127.0.0.1:6379> get k2
"hahah"

127.0.0.1:6379> set views 0 
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> INCR views # 加一
(integer) 1
127.0.0.1:6379> INCR views
(integer) 2
127.0.0.1:6379> DECR views #減一
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> INCRby views 10 #加10
(integer) 11
127.0.0.1:6379> DECRBY views 10#減10
(integer) 1

獲得指定長度:

127.0.0.1:6379> set key1 1234567
OK
127.0.0.1:6379> get key1
"1234567"
127.0.0.1:6379> GETRANGE key1 0 -1 # 獲取所有
"1234567"
127.0.0.1:6379> GETRANGE key1 0 4 # 右邊為閉區(qū)間
"12345"

從指定位置開始替換:

127.0.0.1:6379> set k abcdef
OK
127.0.0.1:6379> get k
"abcdef"
127.0.0.1:6379> SETRANGE k 1 123 #從下標1開始替換123
(integer) 6
127.0.0.1:6379> get k
"a123ef"

設(shè)置過期時間:setex:

127.0.0.1:6379> setex k2 30 "neirong" #設(shè)置k2的過期時間為30s
OK
127.0.0.1:6379> ttl k2 # 可以查看當前k2鍵的有效時間
(integer) 26
127.0.0.1:6379> ttl k2
(integer) 24
127.0.0.1:6379> get k2
"neirong"
127.0.0.1:6379> ttl k2
(integer) 9
127.0.0.1:6379> ttl k2 # 這里我們發(fā)現(xiàn)已經(jīng)過期了
(integer) -2

不存在才使用:setnx:(在分布式鎖中經(jīng)常使用)

127.0.0.1:6379> setnx k2 hhhhh #這里k2不存在,可以進行設(shè)置
(integer) 1
127.0.0.1:6379> get k2
"hhhhh"
127.0.0.1:6379> keys *
1) "k2"
2) "k"
127.0.0.1:6379> setnx k2 qqqq # k2已經(jīng)存在,不可以進行設(shè)置
(integer) 0
127.0.0.1:6379> get k2
"hhhhh"

一次創(chuàng)建多個key:

127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> mset k1 1 k2 2 k3 v3
OK
127.0.0.1:6379> mget k1 k2 k3
1) "1"
2) "2"
3) "v3"
注意這里也可以用msetnx創(chuàng)建多個不存在的k(這是原子性操作,一個失敗都失敗。)

創(chuàng)建一個對象:

127.0.0.1:6379> mset user:1:name zhangsan user:2:age 18
OK
127.0.0.1:6379> mget user:1:name user:2:age
1) "zhangsan"
2) "18"

應(yīng)用場景

  • String類型通常用于保存單個字符串或Json字符串數(shù)據(jù)
  • 因String是二進制安全,所以你可以把一個圖片的內(nèi)容作為字符串來存儲。
  • 計數(shù)器(常用的key-value緩存應(yīng)用,常規(guī)計數(shù):微博數(shù),粉絲數(shù))

Hash類型(哈希)

key(map)--> key (k - V)

存取一個:

hset myhash filed value
hmset myhash filed value filed2 value2

127.0.0.1:6379> hset myhash field SZW  #存入一個hash類型
(integer) 1
127.0.0.1:6379> hget myhash field   # 取出一個hash類型
"SZW"

存取多個:

hmset myhash filed value
hmget myhash filed

127.0.0.1:6379> hmset myhash name szw age 18 address aynu
OK
127.0.0.1:6379> hmget myhash name age address
1) "szw"
2) "18"
3) "aynu"

取出所有的:

127.0.0.1:6379> hgetall myhash
1) "name"
2) "szw"
3) "age"
4) "18"
5) "address"
6) "aynu"

刪除hash中的字段,對應(yīng)的value也會消失:

127.0.0.1:6379> hdel myhash name age
(integer) 2
127.0.0.1:6379> hgetall myhash
1) "address"
2) "aynu"

獲取hash有幾個字段:

127.0.0.1:6379> hgetall myhash
1) "address"
2) "aynu"
3) "name"
4) "szw"
5) "age"
6) "20"
127.0.0.1:6379> hlen myhash
(integer) 3

判斷hash中的指定字段是否存在:

127.0.0.1:6379> hexists myhash name
(integer) 1
127.0.0.1:6379> hexists myhash nohave
(integer) 0

獲取所有的key和values

127.0.0.1:6379> hkeys myhash
1) "address"
2) "name"
3) "age"
127.0.0.1:6379> hvals myhash
1) "aynu"
2) "szw"
3) "20"

對數(shù)字類型的字段可以自增:

127.0.0.1:6379> hincrby myhash id 1
(integer) 2
127.0.0.1:6379> hsetnx myhash testHave 1 #如果不存在這個字段,可以設(shè)置
(integer) 1
127.0.0.1:6379> hsetnx myhash testHave 1#存在這個字段,就不可以設(shè)置
(integer) 0

List類型(列表)

在redis中,我們可以把list玩成棧、隊列、阻塞隊列。

所有的llist命令都是以l開頭的。

127.0.0.1:6379> lpush list one  # push是存
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1    #取出所有的是0 -1
1) "three"
2) "two"
3) "one"

我們可以看到,我們這個list當成一個棧,我們相當于從頭部添加了數(shù)據(jù)。

127.0.0.1:6379> rpush list four # 用rpush對list的右邊進行存執(zhí)
(integer) 4
127.0.0.1:6379> lrange list 0 -1 # 用了rpush后,我們可以重新看這個list,four是在最底部
1) "three"
2) "two"
3) "one"
4) "four"

從左和從右取數(shù)據(jù)

127.0.0.1:6379> Lpop list   # 移除最左邊的元素
"three"
127.0.0.1:6379> Rpop list   # 移除最右邊的元素
"four"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"

查看下標為1的問題

linde list n

127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 1   # 查看下標為1的值
"one"

判斷列表的長度

Llen

127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> Llen list
(integer) 2

移除指定的值,精確匹配

Lrem

127.0.0.1:6379> lrange list  0 -1
1) "one"
2) "one"
3) "four"
4) "two"
5) "one"
6) "five"
127.0.0.1:6379> lrem list 2 one # 移除兩個值為one的數(shù)據(jù)
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "two"
3) "one"
4) "five"

截取

127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "four"
3) "two"
4) "one"
5) "five"
127.0.0.1:6379> ltrim list 1 3 # 這里截取list中下標為1開始的三個數(shù)據(jù)
OK
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "two"
3) "one"

移除最后一個元素,并且將這個元素移動到另外一盒key上

127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "two"
3) "one"
127.0.0.1:6379> rpoplpush list list2    # 在list的右邊pop一個數(shù)據(jù),放入list2中
"one"
127.0.0.1:6379> keys *  # 這里我們發(fā)現(xiàn)多了一個list2
1) "myhash"
2) "list2"
3) "list"
127.0.0.1:6379> lrange list2 0 -1
1) "one"

更改list中某個下標的值

127.0.0.1:6379> exists list3    # 判斷該list 是否存在
(integer) 0
127.0.0.1:6379> lset list3 0 hah    #我們嘗試修改下標為0的數(shù)據(jù),發(fā)現(xiàn)報錯。
(error) ERR no such key
127.0.0.1:6379> lpush list3 qqq # 創(chuàng)建并且在list中傳入qqq
(integer) 1
127.0.0.1:6379> lrange list3 0 0    # 查詢可知有數(shù)據(jù)qqq
1) "qqq"
127.0.0.1:6379> lset list3 0 hah    # 將hah修改坐標為0的數(shù)據(jù)
OK
127.0.0.1:6379> lrange list3 0 0    # 查詢發(fā)現(xiàn)修改成功
1) "hah"

在list中向后或者向前插入數(shù)據(jù)

127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "two"
127.0.0.1:6379> LInsert list before two "insertValue" # 在list中two數(shù)據(jù)前插入insertvalue數(shù)據(jù)
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "insertValue"
3) "two"

Set(集合)

set中的值是不能重復(fù)的。無序不重復(fù)

創(chuàng)建set,向set中添加值,查看set。

127.0.0.1:6379> sadd myset szw # 添加myset并且添加元素szw 
(integer) 1
127.0.0.1:6379> sadd myset ss
(integer) 1
127.0.0.1:6379> sadd myset ww
(integer) 1
127.0.0.1:6379> smembers myset # 查看myset中的元素
1) "ss"
2) "ww"
3) "szw"

判斷set中是否有某個值

sismember key 值

127.0.0.1:6379> smembers myset
1) "ss"
2) "ww"
3) "szw"
127.0.0.1:6379> sismember myset szw
(integer) 1

判斷set中的有幾個值

127.0.0.1:6379> scard myset
(integer) 3

移除set中的某個值

127.0.0.1:6379> smembers myset #查看未移除前的set
1) "ss"
2) "ww"
3) "szw"
127.0.0.1:6379> srem myset ss # 移除ss
(integer) 1
127.0.0.1:6379> smembers myset # 查看移除ss后的set
1) "ww"
2) "szw"

隨機抽選出指定個數(shù)的元素

127.0.0.1:6379> srandmember myset 2 
1) "ww"
2) "szw"
127.0.0.1:6379> srandmember myset
"ww"
127.0.0.1:6379> srandmember myset
"ww"
127.0.0.1:6379> srandmember myset
"szw"

移除指定的key,隨機刪除key。

127.0.0.1:6379> SMEMBERS myset
1) "qq"
2) "ww"
3) "szw"
4) "aa"
5) "bb"
6) "cc"
127.0.0.1:6379> spop myset  # 隨機移除myset中的一個元素
"aa"
127.0.0.1:6379> spop myset
"ww"
127.0.0.1:6379> spop myset 2 # 隨機移除myset中的兩個元素
1) "bb"
2) "szw"
127.0.0.1:6379> SMEMBERS myset #這里我們發(fā)現(xiàn)被移除以上元素后,只剩下了兩個
1) "cc"
2) "qq"

將一個指定的key移除到另外一個key中

127.0.0.1:6379> SMEMBERS myset
1) "ww"
2) "qq"
3) "rr"
4) "ee"
127.0.0.1:6379> SMOVE myset myset2 ww #將myset中的ww移動到myset2中
(integer) 1
127.0.0.1:6379> SMOVE myset myset2 qq
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "rr"
2) "ee"
127.0.0.1:6379> SMEMBERS myset2
1) "qq"
2) "ww"

兩個set的交集,并集,差集

127.0.0.1:6379> sadd key1 a b c
(integer) 3
127.0.0.1:6379> sadd key2 a e f
(integer) 3
127.0.0.1:6379> SINTER key1 key2 # 交集
1) "a"
127.0.0.1:6379> SUNION key1 key2 # 并集
1) "c"
2) "e"
3) "b"
4) "a"
5) "f"
127.0.0.1:6379> SDIFF key1 key2 # 差集
1) "b"
2) "c"

ZSet(有序集合)

相對于set,多了一個計數(shù)位。

添加元素,排序有序集合

127.0.0.1:6379> zadd salary 2500 szw
(integer) 1
127.0.0.1:6379> zadd salary 20000 sql
(integer) 1
127.0.0.1:6379> zadd salary 10000 sq
(integer) 1
127.0.0.1:6379> zadd salary 100 syh
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf #進行從小到大排序
1) "syh"
2) "szw"
3) "sq"
4) "sql"

127.0.0.1:6379> zadd salary 10 ww 1000 qq #添加多個值
(integer) 2
127.0.0.1:6379> zrange salary 0 -1
1) "ww"
2) "syh"
3) "qq"
4) "szw"
5) "sq"
6) "sql"

127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores # 顯示所有并且?guī)铣煽? 1) "ww"
 2) "10"
 3) "syh"
 4) "100"
 5) "qq"
 6) "1000"
 7) "szw"
 8) "2500"
 9) "sq"
10) "10000"
11) "sql"
12) "20000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 100  withscores # 顯示小于等于100的
1) "ww"
2) "10"
3) "syh"
4) "100"

127.0.0.1:6379> ZREVRANGE salary 0 -1 #從高到底進行排序
1) "sql"
2) "sq"
3) "szw"
4) "qq"

移除元素

127.0.0.1:6379> ZRANGE salary 0 -1
1) "ww"
2) "syh"
3) "qq"
4) "szw"
5) "sq"
6) "sql"
127.0.0.1:6379> ZREM salary ww syh
(integer) 2
127.0.0.1:6379> ZRANGE salary 0 -1
1) "qq"
2) "szw"
3) "sq"
4) "sql"
127.0.0.1:6379> zcard salary # 獲取有序集合的個數(shù)
(integer) 4

獲取成員區(qū)間的成員個數(shù)

127.0.0.1:6379> zadd myset 1 aa 2 bb 3 cc
(integer) 3
127.0.0.1:6379> ZCOUNT myset 1 3 #這里可以知道從1到3有三個值
(integer) 3

在這個網(wǎng)站中,可以查出指令的使用方法。

用的時候多看文檔!

https://redis.io/commands

三種特殊類型

Geospatita類型

地理位置,存取經(jīng)度緯度,可以存取城市之間的地理位置,附近的人,直線距離可以用到的場景。

Hyperloglog類型

什么是基數(shù)?

比如數(shù)據(jù)集 {1, 3, 5, 7, 5, 7, 8}, 那么這個數(shù)據(jù)集的基數(shù)集為 {1, 3, 5 ,7, 8}, 基數(shù)(不重復(fù)元素)為5個。 基數(shù)估計就是在誤差可接受的范圍內(nèi),快速計算基數(shù)。

Redis 在 2.8.9 版本添加了 HyperLogLog 結(jié)構(gòu)。

Redis HyperLogLog 是用來做基數(shù)統(tǒng)計的算法,HyperLogLog 的優(yōu)點是,在輸入元素的數(shù)量或者體積非常非常大時,計算基數(shù)所需的空間總是固定 的、并且是很小的。

在 Redis 里面,每個 HyperLogLog 鍵只需要花費 12 KB 內(nèi)存,就可以計算接近 2^64 個不同元素的基 數(shù)。

使用這種數(shù)據(jù)類型的場景

傳統(tǒng)的方式,set保存用戶id,然后可以統(tǒng)計set的個數(shù)作為判斷標準。

但是這個方式會出現(xiàn)大量的重復(fù),比較麻煩,我們的目標是為了計數(shù),而不是保存用戶的id。

127.0.0.1:6379> PFADD myket a b c d
(integer) 1
127.0.0.1:6379> PFADD myket2 c d e f
(integer) 1
127.0.0.1:6379> PFCOUNT mykey
(integer) 0
127.0.0.1:6379> PFCOUNT myket
(integer) 4
127.0.0.1:6379> PFCOUNT myket2
(integer) 4
127.0.0.1:6379> PFMERGE myket3 myket2 myket
OK
127.0.0.1:6379> PFCOUNT myket3
(integer) 6

Bitmap類型

位存儲

統(tǒng)計用戶信息,活躍,不活躍。登錄,未登錄。打卡,未打卡。

兩個狀態(tài)的都可以使用bitmap位圖,數(shù)據(jù)結(jié)構(gòu)。

都是操作二進制位來進行記錄,只用0和1。占用的內(nèi)存十分小。

測試周一到周日打卡

# 1代表打卡,0代表未打卡
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
#獲取那一天打卡的情況
127.0.0.1:6379> getbit sign 6
(integer) 0
127.0.0.1:6379> getbit sign 2
(integer) 1
# 統(tǒng)計操作,統(tǒng)計一周值為1(打卡)的天數(shù)
127.0.0.1:6379> bitcount sign 0 6
(integer) 5

Redis提升

事務(wù)

Redis 事務(wù)可以一次執(zhí)行多個命令, 并且?guī)в幸韵聝蓚€重要的保證:

事務(wù)是一個單獨的隔離操作:事務(wù)中的所有命令都會序列化、按順序地執(zhí)行。事務(wù)在執(zhí)行的過程中,不會被其他客戶端發(fā)送來的命令請求所打斷。

一個事務(wù)從開始到執(zhí)行會經(jīng)歷以下三個階段:

開始事務(wù)。
命令入隊。
執(zhí)行事務(wù)。

Redis的事務(wù)不保證原子性。

# 正常的事務(wù)
127.0.0.1:6379> MULTI # 開始事務(wù),這時候編寫的執(zhí)行都不進行執(zhí)行,只是放在了一塊
OK
127.0.0.1:6379> set k1 a
QUEUED
127.0.0.1:6379> set k2 b
QUEUED
127.0.0.1:6379> set k3 c
QUEUED
127.0.0.1:6379> exec # 執(zhí)行事務(wù),這時候,在隊列中的所有事務(wù)才開始執(zhí)行
1) OK
2) OK
3) OK
# 放棄事務(wù)
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a 1
QUEUED
127.0.0.1:6379> set b 2
QUEUED
127.0.0.1:6379> set c 3
QUEUED
127.0.0.1:6379> DISCARD # 這里進行了放棄事務(wù)
OK
127.0.0.1:6379> get c
(nil)

# 在編寫事務(wù)時,如果出現(xiàn)異常,這整個redis事務(wù)就無法執(zhí)行
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a 1
QUEUED
127.0.0.1:6379> qwesad b 1 # 這里我們瞎寫的一個命令,事務(wù)進行了報錯
(error) ERR unknown command `qwesad`, with args beginning with: `b`, `1`, 
127.0.0.1:6379> set b 3
QUEUED
127.0.0.1:6379> exec # 執(zhí)行事務(wù),我們可以發(fā)現(xiàn)啊,整個事務(wù)沒有執(zhí)行,還報錯了
(error) EXECABORT Transaction discarded because of previous errors.

# 在執(zhí)行事務(wù)時,如果出現(xiàn)錯誤,不會發(fā)生回滾操作,可以執(zhí)行的依然執(zhí)行
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a "a"
QUEUED
127.0.0.1:6379> INCR a
QUEUED
127.0.0.1:6379> set b 2
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) ERR value is not an integer or out of range # 只有這條沒有進行執(zhí)行,其他兩條依然執(zhí)行
3) OK
127.0.0.1:6379> get a
"a"

Redis實現(xiàn)樂觀鎖(面試)

悲觀鎖

很悲觀,認為任何時候都會出現(xiàn)問題,無論做什么都會加上鎖。

樂觀鎖

很樂觀,認為什么時候都不會出現(xiàn)問題,所以不會上鎖。更新的時候去判斷一下,在此期間是否有人更改過數(shù)據(jù)。

Redis實現(xiàn)樂觀鎖的步驟

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> watch money # 使用watch進行監(jiān)控
OK
127.0.0.1:6379> MULTI   # 開啟事務(wù)
OK
127.0.0.1:6379> DECRBy money 10
QUEUED
127.0.0.1:6379> EXEC # 執(zhí)行事務(wù),這里我們監(jiān)視了money,如果另外一個客戶端更改過,事務(wù)會執(zhí)行不成功,我們需要unwatch解鎖后,重新監(jiān)視再次進行事務(wù)。
1) (integer) 90

Jedis

我們要使用Java來操作Redis

什么是redis?

是redis官方推薦的java鏈接開發(fā)工具,使用java操作redis的中間件。如果要使用java操作redis,對jedis應(yīng)該十分熟悉!

jedis的api命令和上面的數(shù)據(jù)類型的指令一樣。

原生api?。?!

集成springboot(無筆記,需補上)

持久化

介紹

Redis 是內(nèi)存數(shù)據(jù)庫,如果不將內(nèi)存中的數(shù)據(jù)庫狀態(tài)保存到磁盤,那么一旦服務(wù)器進程退出,服務(wù)器中 的數(shù)據(jù)庫狀態(tài)也會消失。所以 Redis 提供了持久化功能!

持久化之RDB操作

什么是rdb

在主從復(fù)制中,rdb就是備用了!從機上面!

rdb文件
設(shè)置持久化保存機制

觸發(fā)機制

  • save的規(guī)則滿足的情況下,會自動觸發(fā)rdb規(guī)則(配置的規(guī)則在配置文件中,上圖就是)

  • 執(zhí)行 ?ushall 命令,也會觸發(fā)我們的rdb規(guī)則!

  • 退出redis,也會產(chǎn)生 rdb 文件

優(yōu)點:

1、適合大規(guī)模的數(shù)據(jù)恢復(fù)!

2、對數(shù)據(jù)的完整性要不高!

缺點:

1、需要一定的時間間隔進程操作!如果redis意外宕機了,這個后一次修改數(shù)據(jù)就沒有的了!

2、fork進程的時候,會占用一定的內(nèi)容空間

持久化之AOF操作

以日志的形式來記錄每個寫操作,將Redis執(zhí)行過的所有指令記錄下來(讀操作不記錄),只許追加文件 但不可以改寫文件,redis啟動之初會讀取該文件重新構(gòu)建數(shù)據(jù),換言之,redis重啟的話就根據(jù)日志文件 的內(nèi)容將寫指令從前到后執(zhí)行一次以完成數(shù)據(jù)的恢復(fù)工作。

Aof保存的是 appendonly.aof 文件,并且默認不開啟,,我們需要手動進行配置!我們只需要將 appendonly 改為yes就開啟了 aof。

開啟aof設(shè)置

如果這個 aof 文件有錯誤,這時候 redis 是啟動不起來的嗎,我們需要修復(fù)這個aof文件 redis 給我們提供了一個工具 redis-check-aof --fix 進行修復(fù)。

優(yōu)點:

1、每一次修改都同步,文件的完整會更加好!

2、每秒同步一次,可能會丟失一秒的數(shù)據(jù) 3、從不同步,效率高的!

缺點:
1、相對于數(shù)據(jù)文件來說,aof遠遠大于 rdb,修復(fù)的速度也比 rdb慢!

2、Aof 運行效率也要比 rdb 慢,所以我們redis默認的配置就是rdb持久化

擴展:

(區(qū)別)https://www.php.cn/redis/423077.html

1、RDB 持久化方式能夠在指定的時間間隔內(nèi)對你的數(shù)據(jù)進行快照存儲

2、AOF 持久化方式記錄每次對服務(wù)器寫的操作,當服務(wù)器重啟的時候會重新執(zhí)行這些命令來恢復(fù)原始 的數(shù)據(jù),

AOF命令以Redis 協(xié)議追加保存每次寫的操作到文件末尾,Redis還能對AOF文件進行后臺重 寫,使得AOF文件的體積不至于過大。

3、只做緩存,如果你只希望你的數(shù)據(jù)在服務(wù)器運行的時候存在,你也可以不使用任何持久化。

4、同時開啟兩種持久化方式 在這種情況下,當redis重啟的時候會優(yōu)先載入AOF文件來恢復(fù)原始的數(shù)據(jù),因為在

通常情況下AOF 文件保存的數(shù)據(jù)集要比RDB文件保存的數(shù)據(jù)集要完整。 RDB 的數(shù)據(jù)不實時,同時使用兩者時服務(wù)

器重啟也只會找AOF文件,那要不要只使用AOF呢?作者 建議不要,因為RDB更適合用于備份數(shù)據(jù)庫(AOF在不斷

變化不好備份),快速重啟,而且不會有 AOF可能潛在的Bug,留著作為一個萬一的手段。

5、性能建議

  • 因為RDB文件只用作后備用途,建議只在Slave上持久化RDB文件,而且只要15分鐘備份一次就夠 了,只保留 save 900 1 這條規(guī)則。
  • 如果Enable AOF ,好處是在惡劣情況下也只會丟失不超過兩秒數(shù)據(jù),啟動腳本較簡單只load自 己的AOF文件就可以了,代價一是帶來了持續(xù)的IO,二是AOF rewrite 的后將 rewrite 過程中產(chǎn) 生的新數(shù)據(jù)寫到新文件造成的阻塞幾乎是不可避免的。只要硬盤許可,應(yīng)該盡量減少AOF rewrite 的頻率,AOF重寫的基礎(chǔ)大小默認值64M太小了,可以設(shè)到5G以上,默認超過原大小100%大小重 寫可以改到適當?shù)臄?shù)值。
  • 如果不Enable AOF ,僅靠 Master-Slave Repllcation 實現(xiàn)高可用性也可以,能省掉一大筆IO,也 減少了rewrite時帶來的系統(tǒng)波動。代價是如果Master/Slave 同時倒掉,會丟失十幾分鐘的數(shù)據(jù), 啟動腳本也要比較兩個 Master/Slave 中的 RDB文件,載入較新的那個,微博就是這種架構(gòu)

訂閱發(fā)布

Redis 發(fā)布訂閱(pub/sub)是一種消息通信模式:發(fā)送者(pub)發(fā)送消息,訂閱者(sub)接收消息。微信、 微博、關(guān)注系統(tǒng)!
Redis 客戶端可以訂閱任意數(shù)量的頻道。
訂閱/發(fā)布消息圖: 第一個:消息發(fā)送者, 第二個:頻道 第三個:消息訂閱者

訂閱/發(fā)布消息圖

下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關(guān)系:

pubsub1.png

當有新消息通過 PUBLISH 命令發(fā)送給頻道 channel1 時, 這個消息就會被發(fā)送給訂閱它的三個客戶端:

pubsub2.png

演示:

發(fā)布端:
127.0.0.1:6379> PUBLISH szw qqqq
(integer) 1
127.0.0.1:6379> PUBLISH szw hhhhahhaha
(integer) 1

訂閱端就會接收到來自發(fā)布端的信息:

在訂閱端看到發(fā)布端的消息

發(fā)布訂閱命令:(中文文檔中截取)

Redis發(fā)布訂閱命令

Redis集群搭建

127.0.0.1:6379> info replication # 查看當親庫的信息
# Replication
role:master # 角色
connected_slaves:0 # 從機數(shù)量為0
master_replid:863219d1eaa861a7ebc11c276849bf704b2d2308
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

環(huán)境搭建

1、復(fù)制三個redis.conf文件

2、每個文件中修改端口號

3、pidfile的名字

4、log文件的名字

5、dump.rdb的名字

端口:

修改端口號

pid文件:

pid文件

日志文件:

日志文件

rdb文件:

rdb文件

修改完畢之后,啟動三個集群,可以通過進程信息查看。

ps -ef | grep redis
查看三個進程端口號

一主二從

默認情況下,每一臺Redis服務(wù)器都是主節(jié)點。我們一般只用配置從機就行了。

一主(79)二從(80,81)。

127.0.0.1:6381> SLAVEOF 127.0.0.1 6379 #認主機
OK

也可以在配置文件中進行配置(配置文件中修改的是永久的,記得加密碼):

配置從機

配置后重啟服務(wù)器:

在主機中查看信息,可以看到配置的兩個從機

我們已經(jīng)看到主機端口6379已經(jīng)含有兩個從機!

一主二從,讀寫分離,主機寫,從機進行讀取。

我們可以發(fā)現(xiàn),從機內(nèi)是無法進行寫操作的!

從機無法進行寫入

如果主機斷開連接,從機依然可以進行讀。

如果主機斷開后又連接上了,從機依然可以讀到主機新寫的內(nèi)容。

復(fù)制原理

從機啟動成功后,會發(fā)送一個同步sync命令給主機。

主機接受到命令后,啟動后臺的存盤進程,同時收集所有接收到的用于修改數(shù)據(jù)集命令,在后臺進程執(zhí)行完畢后,主機將傳送整個數(shù)據(jù)給slave,并完成一次完全同步。

全量復(fù)制:從機服務(wù)在接受到數(shù)據(jù)庫文件數(shù)據(jù)后,將其存盤并加載到內(nèi)存中。

增量復(fù)制:主機繼續(xù)將新的所有收集到的修改命令依次傳給從機,完成同步。

只要是我們重新連接主機,一次完全同步將會被自動執(zhí)行!

謀朝篡位

如果說主機宕機了,兩個從機就群龍無首了,這時候我們可以給一個從機使用:

slavof no one

這個命令可以使從機變成主機,但是注意!如果主機復(fù)活了,主機就是光桿司令了!

哨兵模式

介紹

什么是哨兵模式?

主從切換技術(shù)的方法是:當主服務(wù)器宕機后,需要手動把一臺從服務(wù)器切換為主服務(wù)器,這就需要人工干預(yù),費事費力,還會造成一段時間內(nèi)服務(wù)不可用。這不是一種推薦的方式,更多時候,我們優(yōu)先考慮哨兵模式

哨兵模式

配置哨兵文件:

[root@iZ2zeeqh1fctjw2bhzgjnaZ redis]# vim sentinel.conf
# 配置文件中的內(nèi)容
sentinel monitor myredis 127.0.0.1 6379 1

配置文件中的內(nèi)容最后那個1,代表如果主機掛掉了,哨兵就會通過投票來選舉讓誰來接替成主機,票數(shù)最多的,就是主機!

# 啟動我們自己配置的哨兵
[root@iZ2zeeqh1fctjw2bhzgjnaZ bin]# /usr/local/redis/bin/redis-sentinel /usr/local/redis/sentinel.conf

可以看到兩個從節(jié)點

我們把自己主機6379關(guān)閉,等待30s。

關(guān)閉6379后,發(fā)生變化
查看狀態(tài),主機變化為6380

通過以上可以看到,主機已經(jīng)換成了6380端口。

如果master出現(xiàn)了故障,哨兵會根據(jù)算法,投票,選擇出一個新的主機。就算6379回來了,也只能作為6380的從機!

優(yōu)點

  • 基于主從復(fù)制,所有的主從配置優(yōu)點,他全有。
  • 主從可以切換,故障可以切換,系統(tǒng)的可用性就很好,
  • 哨兵模式就是主從復(fù)制的升級,手動到自動,更加健壯!

缺點

  • Redis不好在線擴容,集群一旦達到上線,在線擴容就十分麻煩!
  • 實現(xiàn)哨兵模式的配置是十分麻煩的,里面有很多選擇!

哨兵模式的配置

不止上面那一個。

Redis緩存穿透和雪崩

參考:https://blog.csdn.net/kongtiao5/article/details/82771694

面試高頻!?。?!

緩存穿透

概念

就是用戶想要查詢一個數(shù)據(jù),發(fā)現(xiàn)redis內(nèi)存中不存在,也就是說緩存沒有命中,就去持久層數(shù)據(jù)庫中進行查找,發(fā)現(xiàn)也沒有。當很多用戶進行查找時,緩存都沒有命中,于是都去請求數(shù)據(jù)庫,這會給數(shù)據(jù)庫造成壓力,這時候就會出現(xiàn)緩存穿透。

緩存穿透

方案解決1:

添加布隆過濾器。

方案解決2:

需要查詢的那個對象設(shè)置為空的。

缺點:

  • 如果把空值存起來的話,意味著存儲更多的空字符串。
  • 即使設(shè)置了過期時間,還是會和存儲層有一段時間窗口內(nèi)的數(shù)據(jù)不一致,這對于需要保持一致性的業(yè)務(wù)會有影響。

緩存擊穿

概念

緩存擊穿是指緩存中沒有但數(shù)據(jù)庫中有的數(shù)據(jù)(一般是緩存時間到期),這時由于并發(fā)用戶特別多,同時讀緩存沒讀到數(shù)據(jù),又同時去數(shù)據(jù)庫去取數(shù)據(jù),引起數(shù)據(jù)庫壓力瞬間增大,造成過大壓力

解決方案:

  1. 設(shè)置熱點數(shù)據(jù)永遠不過期。
  2. 加互斥鎖,互斥鎖參考代碼如下

緩存雪崩

概念

緩存雪崩是指緩存中數(shù)據(jù)大批量到過期時間,而查詢數(shù)據(jù)量巨大,引起數(shù)據(jù)庫壓力過大甚至down機。和緩存擊穿不同的是,緩存擊穿指并發(fā)查同一條數(shù)據(jù),緩存雪崩是不同數(shù)據(jù)都過期了,很多數(shù)據(jù)都查不到從而查數(shù)據(jù)庫。

解決方案

  1. 緩存數(shù)據(jù)的過期時間設(shè)置隨機,防止同一時間大量數(shù)據(jù)過期現(xiàn)象發(fā)生。
  2. 如果緩存數(shù)據(jù)庫是分布式部署,將熱點數(shù)據(jù)均勻分布在不同搞得緩存數(shù)據(jù)庫中。
  3. 設(shè)置熱點數(shù)據(jù)永遠不過期。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容