Redis小总结

Redis 在线测试
Redis 中文文档
Redis 配置【官网】
Redis 命令【中文官网】
Docker Redis镜像【官网】
Redis集群教程 官方文档
Redis集群规范官方文档
Redis哨兵模式 官方文档
redis.conf 官网下载-稳定版
sentinel.conf 官网下载-稳定版

简介

Redis 百度百科
Redis(Remote Dictionary Server ),即远程字典服务,
是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
在这里插入图片描述
redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

Linux安装

Docker 安装Redis

官网下载页面https://redis.io/download,点击Stable(稳定版)对应的Download

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 1. 安装gcc环境
[root@localhost ~]# yum -y install gcc centos-release-scl devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
# 临时修改gcc版本
[root@localhost ~]# scl enable devtoolset-9 bash
# 永久修改gcc版本
[root@localhost ~]# echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile

# 2. 创建一个目录,进入
[root@localhost ~]# mkdir -p /app/redis/
[root@localhost ~]# cd /app/redis/

# 3. 下载压缩包,把 6.0.8 替换成你想要的版本号即可
[root@localhost redis]# wget https://download.redis.io/releases/redis-6.0.8.tar.gz
--2020-10-19 18:59:23-- https://download.redis.io/releases/redis-6.0.8.tar.gz
Resolving download.redis.io (download.redis.io)... 45.60.125.1
Connecting to download.redis.io (download.redis.io)|45.60.125.1|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2247528 (2.1M) [application/octet-stream]
Saving to: ‘redis-6.0.8.tar.gz’

100%[========================================================================================================================================================================>] 2,247,528 87.8KB/s in 32s

2020-10-19 18:59:58 (68.0 KB/s) - ‘redis-6.0.8.tar.gz’ saved [2247528/2247528]

# 4. 解压,并进入目录
[root@localhost redis]# tar -zxf redis-6.0.8.tar.gz
[root@localhost redis]# cd redis-6.0.8/

# 5. 安装
[root@localhost redis-6.0.8]# make MALLOC=libc
...
CC tls.o
CC sha256.o
CC timeout.o
CC setcpuaffinity.o
LINK redis-server
INSTALL redis-sentinel
CC redis-cli.o
LINK redis-cli
CC redis-benchmark.o
LINK redis-benchmark
INSTALL redis-check-rdb
INSTALL redis-check-aof

Hint: It's a good idea to run 'make test' ;)

