Redis概述

文章目录

        • NoSQL概述
        • Redis概述
        • Redis优势
        • 关系型数据库与非关系型数据库
        • Redis数据类型
          • 5种基本常用类型
          • 6种底层数据结构
          • 全局哈希表
          • String
          • Hash
          • List
          • Set(集合)
          • Zset(sorted set:有序集合)
          • 设置失效时间
        • Redis相关问题
          • Redis是单线程还是多线程
          • 为什么设计为单线程模型速度也很快
          • Redis持久化
          • Redis事务
          • 主从复制
          • 哨兵机制
          • key的过期策略
          • 缓存穿透、缓存击穿、缓存雪崩
          • 总结


在这里插入图片描述

NoSQL概述

NoSQL,Not Only SQL 泛指非关系型数据库(关系型数据库是指使用标准SQL语言进行操作),以键值对的形式储存,与关系型数据库是相辅相成的。

具有以下优点:

易扩展:数据与数据之间没有关系

高性能:NoSQL数据库都具有非常高的读写性能,尤其是在大数据下同样表现优秀,得益于他的无关性和结构简单

灵活的数据模型:无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。

Redis概述

Redis(Remote Dictionary Server),即远程字典服务,是一个开源的,用C语言编写的,支持网络交互的,以key-value数据结构存储,支持多种语言,可以作为数据库、缓存和消息的中间件。

主要用来做数据的缓存(让数据离程序更近),Redis运行在内存中,数据也保存在内存中。

Redis及其他key-value缓存产品的特点:

  1. 支持数据持久化,可将内存中的数据保存到硬盘上,重启时再加载进内存使用
  2. 不仅仅支持简单的key-value类型的数据,同时还提供list、set、zset、hash等数据结构的存储。
  3. Redis支持数据备份,即master-slave模式的数据备份。

Redis优势

  1. 性能极高——Redis读的速度是110000次/s,写的速度是81000次/s。
  2. 丰富的数据类型——Redis支持二进制案例String,List,Hashes,Sets及Ordered Sets。
  3. 原子——Redis的所有操作都是原子性的,
  4. 丰富的特性——Redis还支持publish/subscribe,通知,key过期等等特性。

关系型数据库与非关系型数据库

关系型数据库:

采用关系模型来组织数据,关系模型就是二维表格的模型。一张二维表的表名就是关系,二维表的一行就是一条记录,二维表中的一列就是一个字段。

优点:

容易理解,使用方便,通用的sql语言,易于维护,丰富的完整性(实体完整性,参照完整性和用户定义的完整性)大大降低了数据冗余和数据不一致的概率缺点

缺点:

  1. 磁盘IO是并非瓶颈;
  2. 海量数据查询效率低;
  3. 横向扩展困难,无法简单的通过添加硬件和服务节点来扩展性能和负载能力,当需要对数据库进行升级和扩展时,需要停机维护和数据迁移
  4. 多表的关联查询以及复杂的数据分析类型的sql查询,性能欠佳,因为要保证ACID

非关系型数据库:

分布式,一般不保证ACID原则的数据存储系统。键值对存储,结构不固定。

优点:结构简单易扩展,高性能,灵活的数据类型

缺点:适合放一些简单的数据,不适合放时间太久太多的数据

Redis数据类型

键都是String类型

5种基本常用类型

String(字符串),List(列表), Hash(哈希),set(集合), zset(有序集合)

6种底层数据结构

简单动态字符串(string),双向链表(list),压缩列表(list hash zset),哈希表(hash set),跳表(zset),整数数组(set)

全局哈希表

底层是hash结构,可以通过key计算出位置,将key-value都存在此位置,也可以存其他类型;

hash冲突问题:提供两块内存空间,将原来的映射渐进式的复制到扩容后的hash表中,然后释放之前的空间

String

是二进制安全的可以包含任何数据,比如jpg图片或序列化对象,最大能存储512MB

单值缓存:比如 phone:13392039203

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

hash特别适合用于存储对象(对对象中数据发生修改的情况),存的是字符串和字符串值之间的映射,比如要存储用户购物车等信息。

hset key field value 存储一个哈希表的键值

hmset key field value [field value……] 存储多个键值对

hget key field 获取

hmget key field [field……] 获取多个

hdel key field [field……] 删除

hlen key 返回哈希表key中的field的数量

hgetall 返回哈希表key中所有的键值

hincrby key field 增加值(负数时,减少)

电商购物车
1)以用户 id 为 key
2)商品 id 为 field
3)商品数量为 value
购物车操作
1)添加商品→hset cart:1001 10088 1
2)增加数量→hincrby cart:1001 10088 1
3)商品总数→hlen cart:1001
4)删除商品→hdel cart:1001 10088
5)获取购物车所有商品→hgetall cart:1001

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(从1开始)

使用场景:可以用来存储接收到的消息数据.

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)却可以重复。
zadd key score member[[score member]…] 往有序集合 key 中加入带分值元

zrem key member[member…] 从有序集合 key 中删除元素
zscore key member 返回有序集合 key 中元素 member 的分值
zincrby key increment member 为有序集合 key 中元素 member 的分值
加上 increment
zcard key 返回有序集合 key 中元素个数
zrange key start stop[withscores] 正序获取有序集合 keyastart 下标到 stop
下标的元素(从0开始)
使用场景:记录微信朋友圈记录点赞用户

设置失效时间

有时候我们并不希望Redis的key一直存在,例如缓存,验证码等数据,Redis提供了一些命令,能够让我们对key设置过期时间,并且让key过期后自动删除。

