Redis基本知识记录

Redis

概念:Redis (REmote DIctionary Server) 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库。

扩展

想要具体环境可以参照本博客,进行配置。

Linux Docker redis、jdk1.8、mysql、nginx、tomcat部署

运行环境

centos7.0

两个虚拟机,一台克隆机。

各自安装了docker redis

启动了docker redis

[root@localhost ~]# docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED       STATUS         PORTS                    NAMES
362e38a62c99   redis:5.0   "docker-entrypoint.s…"   2 weeks ago   Up 5 seconds   0.0.0.0:6379->6379/tcp   c_redis

借此启动两台docker redis服务器,使用RedisDesktopManager软件作为客户端。

代码块代表客户端测试,各种数据格式使用。

key-value中间有一个field作为存储名 

类似于key:hash值,field:名字,value:存储数据

string 类型

string 类型数据的基本操作

添加/修改数据

set key value

获取数据

get key

删除数据

del key 

判定性添加数据

setnx key value 

例子: 

c_redis:0>set name hikktn
"OK"

c_redis:0>get name
"hikktn"

c_redis:0>del name
"1"

c_redis:0>get name
null

c_redis:0>setnx user root
"1"

c_redis:0>get user
"root"

添加/修改多个数据

mset key1 value1 key2 value2 …

获取多个数据

mget key1 key2 … 

获取数据字符个数(字符串长度)

strlen key 

追加信息到原始信息后部(如果原始信息存在就追加,否则新建)

append key value 

 例子:

c_redis:0>mset name1 tom name2 shu
"OK"

c_redis:0>mget name1 name2
 1)  "tom"
 2)  "shu"
c_redis:0>strlen name1 name2
"ERR wrong number of arguments for 'strlen' command"

c_redis:0>strlen name1
"3"

c_redis:0>append name2 su
"5"

c_redis:0>mget name1 name2
 1)  "tom"
 2)  "shusu"

string 类型数据的扩展操作

设置数值数据增加指定范围的值

incr key

# 自增入力值
incrby key increment

# 自增浮点入力值
incrbyfloat key increment

设置数值数据减少指定范围的值

decr key

# 自减入力值
decrby key increment 

设置数据具有指定的生命周期

# 设置几秒后失效

setex key seconds value

#设置几毫秒钟失效
psetex key milliseconds value 

例子: 

incr key和decr key(自增和自减,+1和-1)

c_redis:0>set ace 5
"OK"

c_redis:0>incr ace
"6"

c_redis:0>get ace
"6"

c_redis:0>decr ace
"5"

 incrby key increment和decrby key increment (自增入力值和自减入力值)

c_redis:0>get ace
null

c_redis:0>incrby ace 9
"9"

c_redis:0>incrby ace 10.0
"ERR value is not an integer or out of range"

c_redis:0>incrby ace 100
"109"

c_redis:0>get ace
"109"

c_redis:0>decrby ace 2
"107"

 incrbyfloat key increment(自增浮点数)

c_redis:0>incrbyfloat aoc 10.2
"10.2"

c_redis:0>decrbyfloat aoc 0.2
"ERR unknown command `decrbyfloat`, with args beginning with: `aoc`, `0.2`, "

c_redis:0>get aoc
"10.2"

 setex key seconds value(在10秒钟内失效)

c_redis:0>setex ace 10 109
"OK"

c_redis:0>get ace
"109"

c_redis:0>get ace
null

 psetex key milliseconds value (在5秒钟【毫秒】内失效)

c_redis:0>set ace 100
"OK"

c_redis:0>psetex ace 5000 100
"OK"

c_redis:0>get ace
"100"

c_redis:0>get ace
null

应用场景

关注,粉丝,博客

比如我的博客现在又55篇原创,那么key的命名方式,

  表名 主键名 主键值 字段名
eg1 order id 254858751 user
eg2 fans id 5421884431 type
eg3 blog id 5459982214 txt

 举例:

          博主昵称:hikktn,粉丝数:59;       →→→→ hikktn:id:1213457107:fans   →→→→  59

          博主昵称:hikktn,博客数:55;       →→→→ hikktn:id:1213457107:blog   →→→→  55

          博主昵称:hikktn,点赞数:62;       →→→→ hikktn:id:1213457107:fabulous   →→→→  62

另一种方式(JSON):

         hikktn:id:1213457108       →→→→  {"fans" : 59 , "blog" : 55 , "fabulous" : 62 }