make[1]: Leaving directory `/app/redis/redis-6.0.8/src'


# 6. 启动一个 Redis 服务端
# 如果想启动多个(集群)可指定多个配置文件,空格隔开:redis-server c1 c2 c3
[root@localhost redis-6.0.8]# src/redis-server redis.conf
82394:C 19 Oct 2020 19:04:13.653 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
82394:C 19 Oct 2020 19:04:13.653 # Redis version=6.0.8, bits=64, commit=00000000, modified=0, pid=82394, just started
82394:C 19 Oct 2020 19:04:13.653 # Configuration loaded
82394:M 19 Oct 2020 19:04:13.654 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.0.8 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 82394
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'

82394:M 19 Oct 2020 19:04:13.656 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
82394:M 19 Oct 2020 19:04:13.656 # Server initialized
82394:M 19 Oct 2020 19:04:13.656 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
82394:M 19 Oct 2020 19:04:13.657 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled (set to 'madvise' or 'never').
82394:M 19 Oct 2020 19:04:13.657 * Ready to accept connections

# 7. 拷贝。修改配置文件之前,先备份一份
[root@localhost redis-6.0.8]# cp redis.conf redis.conf.bak

# 8. 建立软链接
# 如果启动提示错误`bash :redis-server:command not found`
ln -s /app/redis/redis-6.0.8/src/redis-server /usr/bin/redis-server
ln -s /app/redis/redis-6.0.8/src/redis-cli /usr/bin/redis-cli

# 查看是否启动成功
ps aux | grep redis

# 启动 Redis客户端,可使用-h指定主机(默认本机) -p指定端口(默认6379)
# redis-cli -h 127.0.0.1 -p 6379
redis-cli

# 关闭 Server
shutdown

# 退出 Client
exit

性能测试

请求本机6379,并发100,请求10万次
可以使用redis-benchmark --help查看帮助

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@f48ac81f2b56:/data# redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000

====== SET ======
100000 requests completed in 3.98 seconds # 10万请求花了3.98s
100 parallel clients # 100并发
3 bytes payload # 3bytes数据
keep alive: 1 # 存活1个Server(单机)

1.34% <= 1 milliseconds
35.73% <= 2 milliseconds
70.75% <= 3 milliseconds
95.01% <= 4 milliseconds
98.27% <= 5 milliseconds
98.86% <= 6 milliseconds
99.16% <= 7 milliseconds
99.42% <= 8 milliseconds
99.60% <= 9 milliseconds
99.74% <= 10 milliseconds
99.87% <= 11 milliseconds
99.95% <= 12 milliseconds
99.98% <= 13 milliseconds
99.98% <= 14 milliseconds
100.00% <= 15 milliseconds # 所有请求15毫秒请求完成
25150.90 requests per second # 每秒请求25150.9次

操作命令

基本命令

命令起效返回1 不起效返回0 找不到返回nil 语法错误error
Redis索引(下标)都从0开始

1)、数据库相关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# DBSIZE 查看当前数据库有多少条数据
127.0.0.1:6379> DBSIZE
(integer) 4

# SELECT 切换数据库,共16个,下标[0,15]
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]>

# FLUSHDB 清空当前库
127.0.0.1:6379> FLUSHDB
OK

# FLUSHALL 清空所有数据库
127.0.0.1:6379> FLUSHALL
OK

2)、connection连接/client客户端/server服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
## QUIT / exit
退出client客户端
127.0.0.1:6379> QUIT
root@856d3e9b4533:/data# redis-cli
127.0.0.1:6379> exit
root@856d3e9b4533:/data#

# SHUTDOWN
退出server服务端
127.0.0.1:6379> SHUTDOWN
[root@localhost ~]#

# PING
ping
[root@localhost ~]# docker exec -it redis01 bash
root@856d3e9b4533:/data# redis-cli
127.0.0.1:6379> ping
PONG # 成功

# CONFIG SET / CONFIG GET / AUTH
设置配置值,获取值,验证服务器密码
设置值,临时生效,重启server服务端后,恢复默认
127.0.0.1:6379> CONFIG SET requirepass 123 # 设置配置文件参数requirepass
OK
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> QUIT
root@856d3e9b4533:/data# redis-cli
127.0.0.1:6379> ping
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH 123
OK
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> CONFIG GET requirepass # 获取配置文件参数requirepass
1) "requirepass"
2) "123"
127.0.0.1:6379>

# ROLE
查看角色
127.0.0.1:6379> ROLE
1) "master"
2) (integer) 0
3) (empty array)

# SLAVEOF / REPLICAOF
我认为这两个是相同的,认主机,自己做为从机
127.0.0.1:6379> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6379> REPLICAOF 127.0.0.1 6379

# LASTSAVE
最后一次同步磁盘的时间
127.0.0.1:6379> LASTSAVE
(integer) 1591920929 # UNIX 秒 《https://tool.lu/timestamp/》

# TIME
127.0.0.1:6379> TIME
1) "1591921456" # UNIX时间戳 秒 《https://tool.lu/timestamp/》
2) "134672" # 微秒

# MONITOR
实时监控,我也不知道干什么的。盲猜:是为了监控是否要断开
127.0.0.1:6379> MONITOR
OK
1591921717.852968 [0 127.0.0.1:38652] "PING"
1591921718.861684 [0 127.0.0.1:41990] "PING"
1591921719.871157 [0 127.0.0.1:41727] "PING"
1591921720.881525 [0 127.0.0.1:35681] "PING"

# INFO
获取详细信息
127.0.0.1:6379> INFO
# Server
redis_version:6.0.4 # redis版本
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:2fc02412644107e4
redis_mode:standalone # 单节点模式
os:Linux 3.10.0-1127.el7.x86_64 x86_64 # 操作系统内核
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:8.3.0
process_id:1 # 进程ID
run_id:d1f83f291f7388a125798ae54998d6196a11a7c4
tcp_port:6379
uptime_in_seconds:973
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:14863598
executable:/data/redis-server
config_file:/usr/local/etc/redis/redis.conf # 配置文件路径
...省略

# INFO server
获取 server 模块
# Server
redis_version:6.0.4
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:2fc02412644107e4
redis_mode:cluster
os:Linux 3.10.0-1127.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:8.3.0
process_id:1
run_id:aec5069b53ebe651e14c0b01b4e4cb4db3b52ca1
tcp_port:6379
uptime_in_seconds:9893
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:14882507
executable:/data/redis-server
config_file:/usr/local/etc/redis/redis.conf


# INFO replication
获取 replication 模块,后面主从复制会用
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=172.22.0.15,port=6379,state=online,offset=6230,lag=1
master_replid:68500f930c37e6c6d2313766300f5200d17328d3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:6230
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:6230


# MEMORY
内存相关
127.0.0.1:6379> MEMORY HELP
1) 把HELP换成下列参数
2) DOCTOR - 返回内存问题报告。
3) MALLOC-STATS -- 从内存分配器返回内部统计数据报告。
4) PURGE -- 尝试清除脏页面,以便由分配器回收。
5) STATS -- 返回关于服务器内存使用情况的信息。
6) USAGE <key> [SAMPLES <count>] -- 以<key>及其值使用的字节来返回内存。嵌套的值会被采样到<count>次(默认为5)。


# CLIENT操作: ID / GETNAME / SETNAME / LIST / KILL
127.0.0.1:6379> CLIENT ID # 获取客户端ID
(integer) 5
127.0.0.1:6379> CLIENT GETNAME # 获取客户端名称,默认空
(nil)
127.0.0.1:6379> CLIENT SETNAME A # 设置客户端名称
OK
127.0.0.1:6379> CLIENT LIST # 获取客户端列表
id=5 addr=127.0.0.1:51502 fd=8 name=A age=1592 idle=1 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client user=default
id=211 addr=127.0.0.1:51506 fd=7 name=A age=820 idle=52 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=client user=default
127.0.0.1:6379> CLIENT KILL addr 127.0.0.1:51506 id 211 # 删除客户端
(integer) 1
127.0.0.1:6379> CLIENT LIST # 再次查询,发送少了一个客户端
id=5 addr=127.0.0.1:51502 fd=8 name=A age=1660 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client user=default

Key

对所有key生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
## expire / ttl
+ `expire key 秒钟`为给定的key设置过期时间
+ `ttl key`查看还有多少秒到期。-1永不过期。-2不存在或已到期。【其实已到期就是不存在,因为到期自动删除了k】

# keys
+ `keys *`显示所有的key值.支持Ant风格
+ `?`匹配一个字符
+ `*`匹配0个或多个字符
+ `[]`表示匹配括号间任意一个字符,用 - 表示范围
+ 例如: a[a-c] 可以匹配`aa` `ab` `ac`不能匹配`ad`
+ `\?`匹配`?`
+ `keys k?`只查询`k1` `k2`而不查询`k11`
+ `keys k??`只查询`k11` `k12`而不查询`k1`

# RENAME
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SET k1 v1
OK
127.0.0.1:6379> RENAME k1 k11
OK
127.0.0.1:6379> KEYS *
1) "k11"


# exists
+ `exists key`判断某个key是否存在

# type
+ `type key`查看你的key是什么类型

# move
+ `move k1 1`移动k1到1号数据库,数据库可以是[0-15]

# del
+ `del key`删除key,返回成功删除数量。删除多个 del k1 k2【用空格分隔,而不是逗号】

String

字符串

Redis最基本的类型,一共key对应一个value,是二进制安全的,可以包含jpg图片或者序列号的对象.value最多可以是512M

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
## set / get
+ SET key value [EX seconds] [PX milliseconds] [NX|XX]
EX seconds – 设置键key的过期时间,单位时秒
PX milliseconds – 设置键key的过期时间,单位时毫秒
NX – 只有键key不存在的时候才会设置key的值
XX – 只有键key存在的时候才会设置key的值
+ `set k1 v1`设置key。不存在插入,存在覆盖。直接使用`set k1`默认插入空字符串""
+ `get k1`获取key的值。不存在返回空(nil)

## mset / mget
+ `mset k1 v1 k2 v2 k3 v3`必须是双数,否则错误。`mset k1 v1 k2`则错误
+ `mget k1 k2 k3`依次返回对应的value

## setex / ttl
+ SETEX key seconds value
127.0.0.1:6379> SETEX k1 10 v1
OK
127.0.0.1:6379> ttl k1
(integer) 7
127.0.0.1:6379> ttl k1
(integer) -2

## PSETEX / PTTL
+ PSETEX key milliseconds value
127.0.0.1:6379> PSETEX k1 5000 v1
OK
127.0.0.1:6379> PTTL k1
(integer) 1580
127.0.0.1:6379> PTTL k1
(integer) -2

# setnx
+ `setnx k5 v5`key不存在再插入。插入成功返回1,失败返回0


# msetnx
+ `msetnx k4 v4 k5 v5`全部插入返回1,全部不插入返回0。已存在任何一个key都全部不插入
# getset
+ `getset k1 v1`【先get再set】返回旧值,再设置新值。key不存在返回空(nil)

# append
+ `append k1 123`在value后面追加内容123
# strlen
+ `strlen k1`返回value的字符串长度。不存在返回0

#### incr / decr / incrby / decrby
> 一定要是数字才能进行加减,返回计算后的值
+ `incr k1`加1
+ `decr k1`减1
+ `incrby k1 2`加2
+ `decrby k1 3`减3

# INCRBYFLOAT
127.0.0.1:6379>
127.0.0.1:6379> set k1 10
OK
127.0.0.1:6379>
127.0.0.1:6379> INCRBYFLOAT k1 1.1
"11.1"
127.0.0.1:6379> INCRBYFLOAT k1 -5
"6.1"


## getrange / setrange
> 测试`set k1 abcdefg`
+ `getrange k1 0 -1`获取全部数据,相当于`get k1`。【不同的是k2如果不存在,返回空字符串""】
+ `getrange k1 1 3`返回下标1 2 3的数据,此时返回"bcd"【下标从0开始】
+ `setrange k1 2 xyz`返回设置后的长度7。把下标234设置成xyz。此时`get k1`返回"abxyzfg"

使用场景

1)、单值缓存

1
2
set k v
get k

2)、对象缓存

1
2
3
4
5
6
set user:1 v # v是json格式
127.0.0.1:6379> mset student:1:name daniu student:1:age 18
OK
127.0.0.1:6379> mget student:1:name student:1:age
1) "daniu"
2) "18"

3)、分布式锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
127.0.0.1:6379> SETNX redisLock v # 设置成功返回1
(integer) 1
127.0.0.1:6379> SETNX redisLock v # 设置失败返回0
(integer) 0
执行业务逻辑...
127.0.0.1:6379> DEL redisLock # 删除锁
(integer) 1


# 设置超时时间,防止业务一直玩阻塞,释放不了锁
127.0.0.1:6379> set redisLock v ex 10 nx
OK //获取锁成功
127.0.0.1:6379> set redisLock v ex 10 nx
(nil) //获取锁失败
执行业务逻辑...
127.0.0.1:6379> del redisLock
(integer) 1

4)、计数器

1
2
3
4
5
6
127.0.0.1:6379> INCR article:readCount:x001 # 每浏览一次文章阅读数 + 1,x001是文章编号
(integer) 1
127.0.0.1:6379> INCR article:readCount:x001
(integer) 2
127.0.0.1:6379> GET article:readCount:x001 # 获取文章浏览数量
"2"

5)、Web集群session共享

1
用Redis来存取session

List

有序集合

左头右尾,lpush依次头插入,rpush依次尾插入,lpop删除头,rpop删除尾
就把它当做LinkedList就行了。lpush头插入,rpush尾插入,lpop删除头,rpop删除尾
lrange key 0 -1 就是for循环,从左开始循环
注意:不存在为空的集合,如果集合无元素,就会删除这个集合的key。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
## lpush / rpush
+ `lpush list01 1 2 3 4 5`从左往右,依次头插入。此时集合[5,4,3,2,1]
+ `rpush list02 1 2 3 4 5`尾插入,此时集合[1,2,3,4,5]

## lpop / rpop
> 如果删除的是最后一个元素,则删除集合。
> 也就是删除这个集合的key。集合就不存在了。
+ `lpop list01`删除头节点,返回删除的内容。为空返回(nil)
+ `rpop list01`删除尾节点,返回删除的内容。为空返回(nil)

## BLPOP / BRPOP
+ BLPOP/BRPOP key [key ...] timeout # timeout超时时间,单位秒,0表示一直阻塞
127.0.0.1:6379> LPUSH k1 a
(integer) 1
127.0.0.1:6379> BRPOP k1 k2 10
1) "k1"
2) "a" //如果有,直接拿出来
(7.01s)
127.0.0.1:6379> BRPOP k1 k2 3
(nil) //三秒超时
(3.07s)

# lrange
+ `lrange list01 0 -1`查看集合的全部内容
+ `lrange list01 2 4`查看集合下标2 3 4的内容。下标从0开始。

# linsert
> 返回插入之后的集合长度。插入失败返回-1,也就是a1不存在集合中。集合不存在返回0。
+ `linsert list01 before a1 a2`在集合的第一个值为`a1`的前面添加`a2`
+ `linsert list01 after a1 a2`在集合的第一个值为`a1`的后面添加`a2`

# lset
+ `lset list01 1 ddd`把下标1的值改为`ddd`

# ltrim
> 截取指定范围作为新集合【也就是删除了集合不指定的部分】
+ `ltrim list01 3 5`除了下标3 4 5其他的元素全部删除。

# rpoplpush
> 把第一个的尾值放到第二个头部
+ `rpoplpush a1 a2`删除并返回a1的头节点,并把头节点尾插入到a2中。
注意:如果a1不存在,则返回空(nil)。如果a2不存在,则新建并插入a1的头节点。

# BRPOPLPUSH
BRPOPLPUSH 是 RPOPLPUSH 的阻塞版本。
source 包含元素的时候,这个命令表现得跟 RPOPLPUSH 一模一样。
source 是空的时候,Redis将会阻塞这个连接,直到另一个客户端 push 元素进入或者达到 timeout 时限。
timeout 为 0 能用于无限期阻塞客户端。
+ BRPOPLPUSH source destination timeout

## LPUSHX / RPUSHX
key不存在,不进行任何操作
key存在用法等同于:LPUSH / RPUSH
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> LPUSHX k1 d e f # key不存在,不进行任何操作
(integer) 0
127.0.0.1:6379> LPUSH k1 a b c
(integer) 3
127.0.0.1:6379> LPUSHX k1 d e f # key存在,等同于LPUSH命令
(integer) 6
127.0.0.1:6379> LRANGE k1 0 -1
1) "f"
2) "e"
3) "d"
4) "c"
5) "b"
6) "a"
127.0.0.1:6379>

# lindex
+ `lindex list01 2`返回下标2的元素。下标越界返回空(nil)

# llen
+ `llen list01`返回集合长度。不存在或集合空返回0

# lrem
> 删除N个value
+ `lrem list01 2 dd`返回删除的数量。删除前2个dd
+ `lrem list01 0 dd`返回删除的数量。删除全部dd

使用场景

1)、常用数据结构

1
2
3
4
5
6
7
8
# Stack 栈
LPUSH + LPOP -> FILO:先进后出(First In Last Out)

# Queue 队列
LPUSH + RPOP -> FIFO:先进先出(First In First Out)

# Blocking Queue 阻塞队列
LPUSH + BRPOP

2)、微博,工众号消息

1
2
3
4
5
6
7
127.0.0.1:6379> LPUSH msg:daniu hello # 公众号弟弟推送消息
(integer) 1
127.0.0.1:6379> LPUSH msg:daniu world # 公众号哥哥推送消息
(integer) 2
127.0.0.1:6379> LRANGE msg:daniu 0 4 # 取出消息
1) "world"
2) "hello"

Set

无序集合

String类型的无序集合.值不允许重复.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
## sadd / srem
+ `sadd set01 1 1 1 1 2 3 3 4`返回4。4表示成功插入元素的数量
+ `srem set01 3`删除集合中值为`3`的元素。删除成功返回1,失败返回0。集合不存在返回0

# smembers
+ `smembers set01`查看set01里面的数据,无序。

# srandmember
+ `srandmember set01 3`随机获取3个元素。如果获取数量>元素数,则获取全部。

# sismember
+ `sismember set01 x`查询集合中是否有元素`x`,有返回1,无返回0。集合不存在返回0

# scard
+ `scard set01`获取集合里面的元素个数。集合不存在返回0

### sdiff / sinter / sunion
+ `sdiff set01 set02 ...`(差集)获取`set01`中有,而`set02`和`后面`中没有的元素
+ `sinter set01 set02 ...`(交集)获取`set01`中有,而`set02`和`后面`中也有的元素
+ `sunion set01 set02 ...`(并集)所有集合元素相加,并去重

# smove
+ `smove set01 set02 x`把`set01`中的值`x`移到`set02`中。成功返回1,失败返回0

# spop
+ `spop set01`随机删除1个元素
+ `spop set01 3`随机删除3条记录【在3.2+版本可用。】

使用场景

1)、抽奖小程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 1. 点击参与抽奖:加入集合
127.0.0.1:6379> SADD students a
(integer) 1
127.0.0.1:6379> SADD students b
(integer) 1
127.0.0.1:6379> SADD students c
(integer) 1
127.0.0.1:6379> SADD students d
(integer) 1
127.0.0.1:6379> SADD students e
(integer) 1
127.0.0.1:6379> SADD students f
(integer) 1
# 2. 查看所有抽奖用户
127.0.0.1:6379> SMEMBERS students
1) "e"
2) "f"
3) "a"
4) "b"
5) "c"
6) "d"
# 3. 查看参与抽奖的人数
127.0.0.1:6379> SCARD students
(integer) 6
# 4. 抽取3名中奖者
127.0.0.1:6379> SRANDMEMBER students 3
1) "f"
2) "d"
3) "c"
# 5. 或者使用随机删除,抽取一等二等三等奖
127.0.0.1:6379> SPOP students 2 // 随机抽取2名,并在集合中删除
1) "e"
2) "a"
127.0.0.1:6379> SMEMBERS students
1) "f"
2) "b"
3) "c"
4) "d"

2)、微信微博点赞,收藏,标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> SADD like:helloworld daniu # 点赞
(integer) 1
127.0.0.1:6379> SADD like:helloworld erdan
(integer) 1
127.0.0.1:6379> SADD like:helloworld sanlv
(integer) 1
127.0.0.1:6379> SREM like:helloworld sanlv # 取消点赞
(integer) 1
127.0.0.1:6379> SISMEMBER like:helloworld daniu # 检查用户是否点赞
(integer) 1
127.0.0.1:6379> SMEMBERS like:helloworld # 获取点赞用户列表
1) "daniu"
2) "erdan"
127.0.0.1:6379> SCARD like:helloworld # 获取点赞用户数
(integer) 2

3)、微信朋友圈,微博相同关注的人:集合操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> SADD k1 1 2 3 4 5 # 用户k1关注了:1 2 3 4 5
(integer) 5
127.0.0.1:6379> SADD k2 3 4 5 6 7 k1 # 用户k2关注了:3 4 5 6 7 k1
(integer) 5
127.0.0.1:6379> SADD k3 1 4 8 # 用户k3关注了:1 4 8
(integer) 3
127.0.0.1:6379> SINTER k1 k2 # 用户k1,k2共同关注的人
1) "3"
2) "4"
3) "5"
127.0.0.1:6379> SISMEMBER k1 3 # 用户k2关注的k1也关注了3
(integer) 1
127.0.0.1:6379> SDIFF k1 k2 # k2可能认识是人
1) "1"
2) "2"

Hash

哈希

类似于java的Map.KV模式不变.但V是一个键值对.
我们这里称【主key为k1,副key为k2,k2对应的值为v2】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
## hset / hget
+ `hset user id 11`设置k1=user,k2=id,v2=11。k2存在返回0,不存在返回1。
+ `hget user id`根据k1,k2查找对应的v2。k1,k2不存在都返回空(nil)

## hmset / hmget
HMSET key field value [field value ...]
HMGET key field [field ...]
+ `hmset student id 7 name daniu age 26`插入成功返回ok.失败error.
+ `hmget student id nameee age`返回三条数据,依次是对应的v2。第二条是空(nil)。

# hsetnx
+ `hsetnx user id 25`如果不存在则添加。添加成功返回1,失败返回0

## hincrby / hincrbyfloat
+ `hincrby student id 2`执行一次id的值都会增长2。返回增加后的值
+ `hincrbyfloat id 1.1`执行一次id的值都会增长1.1。返回增加后的值

### hkeys / hvals / hgetall
+ `hkeys student`得到k1=student中所有的k2
+ `hvals student`得到k1=student中所有的v2
+ `hgetall student`返回6条数据。依次是"id" "7" "name" "daniu" "age" "26"

# hexists
HEXISTS key field
返回值
1 :hash里面包含该field。
0 :hash里面不包含该field或者key不存在。
+ `hexists student id`

# hlen
+ `hlen student`返回key里面的field数量

# HSTRLEN
返回hash指定field的value的字符串长度,如果hash或者field不存在,返回0.
redis> HMSET myhash f1 HelloWorld f2 99 f3 -256
OK
redis> HSTRLEN myhash f1
(integer) 10
redis> HSTRLEN myhash f2
(integer) 2
redis> HSTRLEN myhash f3
(integer) 4

# hdel
HDEL key field [field ...]
+ `hdel student name`删除k1为student k2为name的数据。删除成功返回1,失败返回0
+ `hdel student id name ...`删除多条记录。返回删除k2的成功数量。【未验证】

使用场景

1)、对象缓存

1
2
3
4
5
127.0.0.1:6379> HMSET user 1:name daniu 1:age 18
OK
127.0.0.1:6379> HMGET user 1:name 1:age
1) "daniu"
2) "18"

2)、电商购物车

1
2
3
4
5
6
7
8
9
10
1. 以用户id为key
2. 商品id为field
3. 商品数量为value

购物车操作
1. 添加商品-> hset cart:1 2 3 # 1号用户,2号商品,商品数量3个
2. 增加数量-> hincrby cart:1 2 1
3. 商品总数-> hlen cart:1
4. 删除商品-> hdel cart:1 2
5. 获取购物车所有商品-> hgetall cart:1

在这里插入图片描述

优点&缺点

1
2
3
4
5
6
7
8
9
# 优点
1、方便数据管理。同类数据可以归类整合进行储存
2、相比String操作,消耗内存与CPU更小
3、相比String存储更节省空间

# 缺点
1、过期功能只能使用在key上,不能作用于field
2、Redis集群下不适合大规模使用,可能会多个key落入同一个节点。
要通过方法使hash的key落到其他节点。

Zset

有序set集合

Zset(sorted set) 有序集合 和set一样不允许重复,不同的是每个元素都会关联一个double类型的分数,
通过这些分数从大到小降序排列,成员是唯一的,分数是可以重复的

》》》多说一句
sadd基础上,加一个score
之前sadd是k1 v1 v2 v3 …
现在zset是k1 score1 v1 score2 v2 … 在sadd基础上,加一个score

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# ZADD
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
XX: 仅仅更新存在的成员,不添加新成员。
NX: 不更新存在的成员。只添加新成员。
CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
127.0.0.1:6379> ZADD k1 10 v1 20 v2 30 v1 # 如果有重复的,后者的30会覆盖前者。返回添加成员的数量
(integer) 2
127.0.0.1:6379> ZRANGE k1 0 -1 withscores
1) "v2"
2) "20"
3) "v1"
4) "30"

## ZRANGE / ZREVRANGE
ZRANGE/ZREVRANGE key start stop [WITHSCORES]
返回元素按照得分从小到大/从大到小排列,若得分相同,将按字典排序。

参数start和stop都是基于零的索引,即0是第一个元素,1是第二个元素,以此类推。
它们也可以是负数,表示从有序集合的末尾的偏移量,其中-1是有序集合的最后一个元素,-2是倒数第二个元素,等等。

start和stop都是全包含的区间,因此例如:ZRANGE myzset 0 1将会返回有序集合的第一个和第二个元素。

超出范围的索引不会产生错误。 如果start参数的值大于有序集合中的最大索引,或者start > stop,将会返回一个空列表。
如果stop的值大于有序集合的末尾,Redis会将其视为有序集合的最后一个元素。

可以传递WITHSCORES选项,以便将元素的分数与元素一起返回。
这样,返回的列表将包含value1,score1,...,valueN,scoreN,而不是value1,...,valueN。
客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或记录)。

返回值:给定范围内的元素列表(如果指定了WITHSCORES选项,将同时返回它们的得分)。
127.0.0.1:6379> ZADD vip 10 v1 20 v2 30 v3 10 v4
(integer) 4
127.0.0.1:6379> ZRANGE vip 0 -1 //查看全部
1) "v1"
2) "v4"
3) "v2"
4) "v3"
127.0.0.1:6379> ZRANGE vip 1 3 withscores // 排除了10 v1,查看坐标1 2 3
1) "v4"
2) "10"
3) "v2"
4) "20"
5) "v3"
6) "30"
127.0.0.1:6379> ZREVRANGE vip 1 3 withscores // 排除了30 v3
1) "v2"
2) "20"
3) "v4"
4) "10"
5) "v1"
6) "10"


## ZRANGEBYSCORE / ZREVRANGEBYSCORE
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD vip 1 v1 2 v2 3 v3 4 v4 5 v5 6 v6 7 v7 8 v8 9 v9 10 v10 11 v11 12 v12 13 v13
(integer) 13
127.0.0.1:6379> ZRANGEBYSCORE vip -inf +inf // [负无穷,正无穷]
1) "v1"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
6) "v6"
7) "v7"
8) "v8"
9) "v9"
10) "v10"
11) "v11"
12) "v12"
13) "v13"
127.0.0.1:6379> ZRANGEBYSCORE vip 1 (3 // [1,3) -> 1,2
1) "v1"
2) "v2"
127.0.0.1:6379> ZRANGEBYSCORE vip 1 10 withscores limit 2 3 // 查询[1,10] 跳过前2个,取3个 -> 3,4,5
1) "v3"
2) "3"
3) "v4"
4) "4"
5) "v5"
6) "5"
127.0.0.1:6379> ZREVRANGEBYSCORE vip 3 (1 // [3,1) -> 3,2 ZREVRANGEBYSCORE是倒序
1) "v3"
2) "v2"


## ZRANK / ZREVRANK
ZRANK/ZREVRANK key member
ZRANK:按照分数从小到大排序,同分数按照字典从小到大排序。返回member对应下标,0表示第一个元素
ZREVRANK:倒序
127.0.0.1:6379> ZADD svip 10 v1 20 v2 30 v3 10 v4
(integer) 4
127.0.0.1:6379> ZRANGE svip 0 -1
1) "v1"
2) "v4"
3) "v2"
4) "v3"
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> ZRANK svip v1
(integer) 0
127.0.0.1:6379> ZRANK svip v4
(integer) 1
127.0.0.1:6379> ZRANK svip v2
(integer) 2
127.0.0.1:6379> ZRANK svip v7 // 不存在v7
(nil)
127.0.0.1:6379> ZREVRANK svip v1 // ZREVRANK倒序
(integer) 3


# ZSCORE
ZSCORE key member
返回值:member成员的score值(double型浮点数),以字符串形式表示。
127.0.0.1:6379> ZADD svip 10 v1 20 v2 30 v3
(integer) 3
127.0.0.1:6379> ZSCORE svip v1
"10"
127.0.0.1:6379> ZSCORE svip v4 //不存在返回(nil)
(nil)


# zcard
+ `zcard zset01`key存在的时候,返回有序集的元素个数,否则返回0

# zcount
+ ZCOUNT myzset -inf +inf //[负无穷,正无穷]
+ `zcount zset01 60 70`返回分数在[60,70]的数量。
+ `zcount zset01 60 (70`返回分数在[60,70)的数量。
+ `zcount zset01 (60 (70`返回分数在(60,70)的数量。

# ZREM
ZREM key member [member ...]
返回的是从有序集合中删除的成员个数,不包括不存在的成员。
127.0.0.1:6379> ZADD svip 1 v1 2 v2 3 v3
(integer) 3
127.0.0.1:6379> ZREM svip v1 v2 v4
(integer) 2
127.0.0.1:6379> ZRANGE svip 0 -1
1) "v3"

# ZREMRANGEBYRANK
ZREMRANGEBYRANK key start stop
按照分数从小到大排序,同分数,按照成员的字典从小到大排序
start stop为下标,0表示第一个元素,1表示第二个,-1表示分数最高的元素,-2表示分数第二高的
返回删除的元素的个数
127.0.0.1:6379> ZADD svip 1 v1 2 v2 3 v3 1 v4
(integer) 4
127.0.0.1:6379> ZRANGE svip 0 -1
1) "v1"
2) "v4"
3) "v2"
4) "v3"
127.0.0.1:6379> ZREMRANGEBYRANK svip 1 2 //删除了v4 v2
(integer) 2
127.0.0.1:6379> ZRANGE svip 0 -1
1) "v1"
2) "v3"

# ZREMRANGEBYSCORE
ZREMRANGEBYSCORE key min max
min max 可以默认包含,可以使用(min 表示不包含, -inf +inf表示正无穷 负无穷
返回删除的元素的个数
127.0.0.1:6379> ZADD svip 1 v1 2 v2 3 v3
(integer) 3
127.0.0.1:6379> ZREMRANGEBYSCORE svip -inf (3
(integer) 2
127.0.0.1:6379> ZRANGE svip 0 -1
1) "v3"


# ZINCRBY
ZINCRBY key increment member
为有序集key的成员member的score值加上增量increment。
如果key中不存在member,就在key中添加一个member,score是increment(就好像它之前的score是0.0)。
如果key不存在,就创建一个只含有指定member成员的有序集合。

当key不是有序集类型时,返回一个错误。

score值必须是字符串表示的整数值或双精度浮点数,并且能接受double精度的浮点数。
也有可能给一个负数来减少score的值。
127.0.0.1:6379> ZADD k1 10 v1 20 v2 -inf v3 +inf v4
(integer) 4
127.0.0.1:6379> ZINCRBY k1 10 v1 #
"20" # 以字符串形式返回member成员的score值
127.0.0.1:6379> ZINCRBY k1 -5 v1
"15"

## ZPOPMIN / ZPOPMAX
ZPOPMIN/ZPOPMAX key [count]
删除并返回key中分数最低/最高的成员,count默认是1

返回值: 弹出的元素和分数列表。
127.0.0.1:6379> ZPOPMIN vip
1) "v1"
2) "10"
127.0.0.1:6379> ZPOPMIN vip 2
1) "v3"
2) "10"
3) "v4"
4) "10"
127.0.0.1:6379> ZPOPMIN vip 2
1) "v2"
2) "20"
3) "v5"
4) "30"

## BZPOPMIN / BZPOPMAX
BZPOPMIN/BZPOPMAX key [key ...] timeout
B -> Blocking 带有阻塞功能的版本。

参数 timeout 可以理解为客户端被阻塞的最大秒数值,0 表示永久阻塞。


# ZUNIONSTORE
并集
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

numkeys:表示要指定key的数量
WEIGHTS:为指定的key指定一个乘法因子。默认1
AGGREGATE:默认SUM
例如:ZUNIONSTORE k3 2 k1 k2 weights 2 3
把k1,k2合并为k3,k1中的分数都扩大2倍,k2中的分数都扩大3倍,k1,k2中名称相同的成员进行分数SUM相加

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> ZADD k1 1 v1 2 v2 3 v3
(integer) 3
127.0.0.1:6379> ZADD k2 4 v1 5 v2
(integer) 2
127.0.0.1:6379> ZUNIONSTORE k3 2 k1 k2 weights 2 3
(integer) 3
127.0.0.1:6379> ZRANGE k3 0 -1 withscores
1) "v3"
2) "6" // 3*2
3) "v1"
4) "14" // 1*2 + 4*3
5) "v2"
6) "19" // 2*2 + 5*3

# ZINTERSTORE
交集
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
用法同:并集ZUNIONSTORE,只不过ZINTERSTORE是只取key的交集
如果只有一个key,则相当于复制内容,只是把score扩大weight倍
127.0.0.1:6379> ZADD k1 1 v1 2 v2 3 v3
(integer) 3
127.0.0.1:6379> ZADD k2 4 v1 5 v2
(integer) 2
127.0.0.1:6379> ZINTERSTORE k3 2 k1 k2 weights 2 3
(integer) 2
127.0.0.1:6379> ZRANGE k3 0 -1 withscores
1) "v1"
2) "14"
3) "v2"
4) "19"

#### 关于LEX ###
操作的是Zset集合,是按照Zset集合中成员的字典顺序来排序的,
所以集合中的成员的score必须是一样的,若不一样,可能会造成结果的错误。

# ZRANGEBYLEX
ZRANGEBYLEX 返回指定成员区间内的成员,按成员字典正序排序, 分数必须相同。 分数不相同,结果可能会不准确。
在某些业务场景中,需要对一个字符串数组按名称的字典顺序进行排序时,可以使用Redis中SortSet这种数据结构来处理。
ZRANGEBYLEX key min max [LIMIT offset count]
min:- 表示无下限,[包含,(不包含
max:+ 表示无上限,[包含,(不包含
LIMIT offset count:对结果跳过offset个,再取count个元素
127.0.0.1:6379> ZADD svip 0 v1 0 v2 0 v3 0 v4 0 v11
(integer) 5
127.0.0.1:6379> ZRANGEBYLEX svip - [v2
1) "v1"
2) "v11"
3) "v2"
127.0.0.1:6379> ZRANGEBYLEX svip - (v4 limit 1 2
1) "v11"
2) "v2"

# ZREVRANGEBYLEX
ZREVRANGEBYLEX key max min [LIMIT offset count]
道理同ZRANGEBYLEX,只不过它是倒序

# ZLEXCOUNT
返回有序集合中成员名称在指定范围的成员数量; Integer类型。
ZLEXCOUNT key min max
127.0.0.1:6379> ZADD svip 0 v1 0 v2 0 v3 0 v4 0 v11
(integer) 5
127.0.0.1:6379> ZLEXCOUNT svip [v1 (v3 // v1,v11,v2
(integer) 3

# ZREMRANGEBYLEX
ZREMRANGEBYLEX key min max
127.0.0.1:6379> ZADD svip 0 v1 0 v2 0 v3 0 v4 0 v11
(integer) 5
127.0.0.1:6379> ZREMRANGEBYLEX svip [v1 (v3 // 删除了v1 v11 v2
(integer) 3
127.0.0.1:6379> ZRANGE svip 0 -1
1) "v3"
2) "v4"

应用场景

1)、微博热搜排行榜

1
2
3
4
5
6
7
8
9
10
11
# 点击新闻,浏览量 + 1
ZINCRBY hotNews:20200624 1 疫情高考政策 // 1表示score+1

# 展示当天排行前十
ZREVRANGE hotNews:20200624 0 9 withscores

# 七日搜索榜单计算
ZUNIONSTORE hotNews:20200617-20200624 7 hotNews:20200617 hotNews:20200618 ...

# 展示七日排行前十
ZREVRANGE hotNews:20200617-20200624 0 9 withscores

Geospatial

地理空间

经纬度查询【便民查询网】
可以用于附近的人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# GEOADD
添加一个或多个地理空间位置到sorted set
GEOADD k1 经度1 纬度1 v1[ 经度2 纬度2 v2]
+ 有效的经度从-180度到180度。
+ 有效的纬度从-85.05112878度到85.05112878度。
127.0.0.1:6379> GEOADD china:city 116.23128 40.22077 beijing
(integer) 1
127.0.0.1:6379> GEOADD china:city 121.48941 31.40527 shanghai
(integer) 1
127.0.0.1:6379> GEOADD china:city 106.54041 29.40268 chongqing
(integer) 1
127.0.0.1:6379> GEOADD china:city 120.21201 30.2084 hangzhou
(integer) 1
127.0.0.1:6379> GEOADD china:city 113.88308 22.55329 shenzhen
(integer) 1
127.0.0.1:6379> GEOADD china:city 108.93425 34.23053 xian
(integer) 1

# GEOPOS
返回地理空间的经纬度
+ GEOPOS key member [member ...]
127.0.0.1:6379> GEOPOS china:city beijing
1) 1) "116.23128265142440796" # 经度
2) "40.22076905438526495" # 纬度
127.0.0.1:6379> GEOPOS china:city beijing shanghai
1) 1) "116.23128265142440796"
2) "40.22076905438526495"
2) 1) "121.48941010236740112"
2) "31.40526993848380499"

# GEOHASH
返回一个标准的地理空间的Geohash字符串
+ GEOHASH key member [member ...]
127.0.0.1:6379> GEOHASH china:city beijing shanghai
1) "wx4sucvncn0"
2) "wtw6st1uuq0"

# GEODIST
GEODIST key member1 member2 [m|km|ft|mi]
返回两个地理空间之间的直线距离
+ m 表示单位为米。
+ km 表示单位为千米。
+ mi 表示单位为英里。
+ ft 表示单位为英尺。
127.0.0.1:6379> GEODIST china:city beijing shanghai km # 查看北京到上海直线距离
"1088.6444"
+ 北京与上海之间的直线距离_百度知道
+ 2011年4月1日 - 回答:北京到上海直线距离1080公里.

# GEORADIUS
查询指定半径内所有的地理空间元素的集合。
+ GEORADIUS key 经度 纬度 m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT n] [ASC|DESC]
WITHCOORD:带有经纬度
WITHDIST:带有距离
WITHHASH:显示经纬度Hash值
COUNT n:显示n条
ASC:根据中心的位置, 按照从近到远的方式返回位置元素。
DESC:根据中心的位置, 按照从远到近的方式返回位置元素。
+ m 表示单位为米。
+ km 表示单位为千米。
+ mi 表示单位为英里。
+ ft 表示单位为英尺。
127.0.0.1:6379> GEORADIUS china:city 100 30 1000 km
1) "chongqing"
2) "xian"
127.0.0.1:6379> GEORADIUS china:city 100 30 1000 km WITHCOORD WITHDIST COUNT 4 DESC
1) 1) "xian"
2) "963.6929"
3) 1) "108.93425256013870239"
2) "34.23053097599082406"
2) 1) "chongqing"
2) "635.2845"
3) 1) "106.54040783643722534"
2) "29.40268053517299762"
127.0.0.1:6379> GEORADIUS china:city 100 30 10000 km WITHCOORD WITHDIST COUNT 4 DESC
1) 1) "shanghai"
2) "2057.8186"
3) 1) "121.48941010236740112"
2) "31.40526993848380499"
2) 1) "hangzhou"
2) "1942.4465"
3) 1) "120.21200805902481079"
2) "30.20839995425554747"
3) 1) "beijing"
2) "1858.5506"
3) 1) "116.23128265142440796"
2) "40.22076905438526495"
4) 1) "shenzhen"
2) "1611.4036"
3) 1) "113.88307839632034302"
2) "22.55329111565713873"

# GEORADIUSBYMEMBER
查询指定半径内匹配到的最大距离的一个地理空间元素。
+ GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT n]
127.0.0.1:6379> GEORADIUSBYMEMBER china:city xian 1000 km
1) "xian"
2) "chongqing"
3) "beijing"

# 【拓展】底层使用的是Zset封装的
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379>
127.0.0.1:6379> ZREM china:city chongqing xian shenzhen
(integer) 3

HyperLogLogs

基数统计

用于网站的UV(访问量)

基数介绍:
A(1 ,3 ,5 ,7)
B(1 ,5 ,7 ,9)
基数(不重复的元素):=3,可以接受误差!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# PFADD
+ 将指定元素添加到HyperLogLog,内部被修改了,那么返回 1,否则返回 0 .
+ PFADD key element [element ...]
127.0.0.1:6379> PFADD k1 a b c d a b c
(integer) 1
127.0.0.1:6379> PFADD k1 a
(integer) 0

# PFCOUNT
统计数量
+ PFCOUNT key [key ...]
127.0.0.1:6379> PFCOUNT k1
(integer) 4

# PFMERGE
把多个sourcekey合并成一个destkey
PFMERGE destkey sourcekey [sourcekey ...]
127.0.0.1:6379> PFADD k1 a b c d e
(integer) 1
127.0.0.1:6379> PFADD k2 c d e f g
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> PFMERGE k3 k1 k2 # 把k1 k2合并成k3
OK
127.0.0.1:6379> PFCOUNT k3
(integer) 7

Bitmaps

位图

位运算

模式:使用 bitmap 实现用户上线次数统计
Bitmap 对于一些特定类型的计算非常有效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# SETBIT
【设置周一到周日的签到情况】
设置或者清空key的value(字符串)在offset处的bit值。
那个位置的bit要么被设置,要么被清空,这个由value(只能是0或者1)来决定。
当key不存在的时候,就创建一个新的字符串value。
要确保这个字符串大到在offset处有bit值。
参数offset需要大于等于0,并且小于2^32(限制bitmap大小为512)。
2^32÷8÷1024÷1024=512MB(÷8 bit转B,÷1024 B转KB ÷1024 KB转MB)
当key对应的字符串增大的时候,新增的部分bit值都是设置为0。
+ SETBIT key offset value
127.0.0.1:6379> SETBIT login 1 1
(integer) 0
127.0.0.1:6379> SETBIT login 2 1
(integer) 0
127.0.0.1:6379> SETBIT login 3 1
(integer) 0
127.0.0.1:6379> SETBIT login 4 0
(integer) 0
127.0.0.1:6379> SETBIT login 5 0
(integer) 0
127.0.0.1:6379> SETBIT login 6 0
(integer) 0
127.0.0.1:6379> SETBIT login 7 0
(integer) 0

# GETBIT
【查看周三是否签到】
返回key对应的string在offset处的bit值 当offset超出了字符串长度的时候,
这个字符串就被假定为由0比特填充的连续空间。
当key不存在的时候,它就认为是一个空字符串,
所以offset总是超出范围,然后value也被认为是由0比特填充的连续空间。到内存分配。
+ GETBIT key offset
127.0.0.1:6379> GETBIT login 3
(integer) 1

# BITCOUNT
【统计这周签到多少次】
统计字符串被设置为1的bit数.
127.0.0.1:6379> BITCOUNT login
(integer) 3

事务

Redis 事务中文文档

命令简介

1
2
3
4
5
6
7
8
9
10
11
12
MULTI(开启事务)
...(把命令插入事务队列)
DISCARD(取消事务,回滚)
还具有UNWATCH的功能
EXEC(执行事务)
把事务中的命令按照入队的顺序依次执行

WATCH(开启监控,乐观锁)
结合CAS去理解
可以WATCH多个key:WATCH key [key ...]
UNWATCH(取消监控)
取消所有被监控的key

正常执行事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k1 v1
QUEUED
127.0.0.1:6379> SET k2 v2
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
127.0.0.1:6379> MGET k1 k2
1) "v1"
2) "v2"

取消事务

取消事务,全部不执行,注意,DISCARD具有UNWATCH的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k1 v1
QUEUED
127.0.0.1:6379> SET k2 v2
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> SET k3 v3
OK
127.0.0.1:6379> EXEC
(error) ERR EXEC without MULTI
127.0.0.1:6379>
127.0.0.1:6379> MGET k1 k2 k3
1) (nil)
2) (nil)
3) "v3"

(编译异常)全部失败

(编译异常)一个入队失败,全部不执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k1 k2
QUEUED
127.0.0.1:6379> seteeeee k2 v2 # 入队失败,没有该命令
(error) ERR unknown command `seteeeee`, with args beginning with: `k2`, `v2`,
127.0.0.1:6379> SET k3 v3
QUEUED
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> mget k1 k2 k3
1) (nil)
2) (nil)
3) (nil)

(运行时异常)部分失败

(运行时异常)全部入队成功,部分命令可能会执行失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k1 v1
QUEUED
127.0.0.1:6379> incr k1 # 不能对字符串进行+1操作,但入队成功
QUEUED
127.0.0.1:6379> SET k2 v2
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
127.0.0.1:6379> mget k1 k2
1) "v1"
2) "v2"

不进行WATCH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SET k1 100
OK
127.0.0.1:6379> SET k2 100
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incrby k1 10
QUEUED
127.0.0.1:6379> decrby k2 10
QUEUED
# 执行exec之前,另外一个客户端执行了:incrby k1 10
127.0.0.1:6379> EXEC # 执行失败
1) (integer) 120
2) (integer) 90
127.0.0.1:6379> mget k1 k2
1) "120"
2) "90"

进行WATCH监控

进行WATCH乐观锁监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SET k1 100
OK
127.0.0.1:6379> SET k2 100
OK
127.0.0.1:6379> WATCH k1 # 开启监控锁
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incrby k1 10
QUEUED
127.0.0.1:6379> decrby k2 10
QUEUED
# 执行exec之前,另外一个客户端执行了:incrby k1 10
127.0.0.1:6379> EXEC # 执行失败
(nil)
127.0.0.1:6379> mget k1 k2
1) "110"
2) "100"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incrby k1 10
QUEUED
127.0.0.1:6379> decrby k2 10
QUEUED
# 执行exec之前,另外一个客户端没有对k1执行操作
127.0.0.1:6379> EXEC # 正常执行
1) (integer) 120
2) (integer) 90
127.0.0.1:6379> UNWATCH # 取消监控锁
OK

Jedis操作

更多参考Redis【4】Java Jedis 操作 Redis

0)、引入依赖

1
2
3
4
5
6
7
8
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>

1)、测试连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package taopanfeng;

import redis.clients.jedis.Jedis;

/**
* 描述
*
* @author 陶攀峰
* @version 1.0
* @date 2020-06-11 10:18
*/
public class TestPing
{


public static void main(String[] args)
{
Jedis jedis = new Jedis("192.168.1.1", 6379);
System.out.println(jedis.ping());// PONG

//Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: Failed connecting to 192.168.1.1:6379
//Caused by: java.net.ConnectException: Connection refused: connect
//
//
// 注意:外部连接,需要修改redis.conf配置文件
// protected-mode yes -> 改为 protected-mode no 允许外部连接
// bind 127.0.0.1 -> 改为 bind 0.0.0.0 允许所有ip连接


SetParams setParams = new SetParams();
setParams.nx();
setParams.px(5000);
jedis.set("lock", "v1", setParams);// 加锁
jedis.del("lock");// 放锁
}
}

2)、输出结果
在这里插入图片描述

3)、操作和我们的命令都是一样的
在这里插入图片描述

4)、事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package taopanfeng;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.util.List;

/**
* 描述
*
* @author 陶攀峰
* @version 1.0
* @date 2020-06-11 10:53
*/
public class TestTX
{
public static void main(String[] args)
{
Jedis jedis = new Jedis("192.168.1.1", 6379);

jedis.flushAll(); // 清空数据
jedis.watch("k1"); // 开启监控

Transaction multi = jedis.multi();// 开启事务

try
{
multi.set("k1","v1");
int i=0/0; // 模拟异常
multi.set("k2","v2");
List<Object> exec = multi.exec(); // 执行事务
} catch (Exception e)
{
multi.discard();// 取消事务,并取消监控
e.printStackTrace();
} finally
{
System.out.println(jedis.get("k1"));
System.out.println(jedis.get("k2"));
jedis.unwatch();// 取消监控
jedis.close(); //关闭连接
}

}
}

SpringBoot整合

参考SpringBoot整合Redis

Redis配置文件

Redis配置文件下载
更多参考redis最全配置讲解

Redis.conf文件,6.0配置

1)、说明
、可以在启动时加上参数,例如:redis-server --port 6380 --slaveof 127.0.0.1 6379
、如果要指定配置文件,要把配置文件放在第一个参数:redis-server /usr/local/etc/redis/redis.conf --port 6380 --slaveof 127.0.0.1 6379
、获取配置config get 配置key
、设置配置,临时生效,重启server失效config set 配置key "xxx"
、如果配置文件key的值存在多个可使用空格作为间隔,例如:bind 192.168.1.1 192.168.1.2
、单位不区分大小写
在这里插入图片描述

2)、INCLUDES
、包含一段配置文件

1
2
# include /path/to/local.conf
# include /path/to/other.conf

3)、MODULES
、加载一下模块(了解)

1
2
# loadmodule /path/to/my_module.so
# loadmodule /path/to/other_module.so

4)、NETWORK
网络

1
2
3
4
5
6
7
8
9
10
11
12
13
# 默认本地访问,可指定其他的IP进行远程外部访问
bind 127.0.0.1 # 默认
# bind 192.168.1.100 192.168.1.101 #指定多个
# bind 0.0.0.0 # 全通配

protected-mode yes # 是否受保护,如果想外部访问设为no

port 6379 # 绑定端口

# TCP连接,不用管
tcp-backlog 511
timeout 0 # 超时时间,秒(0表示禁用)
tcp-keepalive 300 # 存活时间,秒

5)、TLS/SSL
省略

6)、GENERAL
通用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
daemonize no # 守护进程开启,no表示后台运行

supervised no # 管理守护进程的,默认no

pidfile /var/run/redis_6379.pid # 如果以后来运行,要指定一个进程文件

# 日志级别
* debug(大量信息,对开发/测试很有用)
* verbose(很多很少有用的信息,但不像调试级别那样混乱)
* notice(可能比较冗长,您在生产环境中想要的内容)
* warning(只有非常重要/关键的消息被记录)
loglevel notice # 默认生产环境使用

logfile "" # 日志文件名,如果为空,就是标志输出

databases 16 # 默认数据库数量

always-show-logo yes # 启动Redis时,是否显示logo,默认开启

7)、SNAPSHOTTING
快照

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 持久化,在规定的时间内,执行了多少次操作,则会持久化到文件:rdb,aof
# Redis是内存数据库,没有持久化,则断电及失
#save <seconds> <changes>
save 900 1 # 900秒内,1个key进行了修改就持久化
save 300 10 # 300秒内,10个key进行了修改就持久化
save 60 10000 # 60秒内,10000个key进行了修改就持久化

stop-writes-on-bgsave-error yes # 持久化如果出错了,是否还继续工作

rdbcompression yes # 是否压缩RDB文件,需要消耗CPU资源

rdbchecksum yes # 保存RDB文件的时候,进行错误的校验,检查

dbfilename dump.rdb # RDB文件名称

rdb-del-sync-files no # 没有启用持久化的情况下,删除从机(副本)的RDB文件

dir ./ # 文件保存目录

8)、REPLICATION
主从复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# replicaof <masterip> <masterport># 主从复制选项,本机为从机,设置主机的IP和端口

# masterauth <master-password> # 设置主机的密码

# 从机与主机失去连接时,从机运行两种方式
* yes:默认。会继续响应客户端请求
* no:除了以下命令,其他命令都返回"SYNC with master in progress"
INFO, replicaOF, AUTH, PING, SHUTDOWN, REPLCONF, ROLE, CONFIG,
SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB,
COMMAND, POST, HOST: and LATENCY.
replica-serve-stale-data yes

replica-read-only yes # 从机,默认只读。可改为NO,用于写(不建议)

# diskless无磁盘,也就是socket方式
* no:默认。以磁盘方式复制数据。磁盘读取快,推荐。
* yes:以socket方式复制数据。网速快,推荐。
repl-diskless-sync no

repl-diskless-sync-delay 5 # 复制延迟,5秒

repl-diskless-load disabled # 禁用无磁盘加载(socket),首先将rdb文件存储到磁盘

# repl-ping-replica-period 10 # 从机向主机10秒发送一次ping心跳

# repl-timeout 60 # 从机,连接超时时间

repl-disable-tcp-nodelay no # 禁用tcp连接,无延迟,默认不禁用。yes增加延迟,no延迟减少

replica-priority 100 # 主机挂了,哨兵会精选主机,权重低的被选中。0表示不参与选举。

9)、KEYS TRACKING
省略

10)、SECURITY
安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 设置密码,默认为空,可以配置密码,持久化
# requirepass foobared
# 也可以使用 CONFIG命令设置临时密码,重启server失效

[root@localhost redis]# docker exec -it redis01 bash
root@856d3e9b4533:/data# redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> CONFIG GET requirepass # 获取密码
1) "requirepass"
2) ""
127.0.0.1:6379> CONFIG SET requirepass "123456" # 设置密码,临时生效,重启服务不生效
OK
127.0.0.1:6379> exit
root@856d3e9b4533:/data#
root@856d3e9b4533:/data#
root@856d3e9b4533:/data# redis-cli
127.0.0.1:6379> ping
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> ping
PONG

11)、CLIENTS
客户端

1
# maxclients 10000 # 设置最大连接数

12)、MEMORY MANAGEMENT
内存管理

1
2
3
4
5
6
7
8
9
10
11
12
# maxmemory <bytes> # 最大内存

# 内存满了之后的处理策略
* volatile-lru -> 仅使用带过期集的key,使用近似的LRU进行删除。
* allkeys-lru -> 使用近似的LRU删除任何key。
* volatile-lfu -> 仅使用带过期集的key,使用近似的LFU删除。
* allkeys-lfu -> 使用近似的LFU删除任何key。
* volatile-random -> 删除具有过期集的随机key。
* allkeys-random -> 删除一个随机的key,任何key。
* volatile-ttl -> 删除最近过期时间的key(较小的TTL)
* noeviction -> 不删除任何东西,只是在写操作上返回一个错误。
# maxmemory-policy noeviction

13)、LAZY FREEING
14)、THREADED I/O
线程IO

1
2
3
4
975 # Redis is mostly single threaded, however there are certain threaded
976 # operations such as UNLINK, slow I/O accesses and other things that are
977 # performed on side threads.
Redis大部分是单线程的,但是也有一些线程操作,如解除链接,缓慢的I/O访问和其他事情是在侧线程上执行的。

15)、APPEND ONLY MODE
AOF追加模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
appendonly no # 默认不开启AOF模式。大部分情况下,RDB够用了

appendfilename "appendonly.aof" # AOF文件名称

# appendfsync always # 每次修改都会同步,效率慢
appendfsync everysec # 每秒同步一下,可能丢失1秒数据
# appendfsync no # 不执行同步,FS操作系统自己同步

no-appendfsync-on-rewrite no # 是否重写,默认否,一直追加

auto-aof-rewrite-percentage 100 # 100%表示全部重写
auto-aof-rewrite-min-size 64mb # 重写最小64mb,达到64mb就进行文件重写

# AOF可能存在错误。
* yes:aof文件被导入的时候,会自动发布一个log给客户端然后load。
* no:用户必须手动redis-check-aof修复AOF文件才可以。
aof-load-truncated yes

aof-use-rdb-preamble yes # 使用RDB作为前言,先重写RDB,再重新AOF,AOF追加

16)、LUA SCRIPTING LUA脚本
17)、REDIS CLUSTER Redis集群

1
2
3
4
5
6
7
# cluster-enabled yes # 默认不开启集群

# cluster-config-file nodes-6379.conf # 每个节点都需要一个单独的配置文件

# cluster-node-timeout 15000 # 节点互连超时的阀值。集群节点超时毫秒数

# cluster-replica-validity-factor 10

18)、CLUSTER DOCKER/NAT support
Docker集群的支持

1
2
3
4
# 案例:
* cluster-announce-ip 10.1.1.5
* cluster-announce-port 6379
* cluster-announce-bus-port 6380

19)、LATENCY MONITOR 延迟监控
20)、EVENT NOTIFICATION 事件通知
21)、GOPHER SERVER
22)、ADVANCED CONFIG 高级配置
23)、ACTIVE DEFRAGMENTATION 激活碎片

Redis持久化

RDB

配置:在上面配置文件7)、SNAPSHOTTING中进行了讲解

0)、简介
Redis DataBase, 对应文件dump.rdb
、能够在指定的时间间隔对你的数据进行快照储存,保存RDB文件时,父进程开启一个子进程,接下来的工作全部由子进程来做,可以最大化Redis性能

1)、测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#save 900 1 # 900秒内修改1次
#save 300 10 # 300秒内修改10次
#save 60 10000 # 60秒内修改1万次
save 20 5 #测试20秒内,修改5次进行持久化

[root@localhost redis]# docker restart redis01 # 修改后,重启容器生效
[root@localhost redis]# docker exec -it redis01 bash
127.0.0.1:6379> CONFIG GET dir # 查看生成在哪个目录下
1) "dir"
2) "/data"
root@856d3e9b4533:/data# mv -f /data/* /tmp/ # 移除所有
root@856d3e9b4533:/data# redis-cli
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379>
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> set k3 v3
OK
127.0.0.1:6379> set k4 v4
OK
127.0.0.1:6379> set k5 v5 # 回车之后,生成dump.rdb文件
OK
127.0.0.1:6379> exit
root@856d3e9b4533:/data# ls # 生成
dump.rdb

2)、触发机制(以下任何一个都会生成dump.rdb文件):
、关闭server端
、执行flushall命令
、满足save条件

3)优缺点
优点
、使用大规模数据恢复
、对数据完整性要求不高!
缺点
、需要一定的间隔时间,如果意外挂了,就会丢失最后一次数据
、开启一份进程进行持久化的时候,会占用一定的时间

AOF

配置:在上面配置文件15)、APPEND ONLY MODE中进行了讲解

0)、简介
Append Only File,对应文件appendonly.aof
、以日志形式来追加记录每一个写操作,恢复需要根据日志文件的命令从头到尾执行一次

1)、测试

1
2
#appendonly no
appendonly yes # 开启AOF

2)、说明
退出server也会生产dump.rdb文件,但不会生成aof文件,只有启动server端,才会生成aof文件。
启动client时,会读取AOF文件。
如果读取aof文件错误,可使用命令修复AOF文件:redis-check-aof --fix appendonly.aof,会把错误的命令去除

3)、优缺点
优点
、每一次修改都同步,文件完整性更好
、每秒同步一次,可能会丢失1秒数据
、从不同步,效率最高
缺点
、对于文件来说,aof比rdb文件要大,修改的速度也比rdb慢。
、aof比rdb的效率慢,所以Redis默认使用rdb

Redis发布订阅

在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+ SUBSCRIBE channel [channel ...]
127.0.0.1:6379> SUBSCRIBE taopanfeng # 订阅频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "taopanfeng"
3) (integer) 1 # 在监听等待监听消息

127.0.0.1:6379> PUBLISH taopanfeng 111 # 往频道推送消息
(integer) 1
127.0.0.1:6379>

127.0.0.1:6379> SUBSCRIBE taopanfeng
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "taopanfeng"
3) (integer) 1
1) "message" # 消息
2) "taopanfeng" # 频道
3) "111" # 消息内容

Redis主从复制

请转自Redis主从复制

Redis哨兵模式

请转自Redis哨兵模式

缓存雪崩/穿透/击穿

1
2
3
4
5
6
7
2021-07-16 09:31:49 补充

雪崩:缓存不存在,数据库存在,高并发,大量key

穿透:缓存不存在,数据库不存在,高并发,少量key

击穿:缓存不存在,数据库存在,高并发,少量key

雪崩

缓存在同一时间内大量key过期(失效)或Redis挂了,接着来的一大波请求瞬间都落在了数据库中导致连接异常。

其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。
因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的。
无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。

解决方案:

1)、Redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。(异地多活!)

2)、限流降级(在SpringCloud讲解过!)
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。
比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

3)、数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。
在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

穿透

缓存查不到,去查数据库,数据库也差不到,导致写入不了缓存。
这会导致每次查询都会去请求数据库,造成缓存穿透;

解决方案:
1)、布隆过滤器
对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;

2)、缓存空对象
当数据库不存在时,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了数据库;

存在问题:
但是这种方法会存在两个问题:
1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
在这里插入图片描述

击穿

这里需要注意和缓存击穿的区别,缓存击穿,是指一个key非常热点,在不停的扛着大并发,
大并发集中 对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,
直接请求数据库,就像在一 个屏障上凿开了一个洞。

当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,
会同时访 问数据库来查询新数据,并且回写缓存,会导使数据库瞬间压力过大。

1)、设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。

2)、加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。
这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

Redis分布式锁:先setnx获取锁,再del释放锁。可能造成长时间等待。会存在超时时间问题。

1
2
3
4
5
6
7
8
9
10
11
Jedis jedis = new Jedis("192.168.1.1", 6379);
System.out.println(jedis.ping());// PONG

SetParams setParams = new SetParams();
setParams.nx();
setParams.px(5000);
// 加锁
jedis.set("lock","v1",setParams);

// 放锁
jedis.del("lock");