Redis知识点总结

五大数据类型

1.String(字符串)

概念

string类型是二进制安全的,意思是redis的string可以包含任何数据。比如ipg图片或者序列化的对象。
string类型是Redis最基本的数据结构,一个redis中字符串value最多可以是512M
单值单V

命令

1.设置值:

set key value [ex seconds] [px millseconds] [nx|xx]

ex seconds:为键设置秒级过期时间,跟 setex 效果一样
px millseconds:为键设置毫秒级过期时间
nx:键必须不存在才可以设置成功,用于添加,跟 setnx 效果一样。由于 Redis 的单线程命令处理机制,如果多个客户端同时执行,则只有一个客户端能设置成功,可以用作分布式锁的一种实现。
xx:键必须存在才可以设置成功,用于更新
2.获取值:

get key

如果不存在返回nil
3.批量设置值:

mset key value [key value...]

4.批量获取值:

mget key [key...]

批量操作命令可以有效提高开发效率,假如没有 mget,执行 n 次 get 命令需要 n 次网络时间 + n 次命令时间,使用 mget 只需要 1 次网络时间 + n 次命令时间。Redis 可以支持每秒数万的读写操作,但这指的是 Redis 服务端的处理能力,对于客户端来说一次命令处理命令时间还有网络时间。因为 Redis 的处理能力已足够高,对于开发者来说,网络可能会成为性能瓶颈。
5.计数

incr key

incr 命令用于对值做自增操作,返回结果分为三种:
① 值不是整数返回错误。
② 值是整数,返回自增后的结果。
③ 值不存在,按照值为 0 自增,返回结果 1。除了 incr 命令,还有自减 decr自增指定数字 incrby自减指定数组 decrby自增浮点数 incrbyfloat

内部编码

int:8 个字节的长整形
embstr:小于等于 39 个字节的字符串
raw:大于 39 个字节的字符串

应用场景

1.缓存功能
Redis 作为缓存层,MySQL 作为存储层,首先从 Redis 获取数据,如果失败就从 MySQL 获取并将结果写回 Redis 并添加过期时间。
2.计数
Redis 可以实现快速计数功能,例如视频每播放一次就用 incy 把播放数加 1。
3.共享session
一个分布式 Web 服务将用户的 Session 信息保存在各自服务器,但会造成一个问题,出于负载均衡的考虑,分布式服务会将用户的访问负载到不同服务器上,用户刷新一次可能会发现需要重新登陆。为解决该问题,可以使用 Redis 将用户的 Session 进行集中管理,在这种模式下只要保证 Redis 是高可用和扩展性的,每次用户更新或查询登录信息都直接从 Redis 集中获取。
4.限速
例如为了短信接口不被频繁访问会限制用户每分钟获取验证码的次数或者网站限制一个 IP 地址不能在一秒内访问超过 n 次。可以使用键过期策略和自增计数实现

2.Hash(哈希,类似于Java中的Map)

概念

Redis hash是一个键值对集合。Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。类似java里面的Map
即KV模式不变,但V是一个键值对

命令

1.设置值:

hset key field value

成功返回1,失败返回0
2.获取值

hget key field

不存在返回nil
3.删除field

hdel key field [field...]

删除一个或多个field,返回结果为删除成功field的个数
4.计算field个数

hlen key

5.批量设置或获取field-value

hmget key field [field...]
hmset key field value [field value...]

6.判断 field 是否存在

hexists key field 

存在返回 1,否则返回 0。
7.获取所有的 field

hkeys key 

返回指定哈希键的所有 field。
8.获取所有 value

hvals key 

获取指定键的所有 value。

9.获取所有的 field-value

hgetall key 

获取指定键的所有 field-value。

内部编码

ziplist 压缩列表:当哈希类型元素个数和值小于配置值(默认 512 个和 64 字节)时会使用 ziplist 作为内部实现,使用更紧凑的结构实现多个元素的连续存储,在节省内存方面比 hashtable 更优秀。
hashtable 哈希表:当哈希类型无法满足 ziplist 的条件时会使用 hashtable 作为哈希的内部实现,因为此时 ziplist 的读写效率会下降,而 hashtable 的读写时间复杂度都为 O(1)

