Redis是什麼
- Redis是一個開源,記憶體儲存的資料結構伺服器,可用作資料庫,快取記憶體和訊息佇列代理。
- Key-Value格式的快取和儲存伺服器;
- 資料結構伺服器,它支援字串、雜湊表、列表、集合、有序集合,點陣圖,hyperloglogs等資料型別;
- 所有資料集必須在記憶體中使用,磁碟是用來持久資料的。
- 是一種NoSQL資料庫
Redis和Memcached的比較
- 效能和用途:Memcached優先考慮高效能和特殊響應時間,適用於簡單快取任務;Redis提供相當的效能,支援更高階的使用案例,包括非同步和非阻塞I/O操作。
- 資料結構和功能:Redis支援更豐富的資料操作,而Memcached只是單一key-value記憶體Cache。
- 可靠性和持久化:Redis對可靠性要求較高,支援資料持久化,而Memcached只是記憶體快取,對可靠性無要求。
- 叢集模式:Redis原生支援叢集模式,而Memcached需要依靠客戶端來實現叢集。
- 效能對比:Redis在儲存小資料時比Memcached效能更高,但在大資料中稍有遜色。
Redis資料持久化
Redis的資料全部在記憶體中,如果突然當機,資料就會全部丟失,因此必須有一種機制來保證redis的資料在發生突發狀況時不會丟失、或者只丟失少量,於是必須根據一些策略來把redis記憶體中的資料寫到磁碟中,這樣當redis服務重啟時,就會將硬碟中的資料恢復到記憶體中。Redis持久化的意義就是為了保證突然當機,記憶體資料不會全部丟失。
redis有兩種持久化機制
RDB和AOF。Redis4.0後支援RDB和AOF兩種持久化機制混合使用,所以存在三種持久化策略。
- RDB是基於快照一次的全量備份,即週期性的把redis當前記憶體中的全量資料寫入到一個快照檔案中(週期時間可以透過配置來調整)。
- AOF(Append-only file)日誌儲存的是redis伺服器的順序指令序列,即對記憶體中資料進行修改的指令記錄。當redis收到客戶端修改指令後,先進行引數校驗,如果校驗透過,先把該指令儲存到AOF日誌檔案中,也就是先存到磁碟,然後再執行該修改指令。
Redis是單執行緒還是多執行緒?
- Redis5及之前是單執行緒版本
Redis5及之前的版本使用的是單執行緒,也就是說只有一個 worker佇列,所有的讀寫操作都要在這一個佇列進行操作,好處是不會有執行緒安全問題(因為它在讀寫時就只有一個執行緒,那對於讀寫操作肯定沒有執行緒安全問題啊!),但是讀寫 write、read 這些系統呼叫在Redis執行期間佔用了大部分的 CPU 時間,所以這就是單執行緒模式的缺點。
所以也就在Redis6引入了多執行緒版本,接著往下看。
- Redis6開始引入多執行緒版本(實際上是 單執行緒+多執行緒 版本)
Redis6引入了多執行緒機制,但是不是說有多個worker執行緒同時併發讀寫, 而是它有 “一個 worker執行緒+多個IO子執行緒”,其實就是在 IO 就緒之後使用多執行緒提升讀寫解析資料的效率,而在 操作記憶體資料的時候還是用單執行緒。
利用這種單執行緒+多執行緒共同運作的機制,將CPU的效能顯著提升了。
同時,這種機制同樣不會產生執行緒安全問題,因為Redis在針對資料的記憶體操作時,是在一個公共的worker佇列中實現的,先進先出,所以不會有執行緒安全問題。
Redis6之所以保留worker單主執行緒是因為單執行緒機制使得Redis內部實現的複雜度大大降低,而且可以保證操作的執行緒安全。(如果整個過程全讓子執行緒做了,整個任務處理過程太重,就失去了原來單執行緒高效處理的優勢了)
簡單來說,就是 “請求是多執行緒的,但核心的記憶體讀寫操作(或者說讀寫計算)仍然是單執行緒的”。
Redis 為什麼單執行緒還這麼快?
誤區1:高效能的伺服器一定是多執行緒的!
誤區2:多執行緒(CPU上下文會切換!)一定比單執行緒效率高!
- redis是將所有的資料全部放在記憶體中的,所以說使用單執行緒去操作效率就是最高的,多執行緒(CPU上下文會切換,耗時的操作!!!)。
- 對於記憶體系統來說,如果沒有上下文切換效率就是最高的!多次讀寫都是在一個CPU上的,在記憶體情況下,這個就是最佳的方案!
- 一條執行緒指的是程序中一個單一順序的控制流,一個程序中可以併發多個執行緒,每條執行緒並行執行不同的任務。多執行緒會進行CPU上下文會切換,造成時間消耗。
安裝部署
https://redis.io/
https://www.redis.net.cn/
因為Redis是C實現的,因此需要安裝如下依賴,其次,有可能需要安裝python3。
# yum install cpp
# yum install binutils
# yum install glibc
# yum install glibc-kernheaders
# yum install glibc-common
# yum install glibc-devel
# yum install gcc
# yum install make
# tar -zxvf redis-7.0.15.tar.gz
# cd redis-7.0.15
# make && make install
Hint: It's a good idea to run 'make test' ;)
make[1]: 離開目錄“/data/apps/redis-7.0.15/src”
cd src && make install
make[1]: 進入目錄“/data/apps/redis-7.0.15/src”
CC Makefile.dep
make[1]: 離開目錄“/data/apps/redis-7.0.15/src”
make[1]: 進入目錄“/data/apps/redis-7.0.15/src”
Hint: It's a good idea to run 'make test' ;)
INSTALL redis-server
INSTALL redis-benchmark
INSTALL redis-cli
make[1]: 離開目錄“/data/apps/redis-7.0.15/src”
- redis的預設安裝路徑:/usr/local/bin
[root@jgswy-pro bin]# ll
總用量 21556
-rwxr-xr-x. 1 root root 5205488 5月 28 21:03 redis-benchmark
lrwxrwxrwx. 1 root root 12 5月 28 21:03 redis-check-aof -> redis-server
lrwxrwxrwx. 1 root root 12 5月 28 21:03 redis-check-rdb -> redis-server
-rwxr-xr-x. 1 root root 5422896 5月 28 21:03 redis-cli
lrwxrwxrwx. 1 root root 12 5月 28 21:03 redis-sentinel -> redis-server
-rwxr-xr-x. 1 root root 11441032 5月 28 21:03 redis-server
- redis預設不是後臺啟動,需要修改配置檔案可以後臺啟動。
# cp /data/apps/redis-7.0.15/redis.conf /data/apps/redis-7.0.15/redis.conf.bak
# vi /data/apps/redis-7.0.15/redis.conf
daemonize yes #守護程序,修改為yes後即可後臺執行
requirepass 123321 #密碼,設定後訪問Redis必須輸人密碼
# redis-server /data/apps/redis-7.0.15/redis.conf
# ss -tul
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 127.0.0.1:323 *:*
udp UNCONN 0 0 [::1]:323 [::]:*
tcp LISTEN 0 128 *:ssh *:*
tcp LISTEN 0 100 127.0.0.1:smtp *:*
tcp LISTEN 0 128 127.0.0.1:6379 *:*
tcp LISTEN 0 128 [::]:ssh [::]:*
tcp LISTEN 0 128 [::]:hbci [::]:*
tcp LISTEN 0 100 [::1]:smtp [::]:*
tcp LISTEN 0 128 [::]:9115 [::]:*
tcp LISTEN 0 128 [::]:websm [::]:*
tcp LISTEN 0 128 [::1]:6379 [::]:*
tcp LISTEN 0 128 [::]:jetdirect [::]:*
[root@jgswy-pro ~]#
- 其它常用配置
#監聽的埠
port 6379
#工作目錄,預設是當前目錄,也就是執行redis-server時的命今,日誌、持久化等檔案會儲存在這個目錄
dir .
#資料庫數量,設定為1,代表只使用1個庫,預設有16個庫,編號0~15
databases 1
#設定redis能夠使用的最大記憶體
maxmemory 512mb
#日誌檔案,預設為空,不記錄日誌,可以指定日誌檔名
logfile "redis.log"
- 測試登入庫
# redis-cli -p 6379
127.0.0.1:6379> set name test
OK
127.0.0.1:6379> get name
"test"
127.0.0.1:6379>
- redis預設有16個庫(0-15),預設使用的是0,可以用select進行切換。每個資料庫互相隔離。
# redis-cli -p 6379
127.0.0.1:6379> SELECT 6 #切換到資料庫6
OK
- 常用命令
127.0.0.1:6379[6]> DBSIZE #檢視資料庫大小
(integer) 0
127.0.0.1:6379[6]> KEYS * #檢視資料庫所有的key
(empty array)
127.0.0.1:6379[6]> flushdb #清空當前庫的內容
OK
127.0.0.1:6379[6]> select 0
OK
127.0.0.1:6379> KEYS *
1) "myhash"
2) "mylist"
3) "name"
4) "key:__rand_int__"
5) "counter:__rand_int__"
127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> flushall #清空所有庫的內容
OK
127.0.0.1:6379[2]> select 0
OK
127.0.0.1:6379> keys *
(empty array)
# redis-cli -p 6379
127.0.0.1:6379> SET name xiaoming
OK
127.0.0.1:6379> KEYS *
1) "name"
127.0.0.1:6379> SET age 1 #插入資料
OK
127.0.0.1:6379> KEYS *
1) "name"
2) "age"
127.0.0.1:6379> EXISTS name #判斷name是否存在,存在返回1,不存在返回0
(integer) 1
127.0.0.1:6379> EXISTS name1
(integer) 0
127.0.0.1:6379> move name 1 #將name從當前庫移動到庫1
(integer) 1
127.0.0.1:6379> set name xioaming
OK
127.0.0.1:6379> get name
"xioaming"
127.0.0.1:6379> expire name 10 #設定key的過期時間10秒,倒數計時10秒後資料過期
(integer) 1
127.0.0.1:6379> ttl name #檢視當前key的時間
(integer) 2
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> set name xiaoming
OK
127.0.0.1:6379> type name #檢視當前key的資料型別
string
併發測試
redis提供了一款測試工具redis-benchmark
redis-benchmark 引數
-h:指定主機名
-p:指定埠,預設6379
-c:指定併發連線數
-n:指定請求數
-d:以位元組形式指定SET/GET值的資料大小
測試100個併發連線,每個併發100000個請求
# redis-benchmark -h localhost -p 6379 -c 100 -n 100000
====== PING_INLINE ======
100000 requests completed in 1.36 seconds #100000個請求
100 parallel clients #100個並行客戶端
3 bytes payload #每次寫入3個位元組
keep alive: 1 #一個伺服器處理請求
host configuration "save": 3600 1 300 100 60 10000
host configuration "appendonly": no
multi-thread: no
Latency by percentile distribution:
0.000% <= 0.247 milliseconds (cumulative count 2)
50.000% <= 0.663 milliseconds (cumulative count 53433)
75.000% <= 0.687 milliseconds (cumulative count 78832)
87.500% <= 0.711 milliseconds (cumulative count 88427)
93.750% <= 1.015 milliseconds (cumulative count 93767)
96.875% <= 1.423 milliseconds (cumulative count 96926)
98.438% <= 1.623 milliseconds (cumulative count 98501)
99.219% <= 1.719 milliseconds (cumulative count 99234)
99.609% <= 1.783 milliseconds (cumulative count 99621)
99.805% <= 2.095 milliseconds (cumulative count 99805)
99.902% <= 2.599 milliseconds (cumulative count 99903)
99.951% <= 2.951 milliseconds (cumulative count 99952)
99.976% <= 3.135 milliseconds (cumulative count 99976)
99.988% <= 3.303 milliseconds (cumulative count 99988)
99.994% <= 3.391 milliseconds (cumulative count 99994)
99.997% <= 3.439 milliseconds (cumulative count 99997)
99.998% <= 3.479 milliseconds (cumulative count 99999)
99.999% <= 3.495 milliseconds (cumulative count 100000)
100.000% <= 3.495 milliseconds (cumulative count 100000) #所有請求在3.495毫秒完成
Summary:
throughput summary: 73367.57 requests per second #每秒處理73367.57個請求
latency summary (msec):
avg min p50 p95 p99 max
0.716 0.240 0.663 1.175 1.695 3.495
...
====== SET ======
100000 requests completed in 1.33 seconds
100 parallel clients
3 bytes payload
keep alive: 1
host configuration "save": 3600 1 300 100 60 10000
host configuration "appendonly": no
multi-thread: no
Latency by percentile distribution:
0.000% <= 0.303 milliseconds (cumulative count 3)
50.000% <= 0.671 milliseconds (cumulative count 57052)
75.000% <= 0.687 milliseconds (cumulative count 77451)
87.500% <= 0.703 milliseconds (cumulative count 92613)
93.750% <= 0.711 milliseconds (cumulative count 95469)
96.875% <= 0.719 milliseconds (cumulative count 97002)
98.438% <= 0.735 milliseconds (cumulative count 98636)
99.219% <= 0.767 milliseconds (cumulative count 99254)
99.609% <= 0.855 milliseconds (cumulative count 99635)
99.805% <= 1.023 milliseconds (cumulative count 99808)
99.902% <= 1.871 milliseconds (cumulative count 99903)
99.951% <= 2.175 milliseconds (cumulative count 99952)
99.976% <= 2.351 milliseconds (cumulative count 99976)
99.988% <= 2.479 milliseconds (cumulative count 99988)
99.994% <= 2.551 milliseconds (cumulative count 99994)
99.997% <= 2.583 milliseconds (cumulative count 99997)
99.998% <= 2.607 milliseconds (cumulative count 99999)
99.999% <= 2.623 milliseconds (cumulative count 100000)
100.000% <= 2.623 milliseconds (cumulative count 100000)
Cumulative distribution of latencies:
0.000% <= 0.103 milliseconds (cumulative count 0)
0.003% <= 0.303 milliseconds (cumulative count 3)
0.030% <= 0.407 milliseconds (cumulative count 30)
0.067% <= 0.503 milliseconds (cumulative count 67)
0.257% <= 0.607 milliseconds (cumulative count 257)
92.613% <= 0.703 milliseconds (cumulative count 92613)
99.412% <= 0.807 milliseconds (cumulative count 99412)
99.722% <= 0.903 milliseconds (cumulative count 99722)
99.794% <= 1.007 milliseconds (cumulative count 99794)
99.833% <= 1.103 milliseconds (cumulative count 99833)
99.850% <= 1.207 milliseconds (cumulative count 99850)
99.860% <= 1.303 milliseconds (cumulative count 99860)
99.866% <= 1.407 milliseconds (cumulative count 99866)
99.870% <= 1.503 milliseconds (cumulative count 99870)
99.874% <= 1.607 milliseconds (cumulative count 99874)
99.880% <= 1.703 milliseconds (cumulative count 99880)
99.893% <= 1.807 milliseconds (cumulative count 99893)
99.910% <= 1.903 milliseconds (cumulative count 99910)
99.928% <= 2.007 milliseconds (cumulative count 99928)
99.941% <= 2.103 milliseconds (cumulative count 99941)
100.000% <= 3.103 milliseconds (cumulative count 100000)
Summary:
throughput summary: 75075.07 requests per second #每秒處理75075個請求
latency summary (msec):
avg min p50 p95 p99 max
0.673 0.296 0.671 0.711 0.751 2.623
...
參考
https://blog.csdn.net/Awwwze/article/details/115396745
https://blog.csdn.net/Wong_H/article/details/126196774
https://blog.csdn.net/Awwwze/article/details/115396745