Redis
NoSQL
特点
数据之间没有关系,方便扩展
大数据量高性能
数据类型多样, 不需要事前设计数据库
读11w次,写8w次
不仅仅是数据
没有固定的查询语言
键值对存储,列存储,文档存储,图形数据库
最终一致性
CAP定理 和 BASE (异地多活)
四大分类
KV键值对
redis
文档型数据库(bson)
-
MongoDB:
基于分布式文件存储的数据库,用来处理大量文档
介于关系型和非关系型数据库的中间产品
属于NoSQL中功能最丰富,最像关系型数据库的
列存储数据库
分布式文件系统
图关系数据库
社交网络、广告推荐
Redis入门
Remote Dictionary Server: 远程字典服务
端口6379
认识
能干嘛?
1、内存存储、持久化。(rbd、aof)
2、效率高,用于高速缓存
3、发布订阅系统
4、地图信息分析
5、计时器计数器
6、。。。
特性
1、多样数据类型
2、持久化
3、集群
4、事务
。。。
WINDOWS
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8zIaI74y-1636819813673)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211030210005160.png)]
如果闪退:redis-server redis.windows.conf
LINUX
安装
直接解压到/opc
配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UEWOn4RX-1636819813679)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211102163010990.png)]
环境安装及启动
yum install gcc-c++:解压完后要下载c++环境,因为redis是c++写的
make:自动安装其他需要的(make2次
make install
自己安装的程序都在/usr/local/bin
将redis配置文件复制到当前目录下
cp /opt/redis-6.2.6/redis.conf kconfig
之后就使用这个配置文件启动
redis默认不是后台启动,要修改配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W5kRVMmC-1636819813681)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211102171246992.png)]
改成yes,以后为后台方式启动
启动redis服务
redis-server kconfig/redis.conf #(kconfig在/usr/local/bin)
连接服务
redis-cli -p 6379:使用redis客户端连接到端口
ping:返回pong就是成功
设置:set name bb
获取:get name:返回“bb”
查看所有键:keys *
查看服务:ps -ef|grep redis
关闭redis服务
shutdowm :在连接服务中使用
压力测试
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
本机 端口 100个并发连接数 每个连接100000条请求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-waTHc3Ec-1636819813684)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211102182012627.png)]
基础知识
数据库
redis默认有16个数据库
默认使用第0个
可以用select num切换
查看DB大小 :DBSIZE
查看DB所有的Key:keys *
清空当前数据库:flushdb
清空全部数据库:flushall
是否存在:exists name:返回1表示存在 / 0
移动:move name 1:移除name到1号数据库
其他
redis是单线程的,是很快的
redis是基于内存操作的,cpu不是redis的性能瓶颈,是机器内存和网络带宽
既然可以使用单线程,那就使用单线程了。
为什么redis单线程还这么快?
1、误区:高性能服务器一定是多线程的
2、误区:多线程(会产生CPU上下文切换,耗时)一定比单线程效率高
CPU>内存>硬盘
核心:redis是将所有的数据全部放在内存中,所以使用单线程去操作效率是最高的
五大基本数据类型
关于Redis-Key
设置限时:expire key seconds:多长时间后过期
查看剩余时间:ttl key:-2代表没了
查看key的类型:type key
String
set key value #设置值
get key #获取值
keys * #查看所有key
# 修改
append key1 "hello" #给key1的value追加字符串"hello","v" -> "vhello"
ps:如果当前key并不存在 就相当于set key value
strlen key1 #获取字符串长度
# 自增自减
incr key:加1操作
decr key:减1操作
incrby key 10:加10操作
decrby key 11:减11操作
# 截取
getrange key start end #获取某个范围内 [0,3] #类似java的substring
# 替换
setrange key offset value #从offset开始,替换成value #类似java的replace
例 name:abcd -> setrange name 1 xx -> axxd
# 设置
setex key seconds value #set with expire 设置过期时间,跟上面的设置限时同理
setnx key value #set if not exist 分布式锁
#如果key不存在再设置,就是如果这个值已经存在了就设置失败(普通set会替换),分布式常用
set key value nx ex 10 #分布式锁:设值的同时加锁并设置过期时间
# 一次设置(获取)多对kv
mset k1 v1 k2 v2 k3 v3
mget k1 k2
#特殊
msetnx k1 v1 k4 v4 #是原子性操作,一个失败(k1)全都失败
# getset
getset key newvalue #先get后set
#如果不存在,返回nil
#如果已经存在了,先get旧的,再set新的
#再get,得到的才是新的
# 设置对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BDnAiT67-1636819813686)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211103002007927.png)]
List
栈、队列
list所有命令都是l开头的
# 插入
lpush list one #将一个值或多个值插入到列表头
lpush list two three #插入多个
rpush list fuor #插入到尾(right,从右边插入)
# 查看
lrange list 0 1 #显示list里面[0,1]的数据(从头开始:two one)
lrange list 0 -1#显示list全部数据
# 移除
lpop list [count] #从头移除count个
rpop list [count] #从尾移除count个
# 用下标获取值
lindex list 0 #获取第0个的值
# 查看长度
llen list #返回长度
# 移除指定值
lrem list count element #移除count个指定值element
# 修剪
ltrim list start stop #只保留[start,stop]之间的值
# 移除并添加
rpoplpush source destination #将列表1最右边的值移除并添加到列表2
# 更新值
lset key index newvalue # 将链表key里面 下标为index的值更新为newvalue
# 不存在的话会报错 下标越界
# 插入
linsert key before|after which element #在which的前面或后面插入元素element
Set
集合,不能重复
set所有命令都是s开头的
# 添加
sadd key v1 v2 v3.. #可以添加多个
# 查看
smembers key #查看这个key的所有元素
sismember key value #判断key中是否存在value(无返回0 有返回1)
scard key #查看key中元素个数
srandmember key [count] #随机查看count个元素
# 移除
srem key value #移除元素
spop key [count] #弹出顶部count个元素
smove set1 set2 element #把set1中的元素element移动到set2中
集合
127.0.0.1:6379> SMEMBERS set1
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> SMEMBERS set2
1) "v5"
2) "v4"
3) "v3"
# 差集 sdiff
127.0.0.1:6379> SDIFF set1 set2
1) "v1"
2) "v2"
SDIFF set1 set2 # 以set1为基准(not in set2)
# 交集 sinter (共同关注)
127.0.0.1:6379> SINTER set1 set2
1) "v3"
SINTER set1 set2 # 查找set1 set2的交集
# 并集 sunion
127.0.0.1:6379> SUNION set1 set2
1) "v5"
2) "v2"
3) "v3"
4) "v1"
5) "v4"
SUNION set1 set2 # set1与set2的并集
实战中,将所有关注的人放在set中,粉丝也放在一个set中…
共同关注、共同爱好 推荐好友 你可能认识的人
Hash
类 Map集合, key-Map集合 key-
hash所有命令都是h开头的
# 添加
hset key field1 value1 field2 value2 #已有则替换(会返回0)
# 特殊
hsetnx key field value #如果已存在field就不创建了
# 查看
hget key field #返回value
hmget key field1 field2 #一次性查询多个field
hgetall key #获取所有field和value
hkeys key #只获取所有的field
hvals key #只获取所有的value
hlen key #获取长度(数量)
hexists key field #查看这个feild是否存在(0/1)
# 移除
hdel key field
# 自增自减
hincrby key field increment #给field的value增加increment
Zset
有序集合,底层是条约链表
在set的基础上增加了一个值 zset k1 score1 v1
score可以是1 2 3 4 … 自己进行(优先级)排序
# 添加
zadd key score value #score是自己排序
# 查看
zrange key min max # 0 -1 可以查看全部
zrangebyscore key min max [withscores] #查看范围[min,max];
#[-inf,+inf]代表正负无穷到正无穷
#withscores可以value和score都显示,不添加则只显示value
zrevrangebyscore key max min [withscores] #倒序查看
zcard key #获取集合个数
# 移除
zrem key value1 value2
三种特殊数据类型
geospatial(地理位置)
有6个命令
geo底层实现原理其实是zset,所以可以使用zset命令来操作geo
geoadd 添加
# geoadd 添加地理位置
# 经度从-180 到 180
# 纬度从-85 到 85
geoadd key 经度 纬度 value #geoadd city 116.40 39.90 beijing
geopos 获取
# geopos 获得定位
geopos key value1 value2... #获得value的经纬度
geodist 距离
# geodist 获得两个value之间的距离
geodist key value1 value2 [m|km|...] #返回两地距离
georadius 坐标查找
# georadius 以给定的经纬度为中心,查找半径内的元素
georadius key 经度 纬度 半径 m|km #根据输入的经纬度,查找该地点 指定半径内的其他元素
georadius key 经度 纬度 半径 m|km [withdist] [withcoord]
# [withdist] 顺带显示其他元素到指定坐标的距离
# [withcoord] 顺带显示其他元素的定位信息
例
127.0.0.1:6379> georadius city 110 30 500 km
1) "chongqing"
2) "xian"
127.0.0.1:6379> georadius city 110 30 500 km withdist
1) 1) "chongqing"
2) "341.9374"
2) 1) "xian"
2) "483.8340"
127.0.0.1:6379> georadius city 110 30 500 km withcoord
1) 1) "chongqing"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
2) 1) "xian"
2) 1) "108.96000176668167114"
2) "34.25999964418929977"
georadiusbymember 元素查找
# georadiusbymember 以给定的元素查找半径范围内的其他元素
georadiusbymember key 元素 半径 m|km [withdist] [withcoord] #返回元素半径内的元素(包含自己)
geohash 返回元素hash
# geohash 将二位的经纬度转化成以为的字符串,两个元素字符串越接近,距离越近
geohash key 元素... #beijing->"wx4fbxxfke0"
zset 查看与移除
因为底层是zset,所以可以用zset来操作!!!
# 查看
zrange key 0 -1 [withscores] #查看所有的value [顺带显示hash]
# 移除
zrem key value #移除
hyperloglog(基数统计)
基数:不重复的元素的个数
hf开头,会有0.81%容错率
# 添加
pfadd key element1 element2...
# 查看
pfcount key #查看总数量(会去重)
# 合并
pfmerge key1 key2... #将key2...去重合并到key1(key1不存在会新建)
bitmap(位图)
位存储, 只有0 1,数据结构,都是操作二进制位来记录
场景:登录、活跃、打卡等 两个状态的都可以用
只要1个bit,1字节=8bit,省
# 添加
setbit key offset value #offset自己设(只能数字),value只能0 1
# 查看
getbit key offset #查看value(0/1)
bitcount
事务操作
事务
一次性、顺序性、排他性
redis单条命令保证原子性,但是事务不保证原子性
redis事务没有隔离性
redis的事务:
- 开启事务(multi)
- 命令入队
- 执行事务(exec)
127.0.0.1:6379> multi #开启事务
OK
# 命令入队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec #执行事务
1) OK
2) OK
3) "v2"
4) "v1"
5) OK
放弃事务:discard
编译型异常,事务中所有命令都不执行
27.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> getset k2 # 错误的命令 (set k2 )也不行
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> set k5 v5
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k5 # 命令没有执行
(nil)
运行时异常,只有错误的那条语句不执行
锁
监控 watch
锁: redis可以实现乐观锁
set money 100
set out 0
watch money #监视money对象
multi #事务开启
decrby money 20
incrby out 20
#exec #这里 先不提交事务
############这时插入了另一个线程对money改动############
set money 1000
##################################################
#接着回到这边,提交事务
exec
(nil) #返回空,代表事务执行失败,有其他线程对这个money进行了修改
解决办法:如果获取失败,获取最新的值即可
unwatch #先解锁
watch #再加锁,这样获取的就是最新的值了
Jedis
1、导入对应以来
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
2、编码测试
- 连接数据库
- 操作命令
- 断开连接
测试 事务
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1",6379);
Transaction multi = jedis.multi();//开启事务
try {
multi.set(new String("a"),new String("hihi"));
multi.set(new String("b"),new String("hoho"));
multi.exec(); //执行
} catch (Exception exception) {
multi.discard();//回滚
} finally {
System.out.println(jedis.get(new String("a")));//hihi
jedis.close(); //关闭连接
}
}
SpringBoot集成Redis
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
简单测试
@SpringBootTest
class DemoApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("a","hi");
System.out.println(redisTemplate.opsForValue().get("a"));
}
}
复杂测试(序列化、json
@Test
void test2() throws JsonProcessingException {
User bb = new User("bb", 18);
// redisTemplate.opsForValue().set("user",bb);
//没有序列化是不能传输的 //User要加实现序列化接口
// :User(name=bb, age=18)
//转化成json对象 //所有对象都要序列化(这里是转json对象
String jsonBB = new ObjectMapper().writeValueAsString(bb);
redisTemplate.opsForValue().set("user",jsonBB);
// :{"name":"bb","age":18}
System.out.println(redisTemplate.opsForValue().get("user"));
}
自定义RedisTemplate
因为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJ4gnDHk-1636819813689)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211105202210175.png)]
所以我们自定义redisTemplate
@Configuration
public class redisConfig {
//自定义RedisTemplate
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
自定义redisUtils封装类
代码太多,另见文章
redis.conf配置文件详解
- 单位
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iJCZe0hh-1636819813691)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107160240193.png)]
- 包含其他配置文件
可以组合其他配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RPiFT8hX-1636819813692)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107165219195.png)]
- 网络
bind 127.0.0.1 -::1 #绑定的ip
protected-mode yes #保护模式
port 6379 #端口号
- 通用配置GENERAL
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 "" #生成的日志文件位置
databases 16 #数据库数量
always-show-logo no #是否总是显示logo
- 快照
持久化,在规定时间内,执行多少次操作,就会持久化到文件.rdb.aof
redis是内存数据库,如果没持久化,那么数据断电就会丢失
# save 3600 1 #如果3600秒内至少有1个key做了修改,就持久化
# save 300 100
# save 60 10000
stop-writes-on-bgsave-error yes #持久化如果出错了,是否还继续工作
rdbcompression yes #是否压缩rdb文件(rdb:持久化文件)
rdbchecksum yes #保存rdb时是否进行检查校验
dir ./ #rdb文件保存的目录
- 复制REPLICATION
- 安全
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9trHRQYj-1636819813694)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107174855199.png)]
自定义密码 root
也可以用命令来设置密码
127.0.0.1:6379> config get requirepass #查看密码
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass "root" #设置密码
auth root #输入密码 才能进行操作
- 限制CLIENTS
# maxclients 10000 #最大客户端数量
# maxmemory <bytes> #redis配置的最大内存容量
# maxmemory-policy noeviction #内存满了之后的处理策略
1、volatile-lru:只对设置了过期时间的key进行LRU(默认值)
2、allkeys-lru : 删除lru算法的key
3、volatile-random:随机删除即将过期key
4、allkeys-random:随机删除
5、volatile-ttl : 删除即将过期的
6、noeviction : 永不过期,返回错误
- APPEND ONLY 模式 aof配置
appendonly no # 默认不开启aof模式,默认使用rdb方式持久化,大部分情况下
appendfilename "appendonly.aof" # 持久化文件的名字
# 同步
# appendfsync always #每次修改都同步(消耗性能
appendfsync everysec #每秒执行一次(可能丢失这一秒数据
# appendfsync no #不同步
具体配置在持久化中详细讲解
持久化
如果只做缓存,就不需要持久化了
因为Redis是内存数据库,如果不保存到磁盘中,断电就消失,所以要持久化。
同时开启两种方式,优先载入aof文件来恢复数据,因为aof文件保存的数据更完整,
RDB(Redis DataBase)
默认的redis数据库,在主从复制中,rdb是备用的,在从机上面用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9KYhxhO0-1636819813696)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107210954318.png)]
在指定的时间间隔将内存中的数据集快照写入磁盘,恢复时是将快照文件直接读到内存。
redis会单独fork创建一个子线程来进行持久化,会先将数据读到一个临时文件,等持久化过程结束了,再用这个临时文件替换上次持久化好的文件。
整个过程中,主线程不进行IO操作,确保高性能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ChDmSAZ-1636819813697)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107211333539.png)]
dump.rdb
触发机制
1、save命令(保存配置),会自动触发rdb规则
2、执行flushall命令,也会触发rdb规则
3、退出redis,也会产生rdb文件
4、触发快照也会触发rdb操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TLXMGjOo-1636819813698)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107210248600.png)]
恢复rdb
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d6DHsYvn-1636819813700)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107210358191.png)]
1、只需要将rdb文件放在redis启动目录就可以,redis启动的时候会自动检查dump.rdb,恢复其中的数据
2、查看需要存放的位置
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin" #如果在这个目录下存在dump.rdb,那启动就会自动恢复其中数据
优缺点
优点:
1、适合大规模的数据恢复 :dump.rdb
2、对数据完整性要求不高
缺点:
1、需要一定的时间间隔进程操作,如果redis意外宕机了,最后一次的数据就没了
2、fork进程的时候,会占用一定的内存空间
AOF(Append Only File)
将我们的所有命令都记录下来,history,恢复的时候,就把这个文件全部执行一边
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9hkXSVT-1636819813701)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107211628312.png)]
一般来说,只需要将no改成yes,开启就行了,其他使用默认即可
aof文件被破坏了,如何恢复
如果 appendonly.aof 文件被破坏了,redis启动不了(redis-cli -p 6379会报错)
需要恢复: redis-check-aof
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3k9wBuA-1636819813702)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211107213713793.png)]
redis提供了工具:redis-check-aof --fix
redis-check-aof --fix appendonly.aof
会丢弃错误的数据
重写规则
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
如果aof文件大于64m,就会fork一个新的进程来将文件重写
aof默认就是文件只限制追加,文件就会越来越大
优缺点
appendonly no #默认不开启aof
appendfilename "appendonly.aof" # 持久化文件的名字
# 同步策略
# appendfsync always #每次修改都同步(消耗性能
appendfsync everysec #每秒执行一次(可能丢失这一秒数据
# appendfsync no #不同步
优点:
1、每一次修改都同步,完整性更好
2、每秒同步一次,可能会丢弃一秒的数据
3、从不同步,效率最高
缺点:
1、相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢
2、aof运行效率低,是io操作,所以我们默认rdb持久化而不是aof
订阅发布(消息队列)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wcZWrhzj-1636819813704)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211108153633485.png)]
测试
订阅端:
127.0.0.1:6379> subscribe c1 #订阅频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "c1"
3) (integer) 1
#等待接收消息
1) "message" #消息
2) "c1" #频道
3) "nihao" #接收的消息
发送端:
publish chanel message 发布消息
主从复制
概念
主从复制,就是将一台redis服务器的数据复制到其他redis服务器,分为主节点和从节点。
主从复制,读写分离。80%的读操作放到从,写放到主中进行。一主二从。
单台redis最大使用内存不应该超过20G
作用
1、数据冗余:主从复制实现了数据热备份
2、故障恢复:主节点出现问题时可以由从节点提供服务
3、负载均衡:读写分离,提高并发量
4、高可用(集群)基石:哨兵和集群的基础
info replication:查看复制信息
127.0.0.1:6379> info replication
# Replication
role:master #角色
connected_slaves:0 #没有从机
master_failover_state:no-failover
master_replid:8a09e83b5cdd576df8f7a83f09fe43478a5cdc4c
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.conf配置文件
(改端口,改pidfile,改日志名,改dump.rdb名字
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LlexqnjH-1636819813705)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211111184120612.png)]
一主二从
默认情况下,每台redis服务器都是主节点,所以只要配置从机
配从机:认主银!
1、这里是用命令配,实际中使用配置文件配
slaveof host port
#在6380中:
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave #角色:从机
master_host:127.0.0.1 #主机地址
master_port:6379 #主机端口
用配置文件配主,这样才是永久的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3H3OfGO-1636819813706)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211111191539906.png)]
主机负责写,从机负责读
结论一:主机才能写,从机只能读,从机写会报错
结论二:如果主机关了(宕机),从机依然是连接主机的,但是没有写操作,这时候如果主机回来了,从机依然可以读取主机写的东西
结论三:如果使用命令配置从机的,从机断了重启后,会变回主机;但是再把他配回从机后,这期间主机写的数据他还是能获取的(同步
原理
slave启动成功连接到主机后会发送一次sync同步命令
master接到命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,
在后台进程完毕后,master将传送整个数据文件到slave,并完成一次完全同步
- 全量复制:而slave在接收到数据库文件数据后,将其存盘并加载到内存中
- 增量复制:master继续将新的所有收集到的修改命令依次传给lave,完成同步
但是只要是重新连接master,依次完全同步(全量复制)将自动进行,我们的数据一定可以再从机得到
哨兵模式
自动选举老大模式
测试
目前:1主(6379)2从(6380/6381)
1、配置哨兵配置文件 sentinel.conf
#sentinel monitor 被监控的名称 主机 端口 1
sentinel monitor myredis 127.0.0.1 6379 1
# 最后的1代表 主机挂了,从机投票看让谁接替成为主机,票数最多的当主机
2、启动哨兵
bin目录下文件redis-sentinel
redis-sentinel kconfig/sentinel.conf
[root@localhost bin]# redis-sentinel kconfig/sentinel.conf
27788:X 11 Nov 2021 22:14:54.239 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
27788:X 11 Nov 2021 22:14:54.239 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=27788, just started
27788:X 11 Nov 2021 22:14:54.239 # Configuration loaded
27788:X 11 Nov 2021 22:14:54.241 * Increased maximum number of open files to 10032 (it was originally set to 1024).
27788:X 11 Nov 2021 22:14:54.241 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.2.6 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379
| `-._ `._ / _.-' | PID: 27788
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
27788:X 11 Nov 2021 22:14:54.243 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
27788:X 11 Nov 2021 22:14:54.264 # Sentinel ID is 62b26ebe620df2ef05a3d045fb2164efc54bd23d
27788:X 11 Nov 2021 22:14:54.264 # +monitor master myredis 127.0.0.1 6379 quorum 1
27788:X 11 Nov 2021 22:14:54.270 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:14:54.273 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
然后,如果主机宕机了shutdown
,哨兵配置文件这里就会发现,然后选择一个从机当主机
27788:X 11 Nov 2021 22:23:36.567 # +sdown master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.567 # +odown master myredis 127.0.0.1 6379 #quorum 1/1
27788:X 11 Nov 2021 22:23:36.567 # +new-epoch 1
27788:X 11 Nov 2021 22:23:36.567 # +try-failover master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.571 # +vote-for-leader 62b26ebe620df2ef05a3d045fb2164efc54bd23d 1
27788:X 11 Nov 2021 22:23:36.571 # +elected-leader master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.571 # +failover-state-select-slave master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.630 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0. 0.1 6379
27788:X 11 Nov 2021 22:23:36.630 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 63 80 @ myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.686 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:37.236 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0. 0.1 6379
27788:X 11 Nov 2021 22:23:37.236 # +failover-state-reconf-slaves master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:37.290 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127 .0.0.1 6379
27788:X 11 Nov 2021 22:23:38.255 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 1 27.0.0.1 6379
27788:X 11 Nov 2021 22:23:38.255 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127 .0.0.1 6379
27788:X 11 Nov 2021 22:23:38.355 # +failover-end master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:38.355 # +switch-master myredis 127.0.0.1 6379 127.0.0.1 6380
27788:X 11 Nov 2021 22:23:38.356 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6380
27788:X 11 Nov 2021 22:23:38.356 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380
27788:X 11 Nov 2021 22:24:08.387 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380
注意最后 可以看出6380成了新的主机
如果后来6379回来了,则6379会变成从机,主机依然是6380
6380: 现在我是老大了,回来只能做我小弟
优缺点
优点:
1、哨兵集群,基于主从复制,所有主从复制优点他都有
2、主从可以切换,故障可以转移,系统可用性更好
3、哨兵模式就是主从模式的升级:手动到自动
缺点:
1、redis不好在线扩容,集群容量一旦到达上限,在线扩容就十分麻烦
2、实现哨兵模式的配置很麻烦,里面有很多选择(我们配的是最基础的
缓存穿透(查不到)
概念
当用于查询数据时,如果redis内存数据库中没有,就向持久层数据库查询,发现也没有,于是查询失败。当用户很多的时候,缓存都没有命中,于是都去请求持久层数据库,这会给持久层数据库带来很大压力,这就是缓存穿透
解决方案
布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免对底层存储系统的查询压力。
缓存空对象
当存储层不命中后,即时返回的空对象也将其缓存起来,同时设置一个过期时间,之后再访问这个数据就会从缓存中获取,保护了后端数据源
缓存击穿(量太大,缓存过期)
概念
key是有时效的
一个key非常热点,不断地大并发请求这个key,在这个key失效的瞬间,持续的大并发就会穿破缓存,直接请求数据库。
解决方案
设置热点数据永不过期
不设置过期时间,也就不会出现热点key过期后产生的问题
缺点:不现实,浪费
ps:也可以设置久一点
加互斥锁
set key value nx ex 10
nx: 加锁
ex 10 :过期时间10秒
分布式锁:使用分布式锁,保证每个key同时只有一个线程去查询后端,其他线程等待。
缺点:这种方式把高并发的压力转移到了分布式锁
缓存雪崩
概念
在某一个时间段,缓存集中过期失效,或是redis宕机
比如双十一,马上0点,这时集中放入了缓存,过了一个小时后,这批商品的缓存集体失效了,于是对这批商品的查询就落到数据库上,对数据库而言就会产生周期性压力波峰,造成存储层也挂掉的现象。
解决方案
1、redis高可用,搭建集群,多增设几台redis,一台挂了其他还可以用
2、限流降级:缓存失效后,通过加锁或者队列来控制数据库写缓存的线程数量
3、数据预热:在正式部署前,先把可能的数据预先访问一遍,这样大量访问的数据就会加载到缓存中。自己手动触发加载不同key,设置不同的过期时间,让缓存失效时间尽量均匀。