c_redis:0>set hikktn:id:1213457107:fans 59
"OK"

c_redis:0>set hikktn:id:1213457107:blog 55
"OK"

c_redis:0>set hikktn:id:1213457107:fabulous 62
"OK"

c_redis:0>set hikktn:id:1213457108 {\"fans\":59,\"blog\":55,\"fabulous\":62}
"OK"

c_redis:0>get hikktn:id:1213457108
"{"fans":59,"blog":55,"fabulous":62}"

hash 类型

hash 类型数据的基本操作

添加/修改数据

hset key field value

 获取数据

# 获取一个键值

hget key field

# 获取全部键值
hgetall key

删除数据

hdel key field1 [field2]

 设置field的值,如果该field存在则不做任何操作

hsetnx key field value

 例子:

c_redis:0>hset user:root name hikktn
"0"

c_redis:0>hset user:root age 18
"1"

c_redis:0>hgetall user:root
 1)  "name"
 2)  "hikktn"
 3)  "age"
 4)  "18"

c_redis:0>hset user:hikktn name mutouren
"1"

c_redis:0>hget user:hikktn name
"mutouren"

c_redis:0>hdel user:root age
"1"

c_redis:0>hgetall user:root
 1)  "name"
 2)  "hikktn"

c_redis:0>hsetnx user:root name tom
"0"

c_redis:0>hgetall user:root
 1)  "name"
 2)  "hikktn"

添加/修改多个数据

hmset key field1 value1 field2 value2 …

获取多个数据

hmget key field1 field2 …

获取哈希表中字段的数量

hlen key

获取哈希表中是否存在指定的字段

 hexists key field

例子:

c_redis:0>hmset user:1 sex "男" souce "篮球"
"OK"

c_redis:0>hmget user:1 sex souce
 1)  "男"
 2)  "篮球"
c_redis:0>hlen sex
"0"

c_redis:0>hlen user:1
"2"

c_redis:0>hexists user:1 shop
"0"

c_redis:0>hexists user:1 sex
"1"

hash 类型数据扩展操作

获取哈希表中所有的字段名或字段值

hkeys key
hvals key

设置指定字段的数值数据增加指定范围的值

# 需要先创建一个field,才能进行自增入力值

hincrby key field increment
hincrbyfloat key field increment

例子:

c_redis:0>hmset car baoma 100 dazhong 50
"OK"

c_redis:0>hincrby car baoma 30
"130"

c_redis:0>hincrby car baoma -300
"-170"

c_redis:0>hkeys car
 1)  "baoma"
 2)  "dazhong"

c_redis:0>hincrbyfloat car dazhong 30.5
"80.5"

c_redis:0>hvals car
 1)  "-170"
 2)  "80.5"

应用场景

假设有一个商家,商家有三件商品。

商家A 

——商品A,数量:1000

——商品B,数量:30

——商品C,数量:50

用户A购买商品A两件,剩余数量998件。

用户B购买商品C一件,剩余数量49件。

用户C购买商品C一件,剩余数量48件。

c_redis:0>hmset shangjia:A shangpin:A 1000 shangpin:B 30 shangpin:C 50
"OK"

c_redis:0>hincrby shangjia:A shangpin:A -2
"998"

c_redis:0>hincrby shangjia:A shangpin:C -1
"49"

c_redis:0>hincrby shangjia:A shangpin:C -1
"48"

c_redis:0>hgetall shangjia:A
 1)  "shangpin:A"
 2)  "998"
 3)  "shangpin:B"
 4)  "30"
 5)  "shangpin:C"
 6)  "48"

list 类型

list 类型数据基本操作

添加/修改数据

# 从左加入

lpush key value1 [value2] ……

# 从右加入
rpush key value1 [value2] ……

获取数据

# 从左查询 start :开始位置,stop:结束位置

lrange key start stop
lindex key index
llen key

获取并移除数据

# 从最左侧取出(首位处)

lpop key

# 从最右侧取出(末尾处)
rpop key

 例子:

c_redis:0>lpush foodList guazi latiao mianbao
"3"

c_redis:0>lrange foodList 0 2
 1)  "mianbao"
 2)  "latiao"
 3)  "guazi"

c_redis:0>lrange foodList 0 -1
 1)  "mianbao"
 2)  "latiao"
 3)  "guazi"

c_redis:0>rpush foodList shui
"4"

