文章目录
NOSQL(Not Only SQL)
NoSQL泛指非关系型数据库,区别于关系型数据库(使用标准的sql语言进行操作)
关系型数据库&非关系型数据库
优点: 易扩展、高性能、灵活的数据模型
关系型数据库:
采用关系模型组织数据的数据库
优点:
- 容易理解
- 易于维护,其完整性大大降低了数据冗余和数据不一致的概率缺点
缺点:
- IO瓶颈
- 海量数据查询效率低
- 横向扩展困难,无法简单的通过添加硬件和服务节点来扩展性能和负载能力
非关系型数据库:
非关系型,分布式,一般不保证遵循 ACID 原则的数据存储系统。键值对存储,结构不固定
优点:
- 结构简单易扩展
- 高性能
- 数据模型灵活
缺点:
- 存储简单数据
- 不适合复杂查询数据
Redis是什么
是一个开源的,使用C语言编写;是键值对存储在内存中,也可以存储在硬盘上,存储结构简单、性能高、易于扩展、支持多语言、保证操作原子性、支持多种数据类型
redis主要用来做数据缓存,数据也保存在内存中,一般将redis称为中间件
Redis数据类型
redis是以键值对进行存储的,键都是String
五种基本常用类型
redis支持多种类型的数据类型,五种数据类型指的是String(字符串)、Hash(哈希)、List(列表)、Set、Zset(有序)
底层数据结构6种
简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组
全局哈希表:
底层结构是hash结构,可以通过key值计算出位置,将key-value都存储在此位置
-
哈希冲突问题:
提供两块内存空间,相当于扩容,将原来的映射渐进式的复制到扩容的哈希表中,然后释放之间的空间
String(字符串)
String是redis最基本的类型,一个key对应value
单值缓存
例:
- set key value
- get key
- del key
对象缓存(不对对象中数据操作时可以使用)
set user : 1 value(json格式数据)
计数器
例:
- set news_views : 1 0 设置文章访问量
- incr news_views : 1 文章访问量+1
- decr news_views : 1 文章访问量-1
- get news_views : 1 获得值
Web集群session共享
session + redis 实现 session 共享
Hash(哈希)
redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象(对对象中的数据发生修改情况)。 存的是字符串和字符串值之间的映射,比如要存储用户购物车等信息
- hset key 属性 值 存储一个哈希表key的键值。
- hmset key 属性1 值1 属性2 值2
- hmget key 属性1 属性2
- hdel key 属性 获取哈希表key对应的属性键值
- hlen key 返回哈希表key中的属性的数量
- hgetall key 返回哈希表key 中所用的键值
- hincrby key 属性 增加的值(减少给负数)
List(列表)
Redis列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或尾部(右边)
- lpush key value[value…] 将一个或多个值插入到 key 列表的表头(最左边)
- rpush key value[value…] 将一个或多个值插入到 key 列表的表尾(最右边)
- lpop key 移除并返回 key 列表的头元素
- rpop key 移除并返回 key 列表的尾元素
- lrange key start stop 返回列表key中指定区间内的元素,区间以偏移量start和 stop
Set(集合)
Redis的Set是无序集合
- sadd key member[member…] 往集合 key 中存入元素,元素存在则忽略,若 key 不存在则新建
- srem key member[member…] 从集合 key 中删除元素
- smembers key 获取集合 key 中所有元素
- scard key 获取集合 key 的元素个数
Zset(sorted set :有序集合)
redis zset 也是不允许重复的成员,但是是有序的。不同的是每个元素都会关联一个double类型的分数,而redis正是通过这样的分数来为集合中的成员进行从小到大的排序
zset的成员是唯一的,但是分数(score)是可以重复的
Redis线程模型
redis是单线程模式还是多线程模式?
不同的版本有区别:
6.x之前是是真正意义上的单线程:处理客户端的连接和执行操作的命令,都是由一个线程来完成的
6.x之后引入多线程:处理客户端请求是由专门的线程处理,执行命令还是单线程
为什么设计为单线程模式,速度还非常快?
- 数据存储在内存中,读取速度快,CPU不是性能瓶颈
- 结构简单,key-value底层是哈希结构,查询速度是O(1)
- 采用IO多路复用,非阻塞IO模型,提高连接访问效率
- 单线程执行命令,不存在线程切换,节省开销,而且是线程安全的
Redis持久化
IO对象持久化,对象序列化,对象信息持久保存到硬盘上
mybatis是一个Java的数据持久层款框架
redis数据是存储在内存中,内存数据是临时保存的
redis支持将数据持久化到硬盘
redis是如何进行数据持久化的?
RDB和AOF(这两种方式都在redis.conf文件可配置)
redis默认使用RDB方式
RDB: 直接将内存的数据快照(key-value)存储起来
配置触发持久化的机制:
- save m n save 多少秒内 多少键
- flushall 命令,也会触发rdb 规则
- 退出redis,也会产生rdb文件
备份自动生成一个 dump.rdb.
关机后下次启动 redis 会自动将文件中的数据还原到内存中.
优点:
1.适合大规模的数据恢复!
2.对数据的完整性要不高!
缺点:
需要一定的时间间隔进程操作!如果 redis 意外宕机了,这个最后一次修改数据就没有了
AOF方式
以日志的形式,将写命令存储到文件,还原时,将命令逐个执行还原数据
开启方式
AOF机制默认是不开启的
修改 redis.conf 配置文件,开启 AOF 机制
appendon1y no #默认是不开启 aof 模式的,改为 yes 开启.
appendfilename appendonly.aof #默认的文件名是 appendonly.aof,可
以通过 appendfilename 参数修改
AOF 同步机制
appendfsync always #每次修改都会 sync。消耗性能
appendfsync everysec #每秒执行一次 sync,可能会丢失这 1s 的数据(默认)
重启 redis 生效
Redis事务
redis在执行单条命令时,是原子性(单线程的,一次只能有一个线程执行命令),有时候,一次操作需要执行多条命令
如何保证多条命令整体执行?
可以通过redis事务实现:
开启事务:multi
添加命令:命令添加进来不会立即执行,添加到一个多列
执行exec命令时,才会将队列中的多条命令依次执行,执行一个事务中多条命令时,其他客户端会被隔离,不会交替执行,但是事务不保证多条命令执行的原子性(假如执行3条命令,其中有一条语法出错了,那么会将其他两条正确继续执行)
redis 的事务:
- 开启事务(multi)
- 命令入队(…)
- 执行事务(exec)
- 放弃事务(discard)
主从复制
主从–>主机和从机—集群架构
为什么用集群?
如果只有一台redis服务,万一服务宕机,所有的请求都会到达MySQL,导致MySQL宕机,可以搭建多台redis服务器,如果其中一台出现故障,其他服务也可以正常使用
哨兵机制
有一个单独线程,对集群中的多态服务进行监听,给每个服务发请求,如果没有响应,表明出现故障,比如主机宕机,会在从机选取一台当做主机,当原来主机恢复后,又可以当做主机继续使用。
key的过期策略
为key设置过期时间,那么时间到了后,redis如何处理过期的key?
- 立即删除,到期立即执行回调函数,立即释放内存,对redis性能有影响
- 惰性删除,根据状态(设置时会有记录)来决定是删除还是继续使用占用内存
- 定期删除,每隔一段时间对所有到期的键进行删除(类似于Java的垃圾回收线程)
缓存穿透、缓存击穿、缓存雪崩
缓存处理流程
前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,
数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。
缓存穿透
所有查询的数据,在数据库中没有查询后,也不在缓存中存储,请求都会到数据库,从而可能压垮数据库。
比如用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库
数据库没有,缓存没有
解决办法:
- 本来数据库没有,将查询出来的空值放到缓冲中
- 对查询的参数进行验证
缓存击穿
数据库有数据,只是某个热点key在某个时间点上过期了,此时有大量查询请求到达(查询是不加锁),这些请求发现缓存过期,一起都向数据库发起请求,导致数据库崩溃
解决办法:
- 热点数据设置永不过期
- 查询缓存没有后,访问数据库时可以加锁(互斥锁)
缓存雪崩
大量的热点key过期,或者redis服务故障,大量的请求到达数据库
解决办法:
- 随机设置有效时间,避免集体失效
- 把不同的热点key放在不同的redis服务上(集群)
- 不设置过期时间
- 在Java中设置定时任务去检测key是否过期