应用场景

缓存用户信息,每个用户属性使用一对 field-value,但只用一个键保存。
优点:简单直观,如果合理使用可以减少内存空间使用。
缺点:要控制哈希在 ziplist 和 hashtable 两种内部编码的转换,hashtable 会消耗更多内存。

3.List(列表)

概念

Redis列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层是一个链表。,一个列表最多可以存储 2^32 -1 个元素
单值多V
特点:
1.列表中元素有序,它可以通过索引下标获得某个元素或某个范围内的元素列表
2.列表中元素可以重复

链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。

命令

1.添加
从右边插入元素: rpush key value [value…]
从左边插入元素: lpush key value [value…]
向某个元素前或者后插入元素: linsert key before|after pivot value ,会在列表中找到等于pivot 的元素,在其前或后插入一个新的元素 value。
2.查找
获取指定范围内的元素列表: lrange key start end ,索引从左到右的范围是 0~N-1,从右到左是
-1~-N,lrange 中的 end 包含了自身。
从左到右获取列表的所有元素: lrange 0 -1
获取列表指定索引下标的元素: lindex key index
获取最后一个元素可以使用 lindex key -1 。
获取列表长度: llen key
3.删除
从列表左侧弹出元素: lpop key
从列表右侧弹出元素: rpop key
删除指定元素: lrem key count value ,如果 count 大于 0,从左到右删除最多 count 个元素,如果 count 小于 0,从右到左删除最多个 count 绝对值个元素,如果 count 等于 0,删除所有。
按照索引范围修剪列表: ltrim key start end ,只会保留 start ~ end 范围的元素。
4.修改
修改指定索引下标的元素: lset key index newValue 。
5.阻塞操作
阻塞式弹出: blpop/brpop key [key…] timeout ,timeout 表示阻塞时间。
当列表为空时,如果 timeout = 0,客户端会一直阻塞,如果在此期间添加了元素,客户端会立即返回。
如果是多个键,那么brpop会从左至右遍历键,一旦有一个键能弹出元素,客户端立即返回。
如果多个客户端对同一个键执行 brpop,那么最先执行该命令的客户端可以获取弹出的值。

内部编码

ziplist 压缩列表:跟哈希的 zipilist 相同,元素个数和大小小于配置值(默认 512 个和 64 字节)时使用。
linkedlist 链表:当列表类型无法满足 ziplist 的条件时会使用linkedlist。
Redis 3.2 提供了 quicklist 内部编码,它是以一个 ziplist 为节点的 linkedlist,它结合了两者的优势,为列表类提供了一种更为优秀的内部编码实现。

应用场景

消息队列
Redis 的 lpush + brpop 即可实现阻塞队列,生产者客户端使用 lpush 从列表左侧插入元素,多个消费者客户端使用 brpop 命令阻塞式地抢列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。
文章列表
每个用户有属于自己的文章列表,现在需要分页展示文章列表,就可以考虑使用列表。因为列表不但有序,同时支持按照索引范围获取元素。每篇文章使用哈希结构存储。
lpush + lpop = 栈、lpush + rpop = 队列、lpush + ltrim = 优先集合、lpush + brpop = 消息队列。

4.Set(集合)

概念

Redis的Set是string类型的无序集合。它是通过HashTable实现的。一个集合最多可以存储 2 ^32 -1 个元素。

Redis 除了支持集合内的增删改查,还支持多个集合取交集、并集、差集。

单值多V

命令

1.添加元素
sadd key element [element…] ,返回结果为添加成功的元素个数。
2.删除元素
srem key element [element…] ,返回结果为成功删除的元素个数。
3.计算元素个数
scard key ,时间复杂度为 O(1),会直接使用 Redis 内部的遍历。
4.判断元素是否在集合中
sismember key element ,如果存在返回 1,否则返回 0。
5.随机从集合返回指定个数个元素
srandmember key [count] ,如果不指定 count 默认为 1。
6.从集合随机弹出元素
spop key ,可以从集合中随机弹出一个元素。
7.获取所有元素
smembers key
8.求多个集合的交集/并集/差集
sinter key [key…]
sunion key [key…]
sdiff key [key…]
9.保存交集、并集、差集的结果
sinterstore/sunionstore/sdiffstore destination key [key…]
集合间运算在元素较多情况下比较耗时,Redis 提供这三个指令将集合间交集、并集、差集的结果保存在 destination key 中。

