Redis
Nosql概述
为什么要用nosql
- 单机Mysql的年代
90年代 一个基本网站访问量一般不会太大,单个数据库完全足够。
这种情况下,网站瓶颈是啥?
-
数据量如果太大,一个机器放不下
-
数据的索引(B+Tree) 一个机器的内存也放不下
-
访问量(读写混合,)一个服务器承受不了
只要出现以上三种情况,就必须晋级
[DAL和DAO的区别
DAL:数据访问层
DAO:data access object数据访问对象
DAL是一层架构,DAO是DAL中的具体实现细节,
DAL可能是单个类,也可能是由多个数据访问对象组成
- Mencached(缓存)+MYSQL+垂直拆分(读写分离)
网站80%情况是在读,每次都要去查询数据库就十分麻烦,所以希望减轻数据的压力,可以使用缓存来保证。
比如网站上多个用户访问同一个链接商品,如果每个用户都去查就增加了数据压力,使用缓存只查一次就可以了。
发展过程:优化数据结构和索引—》文件缓存(IO)—》MEmcached(缓存)
3.分库分表 +水平拆分+MYSQL集群
本质:数据库(读、写)
数据库引擎:
早些年MySAM:表锁(读写会锁一个表)。十分影响效率,高并发下会出现严重的锁问题。
转战Innodb: 行锁(只会锁一行)
慢慢的就开始使用分库分表来解决读写问题。
Mysql的集群,很好的满足那个年代的
4、如今最近的年代
mysql等关系型数据库不够用了,数据量很多,变化很快。
Mysql 有的使用它来存储一些较大的文件,博客,图片,数据库表很大,效率很低,如果有一种数据库来专门处理这种数据就会让mysql压力变小。
目前一个基本的互联网项目的模型
为什么要用NoSQL
用户的个人信息,社交网络,地理位置,用户自己产生的数据,用户日志等暴发式增长。
这时候我们就需要使用nosql数据库了,Nosql可以很好地处理这些问题
什么是Nosql
not only sql 不仅仅是sql
关系型数据库:表格,行,列
nosql泛指非关系型数据库,随着web2.0诞生,传统的关系型数据不能满足web2.0的时代,尤其是超大规模的高并发的社区,暴露出来很多难以克服的问题,nosql在当今大数据环境下发展是十分迅速的,Redis式发展最快的,而且是我们当下必须掌握的
很多数据类型用户的格信信息 社交网络 地理位置。这些数据类型存储不需要一个固定的格式,不需要多余的操作就可以横向扩展。类似Map<String,Object>
Nosql特点
解耦!
1、方便扩展(数据库之间没有关系,很好扩展)
2、大数据量高性能 (redis一秒写8w次,读11w。nosql的缓存是记录级的,是一种细粒度的缓存,性能比较高)
3、数据类型多样 型 (不需要事先设计数据库)
4、传统的RDBMS和Nosql
传统的RDBMS (关系型数据库)
- 结构化组织
- SQL
- 数据和关系都存在单独的表中
- 操作,数据库定义语言
- 严格的一致性
- 基础的事务
Nosql
- 不仅仅是数据
- 没有固定的查询语言
- 兼职对存储,列存储,文档存储,图形数据库(社交关系)
- 最终一致性
- CAP定理和BASE理论 (异地多活)
- 高性能 高可用 高可扩(高扩展性)
了解 3V + 3高**
大数据时代3V 主要是描述问题
1、海量 Volume
2、多样 Varlety
3、 实时 Velocity
大数据时代的3高 主要是对程序的要求
1 高并发
2 高可拓
3 高性能
Nosql的四大分类
**KV键值对 **
- 新浪 redis
- 美团redis+tair
- 阿里 百度 redis+memecache。
文档型数据库(bson格式 和 json一样)
MongoDB (一般必须掌握)
- 是一个基于分布式文件存储的数据库 C++编写 主要用来处理大量的文档
- 是一个介于关系型数据库和非关系型数据库中间的产品,是非关系型数据库中功能最丰富的,最像关系型数据库的!
ConthDB
列存储数据库
Hbase
分布式文件系统
图关系数据库
存的是关系 而不是图形 比如社交网络 广告推荐
Neo4j 、 infoGrid
Redis入门
概述
Redis是一个开源(BSD许可)的内存中数据结构存储,用作 数据库、缓存、消息代理 和流媒体引擎。Redis提供数据结构,如字符串、散列、列表、集合、带范围查询的排序集合、位图、超日志、地理空间索引和流。Redis具有内置复制、Lua脚本、LRU驱逐、事务和不同级别的磁盘持久性,并通过Redis Sentinel和Redis Cluster的自动分区提供高可用性。
Redis(Remote Dictionary Server ),即远程字典服务
一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
称之为 结构化数据库
Redis能干嘛?
1、 内存存储、持久化 内存中是断电即失,所以持久化很重要(rdb、aof)
2、效率高 用于高速缓存
3、地图信息分析
4、计时器 计数器(浏览量)
特性
1、多样的数据类型
2、持久化
3、集群
4、事务
…
windows安装
Linux 安装
没记。。。
1、下载安装包
2、解压安装包 程序放在opt下
3、打开解压后的文件 可以看到redis配置文件
4、基本环境的安装
yum install gcc-c++
make
make install
5、redis的默认安装路径 为 /usr/local/bin
6、将redis配置文件 复制到我们当前目录下
7.redis 默认不是后台启动 修改配置文件
8、启动redis服务
9、使用redis-cli -p 6379 连接
10、查看redis进程是否开启
11、关闭redis服务
12 再次查看进程
13、后面会使用单机多redis启动集群测试
测试性能
官方自带的 redis-benchmark 压力测试工具
简单测试下:
测试:100哥并发连接 10w请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
基础的知识
默认有16个数据库 默认使用第0个
清空数据库 flushdb
清空全部的数据库 flushall
redis 是单线程!
redis 很快,是基于内存操作的,cpu基于内存操作,cpu不是redis的性能瓶颈,瓶颈是根据机器的内存和网络的带宽决定 ,既然可以是用单线程,所以就用了。
C语言写的
为什么单线程还那么快
1、误区1 高性能的服务器一定是多线程的
2、误区2 多线程(因为cpu 需要上下文切换 消耗性能) 一定比单线程效率高
速度 : cpu速度>内存>硬盘
核心:redis将所有的数据放在了内存中,所以说单线程操作效率是最高的,(多线程 cpu上下文切换 耗时的操作),对于内存系统来说,如果没有内存切换,效率就是最高的。多次读写都是在一个cpu的,在内存储存情况下,单线程是最优的。
五大数据类型
redis基本命令:
set
get
exists 判断某个key是否存在 存在返回1 不存在返回0
move key 移除当前的key
keys * 查看所有的数据库内容
expire key 时间 设置过期时间
ttl key 查看当前key过期剩余时间
type key 查看key对应值的类型
flushdb 清楚数据库(所选择的数据库)
String类型
字符串长度
strlen
set
get
append
字符串自加自减
incr
decr
incrby
decrby
字符串范围
getrange
替换
setrange
setex(set with expire)设置过期时间
setnx(set if not exist )不存在再设置 分布式锁中会常使用
批量设置 批量获取(原子性操作 要么一起成功 要么一起失败)
mset
mget
先get再set 组合命令
getset
数据结构是相同的,未来学jredis 所有命令都变成了方法。
strng 类似的使用场景:字符串 或者 数字
计数器
统计数据
粉丝数
对象缓存值
List
在redis,可以吧redis弄成栈,堆,
lpush
lpop
rpush
rpop
lrange key 0 -1
lindex
lrem list x条 value
ltrim 截断
移除列表的最后一个元素 将它移动到另一个列表
rpoplpush
lset将列表中指定下标的值替换为 另外一个值,相当于更新操作,若没有该下标则报错
lset
linsert
实际是一个链表, before after left right 都可以插入
key不存在 则创建
存在 新增内容
移除了所有的值 空链表 也不存在
在两表插入或者改动 效率最高
消息排队! 消息队列 !
set(集合)
set中的值 不能重复 并且 无序!!!
sadd
smembers
sismember
srem
scard
获取set中的随机值
srandmember
移动set集合中的某个元素到另一个集合
smove
交集 差集 并集
sdiff
sinter
sunion
微博 共同关注 共同爱好
Hash(哈希)
Map集合 key-value
set get
hmset hmget
hgetall
长度 判断key
hdel
hlen
hexists
获取所有key 或 value
hkeys
hvals
hash变更的数据
对象 user
字段 name age
Zset(有序集合)
在set基础上 增加了一个值
正序排序: 从小到大
zadd
zrangebyscope 排序
倒叙
zrevrange
获取元素数量
zcard
zcount
案例思路:
set 排序 存储班级成绩 工资表排序
普通消息 1 , 重要消息 2 带权重进行判断
三种特殊数据类型
geospatial 地址位置
可以推算地址位置信息,两地的距离,方圆几里的人
geoadd key 纬度 经度 名称
geopos 获取城市坐标
geodist 获取两地的距离
单位
m 米
km 千米
mi 英里
ft 英尺
georadius 以给定的经纬度为中心 找出某一半径内的元素
找附近的人之类的功能
GeoRadiusByMemeber 找出位于指定范围内的元素,中心点是由给定的未知元素决定的
geo底层实现原理其实就是zset 可以用zset命令操作geo
Hyperloglog
基数统计的算法
优点
占用的内存是固定的,2^64 不同的预算内宿只需要12kb内存。
什么是基数?
A {1,3,5,7,8,7}
B {1,3,5,7,8}
基数 就是不重复的元素,就是5,可可以接受误差。
网页的uv(一个人访问你一个网站多次,但是还是算做一个人!)
传统:set保存用户的id,然后可以统计set中的元素数量作为判断标椎。
这个方式如果保存大量的用户id,就会比较麻烦。目的是计数,而不是保存用户的id。
有0.81%的错误率。
pfadd
pfcount
pfmerge
Bitmaps 位图
也是一种数据结构,都是从操作二进制位进行记录。只有 0 1 两个状态。
位存储
统计用户信息 活跃 不活跃 。登录,未登录!打卡 365 打卡!
两个状态的的都能用bitmaps!
setbit
getbit
bitcount
事务
redis事务的本质
一组命令的集合!
一个事务中所有命令都会被序列化。在事务执行过程中,会按照顺序执行。
一次性、顺序性、排他性!执行一系列命令!
redis事务没有隔离级别的概念。
要么同时成功,要么同时失败。原子性!
- 但是 redis 单条命令保证原子性,事务是不保证原子性的!
redis的事务
开启事务(multi)
命令入队(就是自己想要执行的命令)
执行事务(exec)
放弃事务(discard)
错误
(1)编译型异常(代码有问题) ,事务中所有的命令都不会执行
错误的命令,执行事务也是报错的!!!
(2)运行时异常,如果事务队列存在语法性的错误,那么执行命令的时候,其他命令可以正常执行,错误命令抛出异常。
监控 watch
可以实现乐观锁!
unwatch 放弃监控
悲观锁:
什么时候都会出现问题,无论做什么都会加锁!
乐观锁:
认为什么时候都不会出现问题,所以不会上锁。更新数据的时候去判断一下在此期间是否有人修改过这个数据。
mysql中可以 设置version,获取version 更新的时候比较version
redis监视测试
Jedis
是官方推荐的java连接开发工具,使用java操作redis的中间件。
连接
1、pom文件 导入依赖
<!-- 导入jedis包-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
2、测试连接
public class Main {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1",6379);
System.out.println(jedis.ping());
}
}
常用的api
String
list
set
map
事务
正常执行
异常执行
springboot整合redis
springboot 1.几版本底层是用了 jedis
2.几 后用 lettuce
jedis: 采用的直连,多个线程操作的话,是不安全的。如果想要避免不安全,使用jedis pool连接池。
lettuce:采用netty,实例可以在多个线程中共享,不存在县城不安全的情况,可以减少线程数量。
1、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
2、配置
spring.redis.database=0
# RedisæœåŠ¡å™¨åœ°å€
spring.redis.host=127.0.0.1
# RedisæœåŠ¡å™¨è¿žæŽ¥ç«¯å£
spring.redis.port=6379
3、测试
@SpringBootTest
class RedisSbootApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("weijie1",222);
System.out.println(redisTemplate.opsForValue().get("weijie1"));
}
}
配置文件:
快照
3600 1
如果3600s内,至少有一个key进行了修改,我们将进行持久化操作
300 100
如果至少有100个key进行了修改,我们将进行持久化操作
60 10000
如果60s内,至少有10000key进行了修改,我们将进行持久化操作
持久化
stop-writes-on-bgsave-error yes 持久化如果出错,是否还需要继续工作
rdbcompression yes 是否压缩rdb文件 需要消耗一些cpu资源
rdbchecksum yes 保存rdb文件 进行错误的检查校验
dir ./ 持久化保存的目录
replication 主从复制
replication 主机ip +
security 安全
设置密码 requirepass
登录 auth +密码
限制 CLIENTS
maxclients 10000 设置能连接上的redis的最大客户端的数量
maxmemory redis 配置最大的内存容量
maxmemory-policy noeviction 内存到达上限的处理策略
Redis 提供了六种基本的淘汰策略:
volatile-lru:从设置了过期时间的键集合中选择最近最少使用的键淘汰。
volatile-ttl:从设置了过期时间的键集合中选择即将过期的键淘汰,优先优先级高的。
volatile-random:从设置了过期时间的键集合中随机选择键淘汰。
allkeys-lru:从所有键集合中选择最近最少使用的键淘汰。
allkeys-random:从所有键集合中随机选择键淘汰。
no-enviction(驱逐):禁止键淘汰,这是默认策略。当内存不足以容纳新的写入数据时,新的写入命令会报错。
设置淘汰策略的命令:
redis-cli config set maxmemory-policy <策略名称>
APPEND ONLY MODE aof
appendonly no 默认不开启,默认是rdb模式 大部分情况rdb够用
appendfilename “appendonly.aof” aof文件持久化文件名字
appendfsync always 每次修改都会sync 消耗性能
appendfsync everysec 每秒执行一次sync 可能会丢失这1s的这数据
appendfsync no 不执行sync 这个时候操作系统自己同步数据 速度最快
redis持久化
RDB
什么是rdb?
在指定的时间间隔内,将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot 快照,它恢复时是将快照文件直接读到内存里。
Reedis会单独创建一个子进程来进行持久化,会先将数据写入到一个临时的文件里,待持久化都结束了,再用这个临时文件替代上次持久化好的文件。整个过程,主进程是不进行IO操作的,这就确保了极高的性能。如果需要进行大规模的数据恢复,且对于数据恢复的完整性不是非常的敏感,那RDB比AOF更加高效,RDB的缺点就是最后一次持久化的数据可能会丢失。
rdb保存的文件是 dump.rdb文件
触发规则:
1、save的规则满足的情况下。
2、执行flushall命令
3、退出redis
这些都会生成一个dump文件
如何恢复rdb文件?
1、把rdb文件放在redis的启动目录下,redis启动的时候就会自动检查dump.rdb恢复期中的数据
2、查看需要存在的位置
优点:
1、适合大规模的数据恢复!
2、对数据的完整性不高。
缺点:
1、需要一定的时间间隔进程操作!如果redis意外宕机,这个最后一次修改的数据就丢失了
2、需要消耗一定的性能,因为起了一条子进程
AOF
aof是以日志的形式来记录每个写操作,将redis执行过的所有的指令都记录下来(读操作是不记录的),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,。换言之,redis重启就根据日志文件的内容将写的指令从前到后执行一次,完成数据的恢复工作。
开启:
appendonly yes 默认是no 不开启
appendonly no 默认不开启,默认是rdb模式 大部分情况rdb够用
appendfilename “appendonly.aof” aof文件持久化文件名字 记录所有的写操作
appendfsync always 每次修改都会sync 消耗性能
appendfsync everysec 每秒执行一次sync 可能会丢失这1s的这数据
appendfsync no 不执行sync 这个时候操作系统自己同步数据 速度最快
aof文件损坏
如果appendonly.aof 有错位,Redis是启动不起来的。需要修复aop文件。
redis提供了 redis-check-aof --fix来修复
优点:
1、每一次修改都同步,文件的完整性比较好
2、每秒同步一次,可能会丢失1s的
3、从不同步,效率最高
缺点:
1、相对于数据文件来说,aof远远大于rdb,修复速度比rdb慢
2、aof运行效率比rdb慢,因为aof是写操作
扩展:
1、RDB 持久化方式能够在指定的时间间隔内对你的数据进行快照存储
2、AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以Red is协议追加保存每次写的操作到文件末尾,Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。
3、只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化
4、同时开启两种持久化方式
(1) 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
(2)RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的错误,留着作为一个万一的手段。
5、性能建议
(1)因为rdb文件只用作后备用途,建议只在上持久化rdb文件,而且只要15分钟备份一次就够了,只保留9001这条规则。
(2)如果启用AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只加载自己的A OF文件就可以了,代价一是带来了持续的I0,二是A OF重写的最后将重写过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少A OF重写的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值。
(3)如果不Enable AOF,仅靠 Master-slave Repllcation 实现高可用性也可以,能省掉一大笔0,也减少了rewrite时带来的系统波动。代价是如果Master/slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/slave 中的 RDB文件,载入较新的那个,微博就是这种架构。
Redis发布订阅
Redis发布订阅是一种通信模式,发布者发送消息,订阅者接收消息
Redis客户端可以订阅任意数量的频道
测试
必须先订阅 在发布在能接受到
订阅
发布
原理
Redis是使用C实现的,通过分析 Redis 源码里的 pubsub.c文件,了解发布和订阅机制的底层实现,籍此加深对 Redis 的理解。
Redis 通过 PUBLISH、SUBSCRIBE和 PSUBSCRIBE 等命令实现发布和订阅功能。
通过 SUBSCRIBE 命令订阅某频道后,redis-server 里维护了一个字典,字典的键就是一个个 channel,而字典的值则是一个链表,链表中保存了所有订阅这个channel的客户端。SUBSCRIBE 命令的关键,就是将客户端添加到给定 channel 的订阅链表中。
通过 PUBLISH 命令向订阅者发送消息,redis-server 会使用给定的频道作为键,在它所维护的 channel字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。
Pub/sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个Key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。
使用场景:
1、实时消息系统
2、实时聊天(频道当成聊天室)
3、订阅 关注
稍微复杂的场景我们会使用消息中间件
redis 主从复制
概念
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,slave 以读为主。默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点.
主从复制的作用主要包括:
1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4、高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础.
为什么项目只用一太redis不行?
一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机,一主二从),原因如下
1、从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大; 单台redis内存不应该超过20G
2、从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256G,也不能将所有内存用作Redis存储内存一般来说,单台Redis最大使用内存不应该超过20G.
电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点也就是"多读少写"。
对于这种场景,我们可以使如下这种架构:
主从复制,读写分离。80%的情况下都在进行读操作!减缓服务器的压力,架构中经常使用!一主二从。
环境配置
只配置从库,不用配置主库
127.0.0.1:6379> info replication
# Replication
role:master #查看当前库角色
connected_slaves:0
master_failover_state:no-failover
master_replid:e31396caac422bd7f5fe5e59d90df4f466c6c6ce
master_replid2:d7e43654ae245c7686d4b9d37d0027cc6d3ac128
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
127.0.0.1:6379>
准备
复制三个配置文件
cp redis.conf redis81.conf
修改对应的信息
1、端口号
2、pid
3、log文件名字
4、dump.rdb 文件名
根据不同的配置文件启动redis,根据不同端口号连接redis
查看进程
一主二从
默认情况下,每台服务器都是主节点
配置
只配置从机就可以
SLAVOFE 地址 端口号
从机
主机
真实的主从配置应该在配置文件中修改,命令修改只是暂时的
细节
1、主机可以写,从机负责读。主机中所有的信息和数据,都会被从机保存
2、主机断开连接,从机依旧是连接到主机的。只是没有写的操作了。
3、如果是使用命令行配置的主从复制,从机断开就会变回主机
复制原理
Slave 启动成功连接到 master 后会发送一个sync命令
Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
哨兵模式
概述
主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成-段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel(哨兵)架构来解决这个问题。
谋朝篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
这里的哨兵有两个作用
通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器
当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。
然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行fàailover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。
测试
目前是一主二从模式!
1、配置哨兵配置文件
文件名 sentinel .conf
sentinel monitor myredis1 127.0.0.1 6379 1
#sentinel monitor 被监控的名称 host port 1
这个最后的1 代表是主机挂了,slave投票看让谁接替成为主机。票数最多的成为主机
2、启动哨兵 redis-sentinel
3、模拟主机挂掉
6379 shutdown
如果把6379连回来 也不会变为主机,只能当从机
优点
1、哨兵集群,基于主从复制模式,所有的主从配置优点,它全有
2、主从可以切换,故障可以转移,系统的可用性就会更好
3、哨兵模式就是主从模式的升级,手动到自动,更加健壮!
缺点:
1、Redis 不好啊在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦!
2、实现哨兵模式的配置其实是很麻烦的,里面有很多选择!
哨兵模式全部配置
百度
Redis缓存穿透和雪崩
Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据査询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据的一致性要求很高,那么就不能使用缓存,另外的一些典型问题就是,缓存穿透、缓存雪崩和缓存击穿。目前,业界也都有比较流行的解决方案。
缓存穿透(查不到)
概念
缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
解决方案
布隆过滤器
是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验
不符合则丢弃,从而避免了对底层存储系统的查询压力
缓存空对象
当存储层不命中后,即使返回的空对象也将其缓存起来,同事会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端的数据源
但是这种方法会存在两个问题:
1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键
2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响
缓存击穿(量太大,缓存过期)
概念
这里需要注意和缓存击穿的区别,缓存击穿,是指一个kev非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来査询最新数据,并且回写缓存,会导使数据库瞬间压力过大。
解决方案
设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。
加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去査询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移了分布式锁,因此对分布式锁的考验很大。
缓存雪崩
概念
缓存雪崩,是指在某一个时间段,缓存集中过期失效。Redis 宕机!
产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
解决方案
redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。
限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
统的查询压力
[外链图片转存中…(img-z2OyAS22-1712108929133)]
缓存空对象
当存储层不命中后,即使返回的空对象也将其缓存起来,同事会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端的数据源
[外链图片转存中…(img-CI05FQtG-1712108929133)]
但是这种方法会存在两个问题:
1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键
2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响
缓存击穿(量太大,缓存过期)
概念
这里需要注意和缓存击穿的区别,缓存击穿,是指一个kev非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来査询最新数据,并且回写缓存,会导使数据库瞬间压力过大。
解决方案
设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。
加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去査询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移了分布式锁,因此对分布式锁的考验很大。
缓存雪崩
概念
缓存雪崩,是指在某一个时间段,缓存集中过期失效。Redis 宕机!
产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
解决方案
redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。
限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。