c_redis:0>lrange foodList 0 -1
 1)  "mianbao"
 2)  "latiao"
 3)  "guazi"
 4)  "shui"

c_redis:0>lpop foodList
"mianbao"

c_redis:0>lrange foodList 0 -1
 1)  "latiao"
 2)  "guazi"
 3)  "shui"

c_redis:0>llen foodList
"3"

c_redis:0>lindex foodList 0
"latiao"

c_redis:0>lindex foodList 4
null

list 类型数据扩展操作

移除指定数据

# count : 删除的个数(可去重)

lrem key count value

规定时间内获取并移除数据

# 从左侧获取第一个值,在规定时间内失效(在规定时间内,立即获取到数据,如果没有在规定时间内,获取到数据,就会等待大概规定时间,返回null值。)

# 可以在等待的时间,进行加入,一旦有值,立刻获取到值

blpop key1 [key2] timeout

# 从右侧获取第一个值,在规定时间内失效
brpop key1 [key2] timeout

# 从右侧的第一个值传到左侧第一个值,在规定时间内失效
brpoplpush source destination timeout

 例子:

c_redis:0>lpush paramList a b c a b c a b c b
"10"

c_redis:0>lrange paramList 0 -1
 1)  "b"
 2)  "c"
 3)  "b"
 4)  "a"
 5)  "c"
 6)  "b"
 7)  "a"
 8)  "c"
 9)  "b"
 10)  "a"

c_redis:0>lrem paramList 3 b
"3"

c_redis:0>lrange paramList 0 -1
 1)  "c"
 2)  "a"
 3)  "c"
 4)  "a"
 5)  "c"
 6)  "b"
 7)  "a"

blpop key1 [key2] timeout执行

c_redis:0>lpush a a1
"1"

c_redis:0>blpop a 30
 1)  "a"
 2)  "a1"
c_redis:0>lrange a 0 -1


c_redis:0>

 此时key为a还存在。

c_redis:0>blpop a 30

执行完这条命令,此时数据还是有值,需要等待30秒钟后,键值对就会失效。 

c_redis:0>blpop a 30


c_redis:0>

此时,彻底执行完毕,数据已经失效。

应用场景

数据顺序的查看

多台服务器打印输出的log,方便人员查看。

举例:

          服务器A     输出    2021-03-05 00:30:25 error

          服务器B    输出     2021-03-05 00:30:24 error

          服务器C    输出     2021-03-05 00:31:24 error

c_redis:0>rpush logs a:2021-03-05 00:30:25 error
"3"

c_redis:0>rpush logs a:2021-03-05 00:30:24 error
"6"

c_redis:0>rpush logs c:2021-03-05 00:31:24 error
"9"

c_redis:0>lrange logs 0 -1
 1)  "a:2021-03-05"
 2)  "00:30:25"
 3)  "error"
 4)  "a:2021-03-05"
 5)  "00:30:24"
 6)  "error"
 7)  "c:2021-03-05"
 8)  "00:31:24"
 9)  "error"

set 类型

set 类型数据的基本操作

添加数据

sadd key member1 [member2]

获取全部数据

smembers key

删除数据

srem key member1 [member2]

获取集合数据总量

scard key

判断集合中是否包含指定数据

sismember key member

随机获取集合中指定数量的数据

srandmember key [count]

随机获取集合中的某个数据并将该数据移出集合

spop key [count]

 例子:

c_redis:0>sadd class a b
"2"

c_redis:0>sadd class c
"1"

c_redis:0>sadd class d
"1"

c_redis:0>smembers class
 1)  "d"
 2)  "c"
 3)  "b"
 4)  "a"

c_redis:0>srem class b
"1"

c_redis:0>smembers class
 1)  "d"
 2)  "c"
 3)  "a"

c_redis:0>scard class
"3"

c_redis:0>sismember class a
"1"

c_redis:0>sismember class b
"0"

c_redis:0>srandmember class 2
 1)  "d"
 2)  "a"

c_redis:0>spop class 1
 1)  "a"

c_redis:0>smembers class
 1)  "d"
 2)  "c"

 set 类型数据的扩展操作

求两个集合的交、并、差集

# 交集

sinter key1 [key2 …]

# 并集
sunion key1 [key2 …]

# 差集
sdiff key1 [key2 …]

求两个集合的交、并、差集并存储到指定集合中

sinterstore destination key1 [key2 …]
sunionstore destination key1 [key2 …]
sdiffstore destination key1 [key2 …]