内部编码

intset 整数集合:当集合中的元素个数小于配置值(默认 512 个),使用 intset。
hashtable 哈希表:当集合类型无法满足 intset 条件时使用 hashtable。当某个元素不为整数时,也会使用 hashtable。

应用场景

set 比较典型的使用场景是标签,例如一个用户可能与娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。这些数据对于用户体验以及增强用户黏度比较重要。
sadd = 标签、spop/srandmember = 生成随机数,比如抽奖、sadd + sinter = 社交需求。

5.Zset(sorted set:有序集合)

概念

Redis zset和set一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。
redis正是通过分数来为集合中的成员进行从小到大排序zset的成员是唯一的,但分数(score)却可以重复。
和set的区别:在set基础上加上一个score值,之前set是k1 v1 v2 v3,现在zset是k1 score v1 score v2

命令

1.添加成员
zadd key score member [score member…] ,返回结果是成功添加成员的个数

Redis 3.2 为 zadd 命令添加了 nx、xx、ch、incr 四个选项:
nx:member 必须不存在才可以设置成功,用于添加。
xx:member 必须存在才能设置成功,用于更新。
ch:返回此次操作后,有序集合元素和分数变化的个数。
incr:对 score 做增加,相当于 zincrby。

zadd 的时间复杂度为 O(log n ),sadd 的时间复杂度为 O(1)。

2.计算成员个数
zcard key ,时间复杂度为 O(1)。
3.计算某个成员的分数
zscore key member ,如果不存在则返回 nil。
4.计算成员排名
zrank key member ,从低到高返回排名。
zrevrank key member ,从高到低返回排名。
5.删除成员
zrem key member [member…] ,返回结果是成功删除的个数。
6.增加成员的分数
zincrby key increment member
7.返回指定排名范围的成员
zrange key start end [withscores] ,从低到高返回
zrevrange key start end [withscores] , 从高到底返回
8.返回指定分数范围的成员
zrangebyscore key min max [withscores] [limit offset count] ,从低到高返回
zrevrangebyscore key min max [withscores] [limit offset count] , 从高到底返回
9.返回指定分数范围成员个数
zcount key min max
10.删除指定分数范围内的成员
zremrangebyscore key min max
11.交集和并集
zinterstore/zunionstore destination numkeys key [key…] [weights weight[weight…]] [aggregate sum|min|max]
destination :交集结果保存到这个键
numkeys :要做交集计算键的个数
key :需要做交集计算的键
weight :每个键的权重,默认 1
aggregate sum|min|max :计算交集后,分值可以按和、最小值、最大值汇总,默认 sum。

zset 的内部编码

ziplist 压缩列表:当有序集合元素个数和值小于配置值(默认128 个和 64 字节)时会使用 ziplist 作为内部实现。
skiplist 跳跃表:当 ziplist 不满足条件时使用,因为此时 ziplist 的读写效率会下降。

zset 的应用场景

有序集合的典型使用场景就是排行榜系统,例如用户上传了一个视频并获得了赞,可以使用 zadd 和zincrby。如果需要将用户从榜单删除,可以使用 zrem。如果要展示获取赞数最多的十个用户,可以使用 zrange。

键和数据库管理

