目录
Redis入门
-
测试连接
ping
-
设置一个值
set key value
-
切换数据库
select index
-
查看数据库大小
dbsize
-
查看所有的key
keys *
-
清除当前数据库
flushdb
-
清除全部数据库内容
flushall
-
关闭redis
shutdown
-
查看redis配置中的某一项配置
config get key
-
设置redis配置文件中的某一项配置
config set key value
-
查看某些章节的信息
info [section]
Redis-key
- 判断某个键是否存在
exists key
- 移除某个键
move key db
- 设置过期时间
expire key time
- 查看当前键的剩余时间
ttl key
- 判断当前key是什么类型
type key
基本数据类型
String
-
设置一个key
set key
-
获取一个key
get key
-
判断key是否存在
exists key
-
往字符串后面中追加str
append key str
-
获取字符串的长度
strlen key
-
让key的值自动加1,即i++操作
incr key
-
让key的值自动减1,即i–操作
decr key
-
以步长为n增加,即i + n
incrby key n
-
以步长为n减少,即i - n
decrby key n
-
字符串截取
getrange key start end
-
字符串替换
setrange key offset value
-
当前的值存在就设置(set with expire),设置过期时间
setex key seconds value
-
当前的值不存在就设置(set if not exist),存在就设置失败,在分布式锁中会常常使用
setnx key value
-
批量设置多个值
mset key1 value1 key2 value2...
-
批量获取多个值
mget key1 key2 key3...
-
批量设置多个值,如果都不存在就设置,有一个存在就都不设置,具有原子性,要么一起成功,要么一起失败
msetnx key1 value1 key2 value2
-
设置一个user对象,id为1 user:{field}:{value}
set user:1 {name:"zhangsan",age:3}
mset user:1:name zhangsan user:1:age 3
-
先获取一个值再设置这个值,即如果存在,获取原来的值,并设置新的值
getset key value
List
-
往队列里面添加元素,从左边开始添加,插入到列表头部
lpush key element
-
获取队列中从start到end到所有元素
lrange key start end
-
往队列里面添加元素,从右边开始添加,插入到列表尾部
rpush key element
-
移除队列中的元素,从左边开始移除,移除列表的第一个元素
lpop key
-
移除队列中的元素,从右边开始添加,移除列表的最后一个元素
rpop key
-
通过下标获取列表的值
lindex key index
-
获取列表的长度
llen key
-
移除队列中的指定个数的值
lrem key count element
-
截取队列中的指定的某个范围中的值,会把原来的队列截断
ltrim key start end
-
移除列表的最后一个元素,并且将其移动到新的列表中
rpoplpush source destination
-
判断列表是否存在
exists key
-
替换列表中某个下标的值为新的值,相当于更新操作,如果下标或列表不存在会报错
lset key index element
-
往列表中某个值的前面或者后面插入一个指定的值
linsert key before|after pivot value
-
阻塞等待队列中有值
brpop key [key ...] timeout
队列 lpush – rpop
栈 lpush – lpop
Set
-
往集合中添加一个值
sadd key member
-
获取集合中的所有值
smembers key
-
判断某个元素是否存在该集合中
sismember key member
-
获取集合中元素的个数
lcard key
-
移除集合中的某一个值
srem key member
-
随机抽选出集合中的一个元素
srandmember key
-
随机抽选出集合中指定个数的元素
srandmember key count
-
随机删除集合中的一个元素
spop key
-
将一个指定的值移动到另外一个集合中
smove source destination member
-
集合之间的运算
-
差集
sdiff key1 key2
-
交集
sinter key1 key2
-
并集
sunion key1 key2
-
Hash
-
往哈希表中添加一个字段和值 key-value
hset key field value
-
获取哈希表中field的值
hget key field
-
同时给哈希表设置多个key-value
hmset key field1 value1 field2 value2...
-
获取哈希表多个字段值
hmget key field1 field2
-
获取哈希表全部的数据
hgetall key
-
删除哈希表某个key的某个字段,对应的value值也没有了
hdel key field
-
获取哈希表哈希表有多少个字段
hlen key
-
判断哈希表中的指定字段是否存在
hexists key field
-
只获取哈希表中的所有字段
hkeys key
-
只获取哈希表中的所有值
hvals key
-
给哈希表中某个字段自增指定步长
hincrby key field step
-
哈希表中某个字段不存在就可以设置,如果存在就不能设置
hsetnx key field value
适合对象的存储
Zset
-
往zset中添加一个值
zadd key score member [score member...]
-
获取所有的值
zrabge key min max
-
从小到大排序
zrangebyscore key -inf +inf [withscores]
-
从大到小排序
zrevrange key start end
-
移除zset中的元素
zrem key member
-
查看zset中有多少个元素
zcard key
-
获取指定区间中的成员的数量
zcount key start end
案例:存储班级成绩表、工资表
带权重进行判断,如普通1,重要2
排行榜应用,取Top N测试
三种特殊数据类型
Geospatial
-
添加地理位置:纬度 经度 名称
geoadd longitude latitude member
-
从key中返回指定的member的定位
geopos key member
-
返回两个地点的距离
geodist key member1 member2
-
以给定的经度纬度为中心,找出某一个半径内的元素
georadius key longitude latitude radius
-
找出位于指定范围内的元素,中心点数由给定的位置元素决定的
georadiusbymember key member radius
-
返回一个或多个位置元素geohash表示,将二维的经纬度转化为一维的11位字符串,如果两个字符串越接近,则距离越接近
geohash key member
GEO底层的实现原理其实就是Zset,我们可以使用Zset来操作
-
查看地图的全部元素
zrange key start end
-
移除地图中的某个元素
zrem key member
Hyperloglog
优点:占用的内存是固定的,2^64不同的元素技术,只需要12KB的内存
缺点:有0.81%的错误率
网页的UV:一个人访问一个网站多次,但还是算一个人
传统的方法用set保存用户id,然后可以统计set中元素的数量来作为判断标准
这个方式如果保存大量的用户id,就会比较麻烦,我们是为了计数,而不是保存用户id
-
添加一些值
pfadd key element
-
统计不重复的值的数量
pfcount key
-
合并
pfmerge destkey sourcekey [sourcekey ...]
Bitmap
统计人数:0 1 0 1 0 0 0 0 0 0 0 0
统计[登陆、未登陆的]|[打开、未打卡]等只有两种状态的
-
设置某个位的值
setbit key offset value
-
查看某一个位的值
getbit key offset
-
统计范围内的和
bitcount key [start end]
事务
------ 队列 命令1 命令2 命令3 执行 ------
-
开启事务
multi
-
命令入队
......
-
执行事务
exec
-
取消事务,事务一取消,该事务队列中的所有命令都不会被执行
discard
编译型异常,命令有问题,事务中的所有命令都不会被执行
运行时异常,队列中命令不存在语法错误,但是执行命令出现错误,其他命令是可以正常执行的,错误命令会抛出异常
配置文件
units #单位
include #包含其他文件
#### 网络 ####
bind #绑定ip
port #端口
protected-mode #yes: 保护模式
#### 通用 ####
demonize #yes: 以守护进程的方式运行
pidfile #如果以后台方式运行,需要指定一个pid进程文件
loglevel #日志级别
logfile #生成的日志文件名
database #数据库数量,默认是16个
#### 快照 ####
save 900 1 #如果900秒内,至少有1个key进行了修改,则进行持久化操作
stop-writes-on-bgsave-error yes #持久化出错是否继续工作
rdbcompression yes #是否压缩rdb文件
rdbchecksum yes #保存rdb文件的时候,是否进行错误的检查校验
dir ./ #rdb文件保存的目录
#### 主从复制 ####
#### 安全 ####
requirepass #设置密码
#### 限制 ####
maxclients #最大客户端数量
maxmemory <bytes> #redis配置的内存容量
maxmemory-policy #内存达到上限之后的处理策略
#1、volatile-lru: 只对设置了过期时间的key进行LRU(默认值)
#2、allkeys-lru: 删除lru算法的key
#3、volatile-random: 随机删除即将过期key
#4、allkeys-random: 随机删除
#5、volatile-ttl: 删除即将过期的
#6、noeviction: 永不过期,返回错误
#### aof ####
appendonly no #默认不开启,默认使用rdb
appendfilename "appendonly.aof" #aof持久化文件
appendfsync everysec #持久化时机,每次修改都同步: always 每秒都同步: everysec 不同步: no
RDB
redis 会单独创建一个子进程来进行持久化,会将数据写入到一个临时文件中,等待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程不进行任何IO操作,这就确保了极高的性能。如果需要进行大规模的数据恢复,且对于数据恢复的完整性不是非常敏感,那么RDB方式要比AOF方式更加高效。RDB的缺点是最后一次持久化后的数据可能会丢失。
触发生成rdb文件的机制
- save的规则满足的情况下,会自动触发rdb规则
- 执行flushall命令,会触发生成rdb文件
- 退出redis,也会产生rdb文件
如何恢复rdb文件
- 只需要将rdb文件放到redis.conf配置的dir目录下就行了,redis启动的时候会自动检查dump.rdb文件,恢复其中的数据
优点
- 适合大规模的数据恢复
- 对数据完整性的要求不高
缺点
- 需要一定的时间间隔操作,如果redis意外宕机,最后一次修改就没有了
AOF
以日志的形式去记录每一个写的操作,将redis的所有指令记录下来(读操作不记录),只许追加文件,但不可以改写文件。redis启动之初会读取该文件重新构建数据。换言之,redis重启的话根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
如果aof文件有错误,这时候redis是启动不起来的,我们需要修复这个aof文件。redis给我们提供了redis-check-aof工具去修复aof文件
redis-check-aof --fix appendonly.aof
优点
- 可以配置每一次修改都同步,文件完整性更好
缺点
- 不如rdb恢复高效
Redis发布订阅
Redis发布订阅(pub/sub)是一种消息通信模式,发送者发送消息,订阅者接收消息。[微信、微博]
Redis客户端可以订阅任意数量的频道
需要三个角色:消息发送者、频道、消息订阅者
-
订阅一个或者多个频道
subscribe channel [channel ...]
-
往某个频道发送信息
publish channel message
通过SUBSCRIBE命令订阅某个频道之后,redis-server里面维护了一个字典,字典的键就是一个一个的频道,而字典的值则是一个链表。链表中保存了所有订阅这个channel的客户端,SUBSCRIBE命令的关键,就是将客户端添加到给定的channel的订阅链表中。通过PUBLISH命令向订阅者发送消息,redis-server会使用给定的频道所有客户端链表,遍历这个链表,将消息发送给所有的订阅者
Redis主从复制
redis默认都是master节点,所以只需要配置从库就行
查看主从复制的信息
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:4c55c7bb37450e73a19f157a1c44925a2c1d78f3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
-
配置本机作为
host
-port
的从库slaveof host port
原理
Slave启动成功连接到Master后会发送一个sync同步命令
Master接到命令,启动后台存盘进程,同时搜集所有接收到的用于修改数据集的命令,在后台进程执行完毕之后,Master将传送整个数据文件到Slave,并完成一次完全同步。
- 全量复制:Slave服务在接收到数据库文件数据后,将其存盘并加载到内存中
- 增量复制:Master继续将新的所有搜集到的修改命令依次传送给Slave,完成同步
但只要重新连接Master,一次完全同步(全量复制)将被自动执行。
-
让自己重新变成主节点
slaveof no one
哨兵模式
-
配置哨兵配置文件
sentinel.conf
#sentinel monitor 被监控的名称 host port 1 sentinel monitor myredis 127.0.0.1 6379 1
-
启动哨兵
redis-sentinel /../../sentinel.conf
Redis缓存穿透、击穿、雪崩
缓存穿透
概念
用户想要查询一个数据,发现Redis内存数据库没有,也就是没有缓存命中,于是向持久层数据库查询,发现也没有,也是本次查询失败。当用户很多的时候,缓存都没有命中(秒杀),于是都去请求持久层数据库,这就会给持久层数据库造成很大的压力,就出现了缓存穿透。
解决方案
- 布隆过滤器:一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则舍弃,从而避免了对底层存储系统的查询压力
- 缓存空对象:当存储层不命中之后,即使返回的是空对象也将其缓存起来,同时设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护后端数据源
缓存击穿
概念
指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏幕上凿开了一个洞一样。
解决方案
- 设置热点数据永不过期:从缓存层面来看,没有设置过期时间,就不会出现热点的key过期后产生的问题
- 加互斥锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端数据库,其他的线程没有获得分布式锁的权限,因此只需要等待就可,将高并发的压力转移到了分布式锁
缓存雪崩
概念
指在某一个时间段,缓存集中过期失效。
解决方案
- 限流降级:在缓存失效之后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对于某个key只允许一条线程查询和写缓存,其他线程等待
- 数据预热:在正式部署前,先把可能的数据先预热访问一遍,这样部分可能大量访问的数据就会加载到缓存中,在即将发生大并发访问前手动粗发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。