Redis
一、五大数据类型
- String字符串类型
- Hash哈希表类型
- List列表
- Set集合
- Sorted Set有序集合
1、Redis通用操作
-
exists:判断key是否存在
exists name 存在返回数字,不存在返回0
-
expire:设置key的过期时间,单位秒
expire name 10; 成功返回1,失败返回0
-
ttl:查看key的剩余过期时间
ttl name; 返回剩余的时间,如果不过期返回-1,过期返回-2
-
del:根据key删除键值对
del name; 返回被删除key的数量
-
keys:查看当前redis中的key数据
keys *
-
flushall:清空数据库中所有数据
2、String字符串
-
set:设置指定key的值
set name “zijian”
-
get:获取指定key的值
get name
-
setnx:当key不存在时新增
setnx name “lisi”
-
setex:设置key的存活时间,无论是否存在指定的key都能新增,存在则覆盖。
setex name 10 “zhangsan”
-
incr/dect:让value递增/递减
incr age;
3、Hash表
注意:下方的key表示是在名为key中的hash表中
-
hset:给key中filed设置值
kset key username “zhangsan”
-
hget:获取key中某个filed的值
kget key username;
-
hmset:给key中多个filed设置值
hmset key username “lisi” age 22
-
hmget:一次获取key中多个field的值
hmget key username age
-
hkeys:获取key中所有的field的值
hkeys key
-
hvals:获取key中所有value的值
hvals key
-
hgetall:获取所有field和value
hgetall key
-
hdel:删除key中任意个field
hdel key username age
4、List列表
-
rpush:向列表末尾插入一个或多个值。可以重复
rpush username “zhangsan” “lisi”
-
lrange:返回列表中指定区间内的值。-1代表末尾
lrange username 0 -1
-
lpush:将一个或多个值插入到列表前面
lpush username “wangwu”
-
llen:获取列表长度
llen username
-
lrem:删除列表中元素
lrem username 1 “zhangsan”;正数表示从左往右删除的数量。负数表示从由往左删除的数量。
5、Set集合
-
sadd:向集合中添加内容。不能重复
sadd setage 22 23 24
-
scard:返回集合元素数量
scard setage
-
smembers:查看集合中元素内容
smembers setage
-
srem:删除集合中的元素
srem setage 22
-
spop:随机取出count个集合中的元素
spop setage 1
6、Sorted Set有序集合
注意:有序集合中每个value都有一个score,根据这个进行排序
-
zadd:向有序集合中添加数据
zadd zage 1 22 3 24 2 23
-
zrange:返回区间内容
zrange zage 0 3
-
zrem:删除集合内容
zrem zage 22
二、三种特殊的数据类型
1. geospatial(地理位置)
-
geoadd:添加地理位置
- 有效的经度从-180到180度。
- 有效的纬度从-85.05112878度到85.05112878度。
- 当坐标位置超出上述指定范围时,该命令会发生一个致命的错误。
127.0.0.1:6379[2]> geoadd china:city 116.40 39.90 beijing (integer) 1 127.0.0.1:6379[2]> geoadd china:city 121.47 31.23 shanghai (integer) 1 127.0.0.1:6379[2]> geoadd china:city 106.50 29.53 chongqing (integer) 1 127.0.0.1:6379[2]> geoadd china:city 114.05 22.52 shengzhen (integer) 1
-
geodist:返回两个给定位置之间的距离
127.0.0.1:6379[2]> geodist china:city beijing shanghai "1067378.7564" 127.0.0.1:6379[2]> geodist china:city beijing shengzhen "1945788.0901" 127.0.0.1:6379[2]> geodist china:city beijing shengzhen km #查看北京到上海的直线距离单位是千米 "1945.7881" 127.0.0.1:6379[2]> geodist china:city beijing shanghai km "1067.3788"
-
georadius:以给定的经纬度为中心, 找出某一半径内的元素
127.0.0.1:6379[2]> georadius china:city 110 30 1000 km #查找经纬度为中心,找出1000公里内的城市 1) "chongqing" 2) "shengzhen" 127.0.0.1:6379[2]> georadius china:city 110 30 500 km 1) "chongqing" 127.0.0.1:6379[2]> georadius china:city 110 30 500 km withcoord#查找经纬度为中心,找出500公里内的城市并附带经纬度 1) 1) "chongqing" 2) 1) "106.49999767541885376" 2) "29.52999957900659211" 127.0.0.1:6379[2]> georadius china:city 110 30 500 km withdist#查找经纬度为中心,找出500公里内的城市并附带直线距离 1) 1) "chongqing" 2) "341.9374" 127.0.0.1:6379[2]> georadius china:city 110 30 1000 km withdist count 1 #刷选出指定的城市 1) 1) "chongqing" 2) "341.9374" 127.0.0.1:6379[2]> georadius china:city 110 30 1000 km withdist count 2 1) 1) "chongqing" 2) "341.9374" 2) 1) "shengzhen" 2) "924.6408
-
geo底层实现原理就是Zset,可以使用zset命令来操作geo
127.0.0.1:6379[2]> zrange china:city 0 -1 #查看地图中的全部元素 1) "chongqing" 2) "shengzhen" 3) "shanghai" 4) "beijing" 127.0.0.1:6379[2]> zrem china:city beijing#删除地图中指定的元素 (integer) 1 127.0.0.1:6379[2]> zrange china:city 0 -1 1) "chongqing" 2) "shengzhen" 3) "shanghai"
2.hyperloglog
-
什么是基数:
- 比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
127.0.0.1:6379[2]> pfadd mykey a b c d e f g h i j #创建一组元素 (integer) 1 127.0.0.1:6379[2]> pfcount mykey #统计mykey元素的基数数量 (integer) 10 127.0.0.1:6379[2]> pfadd mykey2 i j l m n o p q r s (integer) 1 127.0.0.1:6379[2]> pfcount mykey2 #创建第二组元素 (integer) 10 127.0.0.1:6379[2]> pfmerge mykey3 mykey mykey2 #合并两组的元素,并集 OK 127.0.0.1:6379[2]> pfcount mykey3 (integer) 18
3.bitmap
- 统计用户信息,例如打卡,或者登陆的活跃状态;只要是两个状态的都可以使用Bitmap.
使用Bitmap记录周一到周五的打卡记录,统计打卡天数
127.0.0.1:6379[2]> setbit sign 0 1
(integer) 0
127.0.0.1:6379[2]> setbit sign 1 1
(integer) 0
127.0.0.1:6379[2]> setbit sign 2 0
(integer) 0
127.0.0.1:6379[2]> setbit sign 3 0
(integer) 0
127.0.0.1:6379[2]> setbit sign 4 0
(integer) 0
127.0.0.1:6379[2]> setbit sign 5 1
(integer) 0
127.0.0.1:6379[2]> getbit sign 2 #查看是否打卡
(integer) 0
127.0.0.1:6379[2]> getbit sign 1
(integer) 1
127.0.0.1:6379[2]> bitcount sign#统计这周打卡记录
(integer) 3
三、Redis持久化策略
- redis是内存数据库,如果不将内存中的数据状态保存到磁盘中,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以redis提供了持久化功能。
- redis提供了两个持久化方案:RDB持久化和AOF持久化,一个是快照的方式,一个是类似日志追加的方式。
1.RDB持久化策略
- 通过快照的方式,在指定的时间间隔内将内存中的数据集快照写入磁盘。在创建快照之后,用户可以备份该快照,可以将快照复制到其它服务器以创建相同数据的服务器副本,或者在重启服务器后恢复数据。RDB是Redis默认的持久化方式。
- RDB持久化会生成RDB文件,该文件是一个压缩过的二进制文件,可以通过该文件还原快照时的数据库状态。RDB文件默认为当前工作目录下的dump.rdb。当redis重启后会自动加载dump.rdb文件中内容到内存中。
触发快照的时机:
-
执行save(同步)和bgsave(异步)命令
-
配置文件设置save 规则,自动间隔性执行bgsave命令
-
主从复制时,从库全量复制同步主库数据,主库会执行bgsave
-
执行flushall命令清空服务器数据
-
执行shutdown命令关闭Redis时,会执行save命令
save和bgsave命令区别:
-
save命令会阻塞Redis服务器进程,服务器进程在RDB文件创建完成之前是不能处理任何的命令请求。
-
bgsave命令会fork一个子进程,然后该子进程会负责创建RDB文件,而服务器进程会继续处理命令请求。
优点:
- rdb文件是一个紧凑文件,直接使用rdb文件就可以还原数据。
- 数据保存会由一个子进程进行保存,不影响父进程。
- 恢复数据的效率要高于AOF的方式。
缺点:
- 在两个保存点之间的时间时,Redis如果关闭了,会导致数据的丢失。
- 使用bgsave保存数据时,每次都需要fork子进程,在数据量比较大时会比较耗费性能。
2.AOF持久化方式
注意:AOF默认是关闭的,需要在配置文件中开启AOF,Redis支持RDB和AOF同时生效,若同时存在,AOF的优先级高于RDB
- 开启后,每执行一条更改Redis数据的命令,都会把该命令追加到AOF文件中,这会降低Redis性能。
AOF实现步骤:
- 命令追加(append)、文件写入(write)、文件同步(sync)
命令追加:
- 开启AOF持久化功能后,服务器每执行一个写命令,都会把该命令以协议格式先追加到
aof_buf
缓存区的末尾,而不是直接写入文件,避免每次有命令都直接写入硬盘,减少硬盘IO次数。
AOF重写(rewrite):
-
随着时间的推移,Redis执行的写命令会越来越多,AOF文件也会越来越大,过大的AOF文件可能会对Redis服务器造成影响,而且会加大还原时间。
-
AOF重写的目的就是减少AOF文件的体积,不过值得注意的是:AOF文件重写并不需要对现有的AOF文件进行任何读取、分享和写入操作,而是通过读取服务器当前的数据库状态来实现的。
-
文件重写可以分为手动触发和自动触发,手动触发执行
bgrewriteaof
命令,该命令的执行跟bgsave
触发快照时类似的,都是先fork
一个子进程做具体的工作。127.0.0.1:6379> bgrewriteaof Background append only file rewriting started
AOF优点:
- 相对于RDB方式更加能保证数据的安全性。
AOF缺点:
- 对于相同的数据集,AOF文件体积要大于RDB文件,数据恢复也会比较慢。
如何选择RDB和AOF:
- 如果是数据不那么敏感,且可以从其他地方重新生成补回的,那么可以关闭持久化。
- 如果是数据比较重要,不想再从其他地方获取,且可以承受数分钟的数据丢失,比如缓存等,那么可以只使用RDB。
- 如果是用做内存数据库,要使用Redis的持久化,建议是RDB和AOF都开启,或者定期执行
bgsave
做快照备份,RDB方式更适合做数据的备份,AOF可以保证数据的不丢失
四、数据恢复
- 如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据。
- 如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复,如果AOF文件破损,那么用
redis-check-aof fix
命令修复。 - 如果没有AOF文件,会去加载RDB文件。
- 如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复。
五、事务
- 事务是一个单独的隔离操作(Redis事务的本质):事务中的所有命令都会
序列化
、按顺序地执行
。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断(排他性
)。 - Redis单条命令式保存原子性的,但是事务不保证原子性。
- Redis事务没有隔离级别的概念。
- 一个事务从开始到执行会经历以下三个阶段:
- 开始事务。
multi
- 命令入队。
- 执行事务。
exec
- 开始事务。
六、Redis缓存
-
缓存穿透:
查询缓存和DB都不存在的数据。
解决方式:
- 利用互斥锁,缓存失效时,失去获得锁,得到锁,再去请求数据库。没得到锁则休眠一段时间重试。
- 采用异步更新策略,无论key是否取到值都返回,value中加入一个缓存失效时间。
- 使用布隆过滤器。
-
缓存击穿:
高并发情况下,某个热门的key突然过期,导致大量的请求在redis中未找到缓存数据,进而全部去访问DB数据库,引起DB压力瞬间变大。
解决方式:
- 保证热点数据永不过期,再加一个互斥保证缓存单线程写。
-
缓存雪崩:
如果大量的缓存在一段时间内集中过期,这是就会出现大量的缓存击穿,所有请求都落在DB上,引起DB压力过大,导致DB宕机。
解决方式:
- 给缓存一个失效时间,避免集体失效。
-
缓存预热:
系统上线后,将相关的缓存数据直接加载缓存系统。
-
缓存降级:
当访问量剧增,服务出现问题(响应忙或不响应),仍需要保证服务还是可用的,系统可根据一些关键数据进行自动降级。