1.键重命名
rename key newkey
2.键过期
expire key seconds :键在 seconds 秒后过期。
setex 命令作为 set + expire 的组合,不单是原子执行并且减少了一次网络通信的时间。
3.键迁移
①move
move 命令用于在 Redis 内部进行数据迁移, move key db 把指定的键从源数据库移动到目标数据库中。
②dump + restore
可以实现在不同的 Redis 实例之间进行数据迁移,分为两步:
第一步:dump key ,在源 Redis 上,dump 命令会将键值序列化,格式采用 RDB 格式。
第二步: restore key ttl value ,在目标 Redis 上,restore 命令将序列化的值进行复原,ttl 代表过期时间, ttl = 0 则没有过期时间。
整个迁移并非原子性的,而是通过客户端分步完成,并且需要两个客户端。
③migrate
实际上 migrate 命令就是将 dump、restore、del 三个命令进行组合,从而简化操作流程。
migrate 具有原子性支持多个键的迁移,有效提高了迁移效率。实现过程和 dump + restore 类似,有三点不同:
Ⅰ整个过程是原子执行,不需要在多个 Redis 实例开启客户端。
Ⅱ 数据传输直接在源 Redis 和目标 Redis 完成。
Ⅲ 目标 Redis 完成 restore 后会发送 OK 给源 Redis,源 Redis 接收后根据 migrate 对应选项来决定是否在源 Redis 上删除对应键。
4.数据库
select dbIndex ,Redis 中默认配置有 16 个数据库,例如 select 0 将切换到第一个数据库,数据库之间的数据是隔离的。
5.清除数据库
用于清除数据库,flushdb 只清除当前数据库flushall 会清除所有数据库。如果当前数据库键值数量比较多,flushdb/flushall 存在阻塞 Redis 的可能性。

持久化

1.RDB (Redis DataBase)

概念

RDB持久化指在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复时将快照文件直接读到内存里。

过程

Redis会单独创建(Fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件
RDB保存的是dump.rdb文件
整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。

Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量‘程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。

如何触发RDB快照?
1.在配置文件中默认的快照配置
2.命令save或者bgsave
save:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用。
bgsave:Redis在后台异步进行快照操作,快照操作同时可以响应供应客户端请求,可以通过lastsave命令获取最后一次成功执行快照的时间。阻塞只发生在fork阶段,时间很快。
3.执行flushall命令,也会产生dump.rdb文件,但是是个空文件,没有意义。

优点

1.适合大规模的数据恢复
2.对数据完整性和一致性要求不高

Redis 加载 RDB 恢复数据远远快于 AOF 的方式

缺点

1.在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。
2.Fork的时候,内存中的数据被克隆了一份,大约2倍的膨胀性需要考虑。
3.RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能导致Redis在一些毫秒级不能响应客户端请求。

2.AOF (Append Only File)

概念

日志的形式记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话根据日志文件的内容将写指令从前到后执行一次已完成数据的恢复工作。
AOF保存的是appendonly.aof文件

过程

开启 AOF 功能需要设置: appendonly yes ,默认不开启。保存路径同 RDB 方式一致,通过 dir 配置
指定。

AOF 的工作流程操作:命令写入 append、文件同步 sync、文件重写 rewrite、重启加载 load:
1.所有的写入命令会追加到 aof_buf 缓冲区中。
2.AOF 缓冲区根据对应的策略向硬盘做同步操作。
3.随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
4.当服务器重启时,可以加载 AOF 文件进行数据恢复。

重写rewrite

概念:
AOF采用文件追加方式,文件会越来越大,为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令gbrewriteaof
重写原理
AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后在rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。
触发机制
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

优势

1.每秒同步:appendfsync always 同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好
2.每修改同步:appendfsync everysec 异步操作 ,每秒记录 如果一秒内宕机,有数据丢失。
3.不同步:appendfsync no 从不同步

劣势

1.相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
2.AOF运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同。

Redis缓存常见问题

1.缓存击穿

对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:如果这个key在大量请求同时进来前正好失效,那么所有对这个key的数据查询都落到db,我们称为缓存击穿。(是某一个热点key在高并发访问情况下突然失效,导致大量并发打入mysql数据库情况)
解决办法:
使用redis数据库的分布式锁,解决mysql的访问压力 加锁限制并发量
第一种分布式锁:redis自带的分布式锁 set px nx,在redis层面解决
第二种分布式锁:redission框架,一个redis的带有juc的lock功能实现,在java层面解决

2.缓存穿透

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中,将去查询数据库,但是数据库也无此记录,并且处于容错考虑,我们没有将这次查询的null写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。利用redis和mysql的机制(redis缓存一旦不存在,就访问mysql),直接绕过缓存而制造的db请求压力
解决办法:空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

3.缓存雪崩

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
解决办法:原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

你可能感兴趣的:(数据库,redis,java)