EX表示以秒为单位;PX表示以毫秒为单位;不区分大小写

ttl 键 查看剩余多少秒

pttl 键 查看剩余多少毫秒

举例:可以直接 set name jim ex 30

也可设置值后设置有效时间:expire name 30(秒)

pexpire name 30 000(毫秒)

Redis相关问题

Redis是单线程还是多线程

Redis6.x之前是真正意义上的单线程,处理客户端的连接和执行操作命令都是由一个线程完成的;Redis6.x引入了多线程,处理客户端的请求由专门线程处理,执行操作命令仍然是单线程。

为什么设计为单线程模型速度也很快
  1. 因为Redis数据存储在内存中,读取速度快,查找和操作的时间复杂度都是O(1),cpu不是其瓶颈
  2. 数据结构简单,以k-v存储,底层是哈希结构,查询速度是O(1)
  3. 单线程执行命令,不存在线程切换节省开销且线程安全
  4. 采用IO多路复用,非阻塞IO模型,提高了连接访问效率
Redis持久化

Redis数据是存储在内存中的,内存中数据是临时保存,Redis是支持将数据持久化到硬盘的。Redis为我们提供了两种持久化的机制,分别是RDB(Redis DataBase)和AOF(Append Only File);这两种方式都可以在redis.conf中进行配置,默认使用的是RDB方式

RDB方式:直接将内存中的数据快照(k-v)存储起来;触发持久化的机制:

  1. save m n 表示m秒内至少n个键被修改则进行快照
  2. 执行flushall命令
  3. 退出执行 shutdown save命令

备份就会自动生成一个dump.rdb文件

AOF方式:以日志的形式,将写命令存储到文件中,还原时,将命令逐个执行还原数据

默认不开启: appendonly no 改为yes开启

同步机制:appendsync always 每set一次记录一次;appendsync everysec 每一秒记录一次(可能丢失一秒数据)

重启redis生效

Redis事务

Redis在执行单挑命令时,是原子性的(单线程一次只能有一个线程执行命令)

有时候,一次操作需要执行多条命令,可以通过redis事务来实现多条命令的整体执行

  1. 开启事务 :multi
  2. 添加命令:命令并没有立即执行,而是添加到队列中等待执行
  3. 执行exec命令:依次执行队列中的命令,执行时其他客户端会被隔离,不会交替执行,但其并不保证多条命令执行的原子性(假如三条命令,第一个执行出错,其余两个仍旧会执行)
主从复制

主从是指主机和从机,是集群架构;如果只用一个redis,万一其意外宕机,所有请求都会到达MySQL,导致MySQL宕机;这时可以搭建多台redis服务器,万一其中有故障出现,其余的redis服务还可以正常使用

主机负责写数据,将数据同步到从机,一般的读数据从从机查询,实现了读写的分离,即写命令由主机执行,读命令由从机执行

作用:

  1. 数据冗余:数据热备份
  2. 故障恢复:主机故障时,从机提供服务,是一种服务的冗余
  3. 负载均衡:读写分离,尤其是写少读多的情况下,可以大大提高redis的服务器并发量
  4. 高可用(集群)基石:是哨兵和集群能够实施的基础
哨兵机制

哨兵(sentinel)有一个单独的线程,对集群中的多台服务器进行监听,给每个服务器发请求,如果没有响应,表名出现了故障,当主机意外宕机时,会从从机中选取一个当做主机,当原主机恢复后又作为主机继续使用;哨兵也可集群,除了监控各个redis服务外,哨兵之间也可互相监控

key的过期策略

为key设置过期时间当时间到了之后有以下三种策略可选:

  1. 立即删除:到期时立即执行回调函数立即释放空间,影响redis的性能
  2. 惰性删除:到期后不会立即删除,到下次使用时,根据状态,来决定是否删除,占用内存
  3. 定期删除:每隔一段时间,对所有到期的key进行删除
缓存穿透、缓存击穿、缓存雪崩

查询数据流程:查询数据是否在redis中,在就返回,不在去数据库查询,然后将数据添加至redis并返回

缓存穿透:查询的数据在数据库中没有,在Redis中也没有,每次还是会去访问数据库

解决办法:

  1. 本来数据库没有将查出来的空值放在redis中
  2. 对查询参数进行验证

缓存击穿:数据库中有数据,只是某个热点key在某个时间点上过期了,此时有大量请求到达,查询缓存没有,一起都向数据库发请求,导致数据库崩溃

解决办法:

  1. 合理设置key的过期时间
  2. 查询缓存没有,查询数据库时加锁

缓存雪崩:大量的热点key过期或redis服务器故障,导致大量请求到达数据库,导致数据库崩溃

解决办法:

  1. 随机设置有效时间,避免集体失效
  2. 不同热点key放在不同的redis服务上
  3. 设置较长过期时间
  4. 在Java中可以设置定时任务去检测key是否过期
总结

雪崩是大面积的key缓存失效,穿透是redis里面不存在这个缓存key,击穿是redis某个热点key突然失效,最终的受害者都是数据库

对于“redis宕机,请求全部走数据库”这种情况我们可以有以下的思路:

  1. 事发前:实现redis的高可用(主从复制+Sentinel(哨兵)),尽量避免redis挂掉这种情况发生
  2. 事发中:设置本地缓存+限流,尽量避免我们的数据库被干掉(最起码保证数据库还能工作)
  3. 事发后:redis持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据

你可能感兴趣的:(Java,redis,数据库,缓存)