学习笔记,根据狂神说的redis教程所记录
部分截图来自狂神说redis和慕课网课程
地址:https://www.bilibili.com/video/BV1S54y1R7SB?p=1
redis的安装
- 官网下载他的压缩包,然后通过fxtp拉进linux中。官网:https://redis.io/
- 解压,tar -zxvf 压缩包名字
- 执行make命令。(执行之前要安装gcc命令。)
- 安装完成后不用运行Redis Test。因为需要安装TCL
- 运行make install命令,测试是否安装成功。
以上安装成功。
知识讲解
-
单进程
-
默认是16个数据库,类似于数组的排序,默认使用的是第0数据库
-
select切换数据库
-
dbsize:查看当前数据库的key数量
5. flushdb:清空当前数据库的数据
6. flushall:清空所有数据库的数据 -
统一密码管理,16个库都是同样的密码,要么全ok,要么全连不上。
-
redis索引都是从0开始的
-
默认端口是6379
-
启动命令:cd /usr/local/bin
redis-server /myredis/redis.conf
redis-cli -p 6379
ping
接着会出现PONG
redis常见数据类型操作命令
Key常用:
keys *
exists keyName,判断某个key是否存在
move keyName db 移动,当前库的就消失
expire keyName 秒钟 给key设置过期时间
ttl keyName 查看还有多少秒过去,-1表示永不过期,-2表示已过期
type keyName 查看key的类型
String常用:
set/get/del/append/strlen:设置,获取,删除,拼接,获取长度
incr/decr/incrby/decrby k: 自增
getrange k : 0 3 获取0到3字符的内容
getrange k -1 : 获取字符全部的内容
setrange k 1 xxx :从1号位开始替换
setex(set with expire) setex k 30 “hello”:设置k的值,30秒后过期
setnx(set if not exit):如果存在就设置失败返回0,没有则设置成功返回1
mset/mget/msetnx :mset k1 v1 k2 v2 … 执行多个key(原子性操作,要么一起成功,要么一起失败)
对象:
mset user:1:name zhangsan user:1:age 22 :设置一个user:1对象 ,值为json字符来保存的一个对象
这里的key是一个巧妙的设计,user:{id}:{filed},如此设计在redis中是可行的
mget user:1:name user:1:age
组合命令
getset:先get后set
HashMap常用:key-map
和string没什么区别,只是存的值是key-value
hash适合存储经常变更的数据,比如用户信息
hset user:{id} name:{name} age:{age}
hset k key value:
hmset k key1 value1 key2 value2…:多次设置值
hgetall k : 获取所有值
hkeys k:获取全部key
hvalues k:获取全部值
hincrby k key count :k中的key的value增加count
hsetnx k key value:如果存在则不设置,不存在就设置
List常用:
多值value
lpush/rpush/:从左边进或者右边进 其中rpush的是先进先出
lrange 0 -1 查看全部元素
lpop/rpop :出列,从左边出或者右边出
lindex 按照索引下表获得元素(从上到下)
llen 长度
lrem key count value: 删count个value
ltrim key 开始index 结束index,截取指定范围的值,截断后只剩下截取的元素
rpoplpush 源列表 目的列表 ,移除源列表的最后一个元素,将其移动到目标列表的左边
lset k index v 更新k列表的第index的值为value,如果不存在则报错
lset key index value 修改列表对应的index的值为value
linsert key before/after v1 v2 将v2插入到v1前/后
Set常用:
sadd k v:添加一个元素
sismember k v:k是否存在v
smenber k:展示k
scard k:元素个数
srem k v:删除k中的v
srandommenber k 2:展示随机两个元素
spop:随机移除一个元素
smove k1 k2 v1 :将k1的元素v1移动到k2
sdiff k1 k2:列出k1中k2差集
sinter k1 k2 : 列出交集
sunion k1 k2:并集
Zset有序集合:
zadd k v1 index v2 index :zadd k v1 one v2 two :v1排第一,v2排第二
显示全部用户,从小到大排序:
排序3000以内的值,并展示出来:
zcard k :获取有序集合中的个数
zrevrange k :从大到小排序展示
事务
redis的单条命令是保证原子性的,但是事务不保证原子性!
redis没有隔离级别的概念
所有命令在事务中并没有被执行,只有发起执行命令才会被执行 Exec
redis事务本质:一组命令一块执行。一个事务中的所有命令都会被序列化,在事务执行过程中,按顺序执行。而且在执行时不允许别人干扰
一次性、顺序性、排他性
-------队列 set set set 执行-----
redis的事务
- 开启事务(multi)
- 命令入队(命令)
- 执行事务(exec)
正常执行事务:
放弃事务:DISCARD
事务中的队列命令都不会被执行
事务中语句出现异常怎么办?
编译型异常(代码错了,命令有误):事务中所有的命令都不能被执行!
运行时异常(类似java中的1/0):其他命令是可以正常执行的!错误命令抛出异常
监控Watch
悲观锁:
很悲观,认为什么时候都出问题,无论做什么都会加锁,影响性能。
乐观锁
- 很乐观,认为什么时候都不会出问题,所以不上锁。更新数据的时候去判断,在此期间是否有人修改过数据。
- 获取version
- 更新的时候比较version
redis监视测试
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money # 监视momey对象
OK
127.0.0.1:6379> multi #事务正常结束,数据期间没有发生变动
OK
127.0.0.1:6379(TX)> DECRBY money 20
QUEUED
127.0.0.1:6379(TX)> INCRBY out 20
QUEUED
127.0.0.1:6379(TX)> exec1)
(integer) 802)
(integer) 20
如果在执行期间来了第二个线程,那么怎么办呢?
那么怎么解决?
- 先解锁
- 再重新监视
- 再执行事务
springboot整合
编写一个我们自己的RedisTemplate
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> myRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
//我们为自己开发方便,一般使用<String,Object>
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//Json序列化配置
//Object.class指所有对象都要来序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(mapper);
//String的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//value采用json的序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash的value采用json的序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
}
redis.conf详解
网络
bind 0.0.0.0 #绑定的ip
protected-mode no #是否开启保护模式
port 6379端口
通用
daemonize yes #以守护进程的方式运行,默认no
pidfile /var/run/redis_6379.pid #如果是后台运行,就需要指定一个pid文件
日志级别:
#Specify the server verbosity level.
#This can be one of:
#debug (a lot of information, useful for development/testing)
#verbose (many rarely useful info, but not a mess like the debug level)
#notice (moderately verbose, what you want in production probably)
#warning (only very important / critical messages are logged)
loglevel notice
logfile /usr/local/bin/redis-log.log #日志文件名:
databases 16 #默认数据库数量
always-show-logo no #总是显示logo
快照
在规定时间内,执行了多少次操作,就会持久化到文件中(.aof .rdb)
redis是内存数据库,没有持久化数据就会断电即失去
save 3600 1 #如果3600s内至少有一个key修改了,就进行持久化操作
save 300 100 #如果300s内至少有10个key修改了,就进行持久化操作
save 60 10000#如果60s内至少有一10000key修改了,就进行持久化操作
stop-writes-on-bgsave-error yes # 持久化出错是否继续工作
rdbcompression yes #是否压缩rdb文件,需要消耗一些cpu资源
rdbchecksum yes #保存rdb文件的时候进行错误的校验
dir ./ #rdb保存的目录
REPLICATION主从复制
安全
config set requirepass “123456” #设置密码
config get requirepass #获取密码
auth 123456 #通过密码登录
redis持久化
RDB(Redis DataBse)
什么是RDB?
触发机制: save的命令满足,会产生rdb文件
flushall清空所有,会产生rdb文件
退出reids时,会产生rdb文件
优点:
适合大规模的数据恢复
对数据完整性要求不高
缺点:
操作有一定的时间间隔,如果redis以外宕机了,这个最后一次修改的数据就没有了。
fork一个进程的时候,需要占用一定的内存空间
AOF(Append Only File)
AOF是什么
将我们的所有命令记录下来,恢复的时候把这个文件中的命令再执行一遍
如果文件正常,重启就直接恢复了。
重写规则:
优点:
每一次修改都同步,文件的完整性会更好
每秒同步一次,可能丢失最后一秒的数据,
缺点
相对于数据文件而言,aof远远比rdb要大,修复的速度也比rdb慢。
aof运行效率也比rdb慢,所以redis默认的持久化策略就是rdb
redis发布订阅
- redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息
- redis客户端可以订阅任意数量的频道
订阅发布消息图:
redis主从复制
环境配置:
只需要配置从库,不需要配置主库,每个redis-server默认就是主库
查看配置信息:
127.0.0.1:6379> info replication
Replication
role:master #角色
connected_slaves:0 #连接的从机
master_failover_state:no-failover
master_replid:7b88172f4851f64c9f3da9d3c169eb825f7cc7c1
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
测试redis单机多集群
复制三个配置文件,修改:
- 端口
- pid名字
- 日志文件名
- rdb文件名
修改完成之后启动redis集群
从机连接主机只需要一个命令:
SLAVEOF 127.0.0.1 6379 #找谁当自己老大
主机中查看信息:
127.0.0.1:6379> info replication
Replication
role:master
connected_slaves:2 #有2台从机了
slave0:ip=127.0.0.1,port=6380,state=online,offset=70,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=70,lag=1
master_failover_state:no-failover
master_replid:ebf5fc9f0f8e63ee7b75b66a3d01b01bafef0ac0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
真实的主从配置应该从配置文件中设置,这样设置以后就是永久的,这里使用的是命令,是暂时的
细节:
- 主机可以写,从机只能读。
- 主机所有的数据,都会被从机保存
测试:主机断开,从机依旧连接,但是没有写操作。主机恢复后,从机依旧可以获取主机写的值
如果是使用命令行来配置主从,如果这个时候重启了,就会变成主机。只要变为从机,立马从主机中获取数据!
复制原理:
如果没有老大了,能不能自动选择一个老大出来?
谋朝篡位
SLAVEOF on one:如果主机断开了连接,使用这个命令让自己变成主机,其他节点手动连接到该主机。如果主机回来了,又得重新配置
这时候就需要哨兵模式了!自动选取老大!
哨兵模式
**概述:**主从切换技术的方法:当主服务器宕机后,需要手动将一台服务器切换为主服务器,这就需要人工干预,耗时耗力,还会造成一段时间内服务不可用,更多时候我们考虑率哨兵模式。(自动版谋朝篡位)
哨兵模式:能够后台监控主机是否故障,如果故障了自动将从库转换成主库。
哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令,哨兵是一个独立的进程,它会独立运行。其原理是哨兵通过发送命令,等待redis服务器响应,从而监控运行多个redis实例
测试:
目前是一主二从
配置哨兵配置文件sentinel.conf
#sentinel monitor 被监控名称 host port 1 #1代表主机挂了,哨兵投票,看看选择哪个从机代替主机
sentinel monitor myredis 127.0.0.1 6379 1
启动哨兵
root@iZbp1ixrdjvxpq8fh7vpauZ:/usr/local/bin# redis-sentinel myRedisConfig/myRedisConfig/sentinel.conf
- 如果master宕机,那么会从从机中选择一个作为主机。哨兵会根据一定的算法进行投票,可以自己深入了解。
- 如果主机又回来了,就只能当小弟了
优点:
- 哨兵集群,基于主从复制模型,所有主从的配置的有点它都有
- 主从可以切换,故障可以转移,系统的可用性更好
- 哨兵模式就是主从模式的升级,手动到自动,更加健壮。
缺点:
- redis不好在线扩容,集群容量一旦达到上限,在线扩容十分麻烦。
- 实现哨兵模式的配置其实是很麻烦的,里面有很多选择
redis缓存穿透和雪崩
缓存穿透(查不到): 是指用户查询数据,数据库中没有,那么缓存中当然也就不会有,就会导致用户在缓存中找不到,每一次都要再从数据库中查询一遍,然后返回一个空,这样相当于进行了两次无用的查询:选取查询缓存,再去查询数据库
解决方案
缓存击穿(对某个点查得太多了):