将指定数据从原始集合中移动到目标集合中

smove source destination member

 例子:

c_redis:0>sadd s1 100 600 hikktn
"3"

c_redis:0>sadd s2 100 hikktn
"2"

c_redis:0>sinter s1 s2
 1)  "hikktn"
 2)  "100"

c_redis:0>sunion s1 s2
 1)  "hikktn"
 2)  "100"
 3)  "600"

c_redis:0>sdiff s1 s2
 1)  "600"

c_redis:0>sunionstore s1 s5
"1"

c_redis:0>smembers s1
 1)  "300"

c_redis:0>smembers s5
 1)  "300"

zset类型(有序)

zset 类型数据的基本操作

添加数据

zadd key score member [score member…]

 获取数据

zrange key start stop [WITHSCORES]

 返回有序集中指定区间内的成员,通过索引,分数从高到低

zrevrange key start stop [WITHSCORES]

删除数据

zrem key member [member…]  

key常用指令

key 基本操作

删除指定key

del key

获取key是否存在

exists key

获取key的类型

type key

 key 扩展操作

排序

sort

改名

rename key newkey
renamenx key newkey

 key 扩展操作(时效性控制)

为指定key设置有效期 

expire key seconds
pexpire key milliseconds
expireat key timestamp
pexpireat key milliseconds-timestamp

获取key的有效时间

ttl key
pttl key

切换key从时效性转换为永久性

persist key

 key 扩展操作(查询模式)

查询key

keys pattern

查询模式规则

* 匹配任意数量的任意符号 ? 配合一个任意符号 [] 匹配一个指定符号

keys * 查询所有
keys it* 查询所有以it开头
keys *heima 查询所有以heima结尾
keys ??heima 查询所有前面两个字符任意,后面以heima结尾
keys user:? 查询所有以user:开头,最后一个字符任意
keys u[st]er:1 查询所有以u开头,以er:1结尾,中间包含一个字母,s或t

数据库常用指令

db 基本操作

切换数据库

select index

其他操作

ping

db 扩展操作 

数据移动

move key db

数据总量

dbsize

数据清除

flushdb
flushall

redis持久化 

什么是持久化

利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化
持久化用于防止数据的意外丢失,确保数据安全性

持久化过程保存什么


RDB  数据(日志)

10011001110000001
00101001011010110
10110011001110000
00100101001011011

AOF 过程 (快照)

删除第3行
第4行末位添加字符x
删除第2到第4行
复制第3行粘贴到第5行

 RDB

 save指令进行手动RDB过程

手动执行一次保存操作

save

RDB启动方式 —— save指令相关配置

设置本地数据库文件名,默认值为 dump.rdb,通常设置为dump-端口号.rdb

dbfilename filename

 设置存储.rdb文件的路径,通常设置成存储空间较大的目录中,目录名称data

dir path

 设置存储至本地数据库时是否压缩数据,默认yes,设置为no,节省 CPU 运行时间,但存储文件变大

rdbcompression yes|no

设置读写文件过程是否进行RDB格式校验,默认yes,设置为no,节约读写10%时间消耗,但存在数据损坏的风险

rdbchecksum yes|no

redis.conf 

bind 192.168.135.132
port 6381
# Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
daemonize no
# 因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendonly no
#logfile "6379.log"
dir /redis/data
dbfilename "dump-6381.rdb"
requirepass 123456

 rdb文件就会存储redis的key-value值。

save指令原理 

客户端1:127.0.0.1:6379> set key1 value1

客户端2:127.0.0.1:6379> set key2 value2

客户端3:127.0.0.1:6379> save

客户端4:127.0.0.1:6379> get key1

上面的执行过程:get → save → set → set(单线程任务执行序列)

 注意:save指令的执行会阻塞当前Redis服务器,直到当前RDB过程完成为止,有可能会造成长时间阻塞,线上环境不建议使用。

bgsave指令进行手动RDB过程

RDB启动方式 —— bgsave指令

手动启动后台保存操作,但不是立即执行

bgsave

RDB启动方式 —— bgsave指令相关配置

后台存储过程中如果出现错误现象,是否停止保存操作,默认yes

 stop-writes-on-bgsave-error yes|no

其他

dbfilename filename
dir path
rdbcompression yes|no
rdbchecksum yes|no

停止redis前 

 停止redis后

bgsave原理

