一、数据存储发展:
-
单机Mysql(缺点:随着数据量和访问量增大,无法承受)
-
缓存+垂直拆分(读写分离)
-
缓存+水平拆分+Mysql集群
二、引入NoSql(数据类型的多样化需要NoSql解决)
NoSql 特点:
- 数据间没有关系,方便扩展
- 高性能(redis一秒写8万次,读11万次)
- 存储各种数据类型,不需要提前设计数据库。
各种数据库选择:
- 商品基本信息:关系型数据库(mysql)
- 商品描述(文字多):MongoDB
- 图片:分布式文件系统(HDFS)
NoSql 四大类:
- KV键值对:redis
- 文档型数据库:MongoDB(类似关系型数据库)
- 列存储数据库(HBase,分布式文件系统)
- 图关系数据库(非图像,如社交网络):(Neo4j)
三、Redis
概述:redis是远程字典服务,Key-Value数据库,提供多种语言API(不是关系型数据库,是结构化数据库)
特点:多样数据类型,持久化,集群,事务,高效率
1. 基础知识:
- Redis默认16个数据库,默认使用第0个。
- Redis是单线程的,redis是基于内存操作,它的瓶颈取决于内存和网络带宽,不在CPU。多线程CPU会进行上下文切换,所以redis采用单线程效率是最高的。(基于磁盘操作选择多线程是因为,磁盘读取速度慢,多线程能够提高cpu的利用率)
2. 五种基本数据类型:
- String字符串(可用于计数器,缓存等)
- List列表(底层是链表。可以当作栈,队列,阻塞队列来使用)
- Set集合(值不重复,可以用于且交集,如共同好友等)
- ZSet有序集合(相对Set多一个值,ZSet会根据该值排序,可用于排行榜之类的)
- Hash(本质跟String类似,key-value形式,hash多用于对象存储,String多用于字符串存储)
3. 三种特殊数类型
- Geospatial(可以添加地理位置(经纬度),可以计算两地间的距离,或者查找某地周围元素,它底层是ZSet,可以使用ZSet相关命令操作Geospatial)
- Hyperloglog(可以求并集,可以用于统计网站访问量(同一个用户算一次访问),占用固定12kb内存,就可以统计2^64用户量,有0.81%错误率。如果不允许出错,可以使用set或自定义数据类型)
- Bitmap(位存储,只有0,1两个状态,用于统计两个状态的信息,如活跃,不活跃。如使用bitmap记录员工一年打卡记录,可以很快算出打卡天数)
4.事务:
- redis事务本质是一组命令的集合。reids事务没有隔离级别概念,事务命令加入队列后,要发起执行命令才执行。流程:开启事务(multi)-命令入队-执行事务(exec)
a) 单条命令是原子性,但事务不保证原子性
b) 在命令入队后,可以使用discard取消事务
c) 在入队的命令中,若命令本身有错,执行事务后所有命令不会生效。若是其中命令出现运行时异常(1/0),则执行事务时,其他命令生效,异常命令抛出异常。 - Redis事务中的监控Watch(乐观锁)
a) 悲观锁:做什么都加锁。
b) 乐观锁:只有更新数据时判断是否有人改过该数据,改过不执行。Redis中watch就是乐观锁。(先监控一个数据,在开启事务,加入命令执行时判断监控数据是否被修改,修改就会导致执行事务失败)
Jedis: redis官方推荐java操作redis的中间件
四、Springboot整合redis(比单独使用jedis更方便)
- SpringBoot2.x后,原来使用的jedis替换为lettuce。Jedis采用直连,多个线程操作不安全,避免不安全可以使用jedis pool连接池,更新BIO模式。Lettuce采用netty,实例可以在多个线程中共享,不存在线程不安全情况,可减少线程数据。更像NIO模式。
- 注意:springboot给我们定义了一个redisTemplate模板,但操作比较繁琐,一般情况下都是自己定义一个redisTemplate模板(可以配置序列化方式等——如过一个类没有配置序列化,直接加入redis是会报错的),在根据该模板设计一个redis工具类,通过工具类操作redis,简化操作。
五、Redis.conf详解(启动时,可以根据指定的配置文件启动)
- 配置文件不区分大小写
- 配置文件中可以通过include引入其他文件
- 配置文件中的重要内容:
a) 可以绑定可访问ip,设置端口, 设置后台方式运行(默认关闭), 设置redis密码(默认无密码)
b) 设置数据库个数(默认16个),redis最大内存以及到达最大内存后的处理策略,最大客户端个数,
c) 设置持久化rdb相关:1.如save 900 1表示900秒内,有至少1个内容修改就进行持久化操作。2.持久化出错是否工作,.是否压缩rdb文件,对rdb文件校验,文件位置等
d) 设置持久化aof相关:1.是否开启aof(默认关闭),aof保存文件名, 执行持久化操作触发(如默认appendfsync everysec :每秒触发。也可以改为没条命令都触发,或者不执行sync)
六、redis持久化(redis是内存数据库,如果不将内存中的数据保存到磁盘,一旦出现如断电情况,数据就会丢失)
redis提供的两种持久化:
1. Rdb(在指定间隔内将内存中的数据集快照写入磁盘,恢复时将快照文件直接读到内存中)
Redis单独创建一个子进程来进行持久化,主进程不进行任何IO操作,确保性能。
- 触发机制:
a) 配置文件中的Sava规则满足时(如save 900 1表示900秒内,有至少1个内容修改就进行持久化操作。)
b) 执行flushall命令
c) 退出redis时 - 优点:效率较高,适合大规模数据恢复
- 缺点:因为是一定间隔时间进行复制,所以数据可能不完整
2. Aof(将所有执行过的写命令记录下来,恢复的时候再全部执行一遍)
-
Aof默认不开启
-
如果aof文件被修改,可以通过redis-check-aof 来恢复
-
触发机制跟rdb一致,在配置文件中通过下面命令设置
appendfsync always # 每次修改都会 sync。消耗性能 appendfsync everysec # 每秒执行一次 sync,可能会丢失这1s的数据! appendfsync no # 不执行 sync,这个时候操作系统自己同步数据,速度最快!
-
Aof是通过追加的形式将命令保存在aof文件中,所以aof文件会越来越大,默认大于64mb就会重写(压缩命令)来减少文件大小
-
优点:如果每次命令都同步,数据完整性会很好
-
缺点:效率比rdb慢
-
同时开启rdb和aof会优先载入aof中的数据,因为它相对更完整
七、Redis发布订阅(是一种消息通信模式,可以用于实时聊天系统,订阅关注系统等,对于复杂场景可以使用消息中间件MQ)
- 三个部分组成:消息发送者,频道和消息订阅者
- Redis-server维护一个字典,字典键就是一个个频道,字典值就是一个链表(保存所有订阅了该频道的客户端)。
- 订阅频道:通过subscribe订阅某个频道(如:SUBSCRIBE kuangshenshuo,若字典无该频道,会新生成一个)
- 发布消息:通过publish命令发布消息(如:PUBLISH kuangshenshuo “hello,kuangshen”),redis-server会根据publish给定的频道作为键,在字典中查找对应订阅该频道的客户,最后将消息发给所有客户。
八、Reids主从复制(将一台redis服务器作为主节点,将其数据复制到其他从节点redis服务器,数据复制只能从主节点到从节点,主节点master写为主,从节点slave读为主)
主从复制作用:1. 数据热备份,2.数据恢复。3.负载均衡(读写分离)。4.高可用基石(如它是哨兵模式基础)
- 默认每个 redis服务器都是主节点,可以设置它的主节点(配置文件或命令行设置,命令行设置下次启动不生效)
- 只有主机节点可以写,从机节点只能读
- 一个主节点可以多个从节点,一个从节点只能有一个主节点。
- 主机宕机后,从机依然可以使用
- 复制原理:每次从机重新连接主机都会进行一次全量复制,正常情况都是进行增量复制(只复制主机中新增加的数据)
- Redis层层链路一个主机可以同时作为主机和从机(主属性还是从机,不能写)
- 如果主机宕机了,可以手动使用slaveof no one让自己变成主机(手动太麻烦,后面引入哨兵模式)
九、哨兵模式(主机宕机后,自动选择主机)
- 哨兵是独立的进程,用于监控每个reids服务器是否正常运行。如果发现主机宕机后,就会选择一个新的主机,然后通过发布订阅模式通知其他的从机让他们切换主机
- 多哨兵模式:哨兵也可能宕机,所以一般也有多个哨兵,当一个哨兵认为主机服务器不可用时,成为主观下线。当发现主机不可用的哨兵到达一定值时,就会进行failover故障转移操作,通过投票选择一个新的主机。
- 最简单的单哨兵模式配置:
- 首先新建哨兵配置文件sentinel.conf,
- 加入内容:sentinel monitor myredis 127.0.0.1 6379 1(myredis表示名称可以随便取,127.0.0.1 6379表示监控的主机,1表示1个哨兵发现主机挂了就投票选新的主机)
- 启动哨兵模式:redis-sentinel kconfig/sentinel.conf
- 优点:主从复制的优点他都有,自动切换主机更加健壮。
- 缺点:redis不好在线扩容。多哨兵配置麻烦。
十、Redis缓存穿透
- 定义:在缓存中查不到,数据库也查不到,大量请求都在持久层数据库时,就造成了缓存穿透。
- 解决方案:
a) 布隆过滤器:一种数据结构,对所有可能查询的参数以hash形象存储,当查询时,在控制层先进行校验,过滤不符合的查询请求。
b) 缓存空对象:持久层数据库查不到时,将返回的空对象也缓存起来,并设置一个过期时间,后面查询这个值时,就会在缓存中获取了,减少持久层数据库的压力(数据一致性有影响)
十一、Redis缓存击穿
- 定义:在某个热点key过期的瞬间,大量该值的请求在缓存中查不到,都会涌入数据库。
- 解决方案:
a) 热点词不过期。
b) 加互斥锁:使用分布式锁,对每个key同时只有一个线程去查询,其他该key的查询等待。
十二、Redis缓存雪崩
- 定义:在某个时间段,缓存集中过期,或者reids宕机。
- 解决方案:
a) redis高可用(多台redis集群)、
b) 加互斥锁:使用分布式锁,对每个key同时只有一个线程去查询,其他该key的查询等待
c) 数据预热:正式部署前,将可能大量访问的数据先访问一边,让它加载到缓存中去。