注意: bgsave命令是针对save阻塞问题做的优化。Redis内部所有涉及到RDB操作都采用bgsave的方式,save命令可以放弃使用。

 save配置进行自动RDB过程

RDB启动方式 ——save配置
设置自动持久化的条件,满足限定时间范围内key的变化数量达到指定数量即进行持久化

save second changes

参数
      second:监控时间范围
      changes:监控key的变化量

save 900 1
save 300 10
save 60 10000

注意: save配置要根据实际业务情况进行设置,频度过高或过低都会出现性能问题,结果可能是灾难性的
save配置启动后执行的是bgsave操作

三种方式对比(优缺点)

方式 save读写 bgsave读写
读写 同步 异步
阻塞客户端指令
额外内存消耗
启动新进程

RDB特殊启动形式

服务器运行过程中重启

debug reload 

关闭服务器时指定保存数据

shutdown save 

RDB优点

RDB是一个紧凑压缩的二进制文件,存储效率较高
RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
RDB恢复数据的速度要比AOF快很多
应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。 

RDB缺点

 RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据
bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能
Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象

RDB存储的弊端

存储数据量较大,效率较低,基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低
大数据量下的IO性能较低
基于fork创建子进程,内存产生额外消耗
宕机带来的数据丢失风险

 AOF

◆ AOF概念


 AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令
达到恢复数据的目的。与RDB相比可以简单理解为由记录数据改为记录数据产生的变化
AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

启动AOF相关配置

 开启AOF持久化功能,默认no,即不开启状态

appendonly yes|no

AOF持久化文件名,默认文件名为appendonly.aof,建议配置为appendonly-端口号.aof

appendfilename filename

AOF持久化文件保存路径,与RDB持久化文件保持一致即可

dir

 AOF写数据策略,默认为everysec

appendfsync always|everysec|no

◆ AOF执行策略

AOF写数据三种策略(appendfsync)

 always(每次):每次写入操作均同步到AOF文件中
数据零误差,性能较低,不建议使用。
everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,在系统突然宕机的情况下丢失1秒内的数据
数据准确性较高,性能较高,建议使用,也是默认配置
no(系统控制):由操作系统控制每次同步到AOF文件的周期
整体过程不可控

◆ AOF重写

随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。AOF文件重
写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是将对同一个数据的若干个条命令执行结
果转化成最终结果数据对应的指令进行记录。

AOF重写作用

降低磁盘占用量,提高磁盘利用率
提高持久化效率,降低持久化写时间,提高IO性能
降低数据恢复用时,提高数据恢复效率

◆ AOF工作原理

进程内具有时效性的数据,并且数据已超时将不再写入文件
非写入类的无效指令将被忽略,只保留最终数据的写入命令
如del key1、 hdel key2、srem key3、set key4 111、set key4 222等
如select指令虽然不更改数据,但是更改了数据的存储位置,此类命令同样需要记录
对同一数据的多条写命令合并为一条命令
如lpush list1 a、lpush list1 b、 lpush list1 c 可以转化为:lpush list1 a b c。
为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素

AOF重写方式

手动重写

bgrewriteaof

自动重写

auto-aof-rewrite-min-size size
auto-aof-rewrite-percentage percentage 

 自动重写触发比对参数( 运行指令info Persistence获取具体信息 )

aof_current_size
aof_base_size

RDB与AOF区别 

持久化方式 RDB  AOF
占用存储空间  小(数据级:压缩)  大(指令级:重写)
存储速度
恢复速度
数据安全性  会丢失数据 依据策略决定
资源消耗  高/重量级  低/轻量级
启动优先级 

RDB与AOF的选择之惑 

对数据非常敏感,建议使用默认的AOF持久化方案
             AOF持久化策略使用everysecond,每秒钟fsync一次。该策略redis仍可以保持很好的处理性能,当出现问题时,最多丢失0-1秒内的数据。
注意:由于AOF文件存储体积较大,且恢复速度较慢
数据呈现阶段有效性,建议使用RDB持久化方案
数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段点数据恢复通常采用RDB方案
注意:利用RDB实现紧凑的数据持久化会使Redis降的很低,慎重总结:
综合比对
RDB与AOF的选择实际上是在做一种权衡,每种都有利有弊
如不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用AOF

如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB
灾难恢复选用RDB
双保险策略,同时开启 RDB 和 AOF,重启后,Redis优先使用 AOF 来恢复数据,降低丢失数据的量

猜你喜欢

转载自blog.csdn.net/qq_41520636/article/details/114375732