Redis-涵盖大部分知识

Redis 简介

概念:Redis是用基于C语言开发的一个开源的高性能键值对(Key-value)数据库。

特征:

  1. 数据之间没有必然的关联关系
  2. 内部采用单线程机制进行工作
  3. 高性能。50个并发执行十万个请求,读的速度是11万次/秒,写的速度是8.1万次/秒
  4. 多数据类型支持
    • 字符串类型 string 类似 String
    • 列表类型 list 类似LinkedList
    • 散列类型 hash 类似HashMap
    • 集合类型 set 类似HashSet
    • 有序集合类型 sorted_set 类似 TreeSet
  5. 支持持久化,不能老在内存中存着吧,断电了怎么办,所以支持持久化,还可以进行数据灾难恢复。

Redis 的使用场景

  • 热点数据缓存

  • 任务队列,比如秒杀、抢购、排队购票

  • 即使信息查询,比如排行榜、网站访问量统计、公交到站信息、聊天室或网站的在线人数信息、设备信号

  • 时效性信息,比如验证码的有效时间

  • 分布式数据共享,比如分布式集群架构中的session分离

  • 消息队列

  • 分布式锁

Redis常用的数据类型

先说一下redis的数据存储格式

redis自身是一个Map,所有的数据都是使用key:value的形式存储,而我们说的数据类型是值value的类型,key的类型永远都是字符串。

image-20210409202024012

字符串类型 string

基本操作

set key value	添加、修改数据
get key		获取数据
del key		删除数据
mset key1 value1 key2 value2..	添加/修改多个数据
mget key1 key2...	获取多个数据
strlen key 		获取数据字符串长度
append key value	追加信息到原始信息后面。如果不存在则新建

set 和 mset 该怎么选择?

set就是一次向redis服务器发送一条数据,mset就是一次性向redis服务器发送多条数据,所以发送数据的时候要考虑发送的时长的服务器处理的时长,如果一条数据非常大,发送的时长也非常长,那么无疑选择将大数据分割成一条条的小数据比较合适,具体的选择还需要通过实际测试对比一下才能做出选择。

string类型的扩展操作

  1. 设置数据按照指定范围增加或者减少。
incr key   // 让key对应的value加1
incrby key increment  // 让key对应的value加increment
incrbyfloat key increment   // 让key对应的value加一个小数
decr key
decrby key increment

string在redis内部存储默认就是一个字符串,但是遇到incr decr操作的时候会转换成数值进行加减操作。

在大型企业级应用中,分表操作是常见的,也就是使用多张表存储同类型的数据,但是对应的主键id必须保证唯一性,不能重复。因此,redis可以用于控制数据表的主键id,位数据库表主键提供生成策略,保障数据库表的主键唯一性。

**注意:**按照数值进行数据的操作的时候,如果原始数据不能转换成数值或者超越了redis数值上限的范围,将报错,上限的范围和Java中的long类型一样,Long.MAX_VALUE

  1. 设置数据具有指定的生命周期

redis控制数据的生命周期,通过数据是否失效控制业务行为。

setex key seconds value  例如:setex tel 10 17803831111  则tel在10秒后就没了
psetex key milliseconds value

string类型数据操作的注意事项

  • 数据为获取到

    nil 等同于null

  • 数据最大存储量

    512MB

string类型的业务场景案例

主页高频访问信息显示的控制,例如微博大V主页显示粉丝量与微博数量。

解决方案:在redis中为大V用户设定用户信息,以用户主键和属性值作为key,后台设定定时刷新策略即可

粉丝数: user:id:11211200:fans    --> 1000000
博客数: user:id:11211200:blogs   --> 2000
关注数: user:id:11211200:focuss  --> 88

也可以使用json的格式存储,但是更改的时候需要先拿出来,比较麻烦

key的命名约定

数据库中的热点数据key命名惯例

表名:主键名:主键值:字段名

列表类型 list

image-20210409215847674

操作具有先后顺序的数据

散列类型 hash

存储结构

image-20210409211042144 image-20210409211308421

一个key对应一堆数据,其底层使用的是哈希表结构

hash存储结构会自动优化:field少的时候,存储结构优化为类似数组结构;field多的时候,优化为hashmap结构

为什么需要hash类型?

  • 新的存储需求

    对一系列存储的数据进行编组,方便管理,可以应用于存储对象信息

  • 需要的存储结构

    一个存储空间可以保存多个键值对数据

基本操作

hset key field value	添加/修改hash的某个field值
hget key field			获取hash的某个field的值
hgetall key				获取key对应的hash结构的所有field值
hdel key field1 [field2] 删除数据
hmset key field1 value1 [field2 value2] 添加/修改多个数据
hmget key field1 field2	获取多个数据
hlen key	获取哈希表中字段的数量
hexists key field 哈希表中是否存在指定的字段

image-20210409212115619image-20210409212249430

注意事项

  • hash类型下的value只能存储字符串,不能存储其他类型,不能存在嵌套。
  • 每个hash可以存储2^32 -1 个键值对
  • hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但是hash的初衷不是为了存储大量对象,不能说hash就是为了存对象用的

集合类型 set

set类型

存储大量的数据,高效的内部存储机制,在查询方面提供更高的效率

image-20210410093640015

其实就是基于hash的结构

支持随机获取集合中指定数量的数据

适用于随机推荐类信息检索

求交集、并集、差集

有序集合类型 sorted_set(zset)

image-20210410100017025

各个数据类型使用场景总结

string

  • 与计数相关热点数据,微博中明星的粉丝数量

hash

  • 存储对象
  • 存储购物车

list:应用于具有先后操作顺序的数据控制

  • 微信朋友圈的点赞,按照点赞的顺序显示点赞好友的信息
  • 按照关注的顺序显示出粉丝
  • 最新消息的显示

set

  • 可以随机获取数据,可应用于随机推荐信息
  • set可以求交集、差集、并集,可用于实现共同关注、共同好友
  • 统计网站的PV(访问量)、UV(独立访客)、IP(独立IP)

zset

  • 与排名相关的功能,比如电影热榜前十名

高级数据类型

Bitmaps

该数据类型存放的实际上就是字符串,但是它可以实现对位的操作。可以把Bitmaps想象成一个以位为单位的数组,每个数组的单元只能存储0或者1,数组的下标在Bitmaps中叫做偏移量。

该类型常应用信息状态统计

HyperLoglog

用来统计基数的个数。基数:数据集去重后的元素个数。

该数据类型不保存具体数据,只是记录数量,占用空间很小,最大只有12KB

GEO

GEO用于地理位置的计算

Redis持久化

什么是redis的持久化?

将redis中的数据保存在磁盘上,然后在特定的时间将保存的数据进行恢复的工作机制就是持久化

为什么要进行持久化?

防止数据的意外丢失,确保数据的安全性

持久化过程保存什么?

在redis中的持久化有两种形式:

  • 将当前数据状态以快照的形式保存,存储格式简单,关注点主要在数据。(RDB
  • 将数据的操作过程以日志的形式保存,存储格式复杂,关注点主要在数据的操作过程(AOF

RDB

存储到硬盘

1.手动保存

命令:save 每执行一次就会保存一次当前数据的快照信息

注意:redis是单线程的,当多个客户端并发向客户端发送指令的时候,会按照多个指定的到达顺序装进任务执行队列,当执行到save指令的时候,save指令的执行会阻塞当前redis服务器,直到但其概念RDB过程完成为止,如果数据量过大有可能会造成长时间阻塞,线上环境不建议使用。

**解决方案:**使用bgsave指令让其在后台执行保存操作,不是立即执行,会在合理的时间进行执行,不用我们管。

实现原理是:redis客户端向服务器发送bgsave指令的时候,服务器给客户端返回一条后台保存开启的消息并且服务器会调用fork()函数生成一个子进程,让子进程去执行后台保存操作,子进程执行结束后向服务器发送执行完毕的消息,可以在日志文件中查看到该消息。

因此,bgsave是针对save的阻塞问题做的优化

2.自动保存

save second changes 注意该操作在后台执行的是bgsave指令

在指定时间范围内key的变化次数达到指定数量即进行持久化。 在配置文件中配置就行

例如 save 60 10 :在60秒内发生了10次变化就进行持久化,如果到达了时间,没有变化那么多次,就重新计时

RDB启动方式对比

方式savebgsave
读写同步异步
阻塞客户端指令
额外内存消耗
启动新线程

RBD优缺点

优点:

  • RDB存储的是紧凑的二进制压缩文件,存储效率较高
  • 内部存储的是redis在某个时间点的数据快照,适用于数据备份、全量复制等场景
  • RDB恢复数据要比AOF快

缺点:

  • 无法做到实时持久化,很可能丢失数据,也就是宕机带来的数据丢失风险
  • bgsave要创建子进程,所以会牺牲性能
  • redis的各个版本中RDB文件格式不统一,可能存在各个版本间数据不兼容的现象
  • 存储数据量大的时候,效率会比较低

恢复到内存

启动的时候自动恢复到内存

AOF

AOF持久化:以独立日志的方式记录每次的命令,重启时再重新执行AOF文件中的命令恢复数据。与RDB相比,就是改记录数据为记录数据产生的过程。

AOF的主要作用是可以做到数据持久化的实时性,目前已经是Redis持久化的主流方式

AOF写数据的三种策略

  • always(每次)

    每次执行完写入操作都要同步到AOF文件中,数据零误差,性能较低,不建议使用

  • everysec(每秒)

    每秒将AOF缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高,建议使用,也是默认配置

  • no(系统控制)

    由操作系统控制每次同步到AOF文件的周期,整体过程不可控

Redis事务

Redis中的事务是什么?

redis中的事务就是将一系列的命令放进一个队列中,这个队列中的命令会按照顺序执行,在执行的过程中不会被打断或干扰。

事务的基本操作

  • 开启事务:multi
  • 执行事务:exec

开启事务之后输入的命令都不会立即执行,会先添加到队列中,当收到exec命令的时候才按照添加的顺序执行

使用watch对某个key加锁,在执行exec之前如果该key的值发生的变化,将终止事务的执行

Redis的删除策略

##数据删除策略

数据删除策略的目标是:**在内存占用和CPU占用之间寻找一种平衡。**因为这两者无论哪一个走极端都会造成redis性能的下降。

定时删除

创建一个定时器,由定时任务对到达过期时间的key执行删除操作。

优点:能够及时删除过期的key,释放内存

**缺点:**如果CPU很忙的时候有key过期,CPU也得立马去执行删除操作,增大了CPU的压力

这是一种以时间换空间的方式。

惰性删除

如果有key过期,不做处理。放下次访问redis中的数据时,如果该key没过期,直接返回;如果该key过期了,则删除该key,返回不存在该数据。

**优点:**减轻了CPU压力,等到发现必须删除的时候才会删除。

**缺点:**增大了内存占用

这是一种以空间换时间的方式。

定期删除

以上两种方式,都各有弊端,定期删除是一种折中的方式。

每隔一段时间,对数据库进行一次检查,删除过期键,由具体的算法决定删除多少过期键和检查多少数据库

注意:

如果删除太频繁会退化成定时删除,删除次数太少会退化成惰性删除。

##逐出算法(策略)

当redis中有新数据进来,如果内存不足,就要清理掉部分数据腾出内存,具体要清理掉那些数据就是由逐出算法决定。

列举八种数据逐出策略

  • 检测易失数据
  1. volatile-LRU : 挑选最近最久使用的数据淘汰
  2. volatile-LFU:挑选最近使用次数最少的数据淘汰
  3. volatile-TTL:挑选将要过期的数据淘汰
  4. volatile-random:选择任意数据淘汰
  • 检索全库数据
  1. allkeys-LRU: 挑选最近最久未使用的数据淘汰

  2. allkeys-LFU:挑选最近使用次数最少的数据淘汰

  3. allkeys-random:任意选择数据淘汰

  • 放弃数据驱逐
  1. no-enviction:禁止逐出数据(redis4.0中的默认策略),引发错误OOM

主从复制

简介

首先说一下互联网的“三高”架构:

  • 高并发
  • 高性能
  • 高可用

单机的Redis存在的风险与问题:机器故障、容量瓶颈。为了避免这些问题,就需要准备多态服务器,互相连通,将数据复制多个副本保存在不同的服务器上,连接在一起,并且保证数据是同步的。这样即使有一台服务器宕机了,还可以有其他机器支撑,继续提供服务,从而实现redis的高可用,同时实现数据的冗余备份

这时候就要用到主从复制将主服务器中的数据及时有效地复制到slave中

  • 主服务器(master):提供数据。职责:负责写数据,并将发生变化的数据自动同步到从服务器中
  • 从服务器(slave):接收数据。职责:负责读数据

将master中的数据复制到slave中。

主从复制的作用

  • 读写分离:主服务器写,从服务器读,提高服务器的读写负载能力
  • 负载均衡:slave分担master的负载,并根据需求的变化,改变slave的数量,大大提高redis服务器的并发量和数据吞吐量
  • 故障恢复:当master出现问题时,由slave服务器提供服务,实现快速的故障恢复
  • 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
  • 高可用基石:基于主从复制,构建哨兵模式集群,实现redis的高可用方案

主从复制工作流程

大体上可分为三个阶段:建立连接阶段(准备阶段)、数据同步阶段、命令传播阶段

image-20210412200232461

image-20210412200243714

阶段一 :建立连接阶段

建立slave到maser的连接,使master能够识别slave,并且保存slave端口号。

image-20210412201044558

阶段二:数据同步阶段

在slave初次连接到master后,会将master中的所有数据复制到slave(全量复制)

将slave的redis数据库状态更新成master当前的数据库状态(数据恢复)

image-20210412201329337

阶段三:命令传播阶段

当master数据库数据发生改变的时候,需要将这种改变同步到slave数据库,同步的动作就是命令传播。

master数据更改的命令发送给slave,slave接收到命令后执行命令

哨兵模式

哨兵模式简介

哨兵(sentinel)是一个分布式系统, 用于对主从结构中的每台服务器进行监控,当出现故障的时候,通过投票机制选择新的master并将所有slave连接到新的master。

哨兵的作用

也是哨兵在进行主从切换的过程中经历的三个阶段:

  • 监控

    不断检查master和slave是否正常运行

  • 通知(提醒)

    当被监控的服务器出现问题的时候,向客户端发出通知

  • 自动故障转移

    master出问题的时候,选取一个slave作为新的master,将其他slave连接到新的master,并告知客户端新的master的地址

注意:哨兵也是一台redis服务器,只是不提供数据服务而已。通常哨兵的数量是单数

Redis集群

集群的概念

集群就是使用网络将多个计算机连接起来,并统一管理提供服务,对外呈现出单机的效果。

image-20210412202538448

集群的作用

  • 分散访问压力,实现负载均衡
  • 分散存储压力,实现可扩展性
  • 降低单台服务器宕机时带来的业务灾难

集群下的数据存储

  • 通过特定算法,计算出key的存放位置
  • 将所有的存储空间分割成16384分,每台主机保存一部分。其中每份代表一个存储空间,并不是一个key的保存空间
  • 将key按照计算出的结果放到对应的存储空间

集群内部的通信

各个数据库相互通信,保存各个库中槽的编号,查询的时候若能够一次命中则直接返回,一次未命中的时候,会告知该key存放的位置,再次查找。

问题解决方案

缓存预热

针对现象

服务器启动后迅速宕机

问题排查

  • 请求数量较多
  • 主从数据库之间数据吞吐量较大,数据同步操作频率较高

解决

缓存预热:在系统启动之前,提前将相关的缓存数据加载到缓存系统,避免在用户请求到来的时候先查询数据库再将数据缓存的问题,让用户直接查询事先缓存好的数据。

缓存雪崩

缓存雪崩就是大量的数据瞬间过期,导致对数据库服务器造成压力。如果能将过期的时间错开,可以有效并避免这个问题。

解决:

  1. 避免对大量的key设置相近的失效期
  2. 超热数据使用永久key
  3. 加锁

缓存击穿

缓存击穿就是单个数据过期的瞬间,对该数据由大量的请求,由于无法再redis命中,所有向数据库发起了对该数据的大量请求,对数据库造成压力。

解决:

  1. 加锁
  2. 设置永久key

缓存穿透

缓存穿透就是访问不存在的数据,每次都不经过redis直接访问数据库,对数据库造成压力,另外由于缓存一直不命中,也失去了缓存的意义。

解决

  1. 由于查询的是不存在的数据,所以会返回null,我们将返回的null也进行缓存,有效时间设置短一点就好了。

  2. 白名单策略

    • 提前把分类数据id映射到bitmaps,id作为bitmaps的offset,相当于设置了数据白名单,当加载正常数据的时候就放行,加载异常数据的时候就拦截。不过这种方式效率比较低
    • 使用布隆过滤器(下面有介绍什么是布隆过滤器),将数据库中所有的查询条件放入缓存数据库中,当一个请求过来时,先经过布隆过滤器进行筛查,如果判断请求查询的值可能存在,则继续查;如果判断请求的查询值一定不存在,则直接拦截。

扩展:布隆过滤器

什么是布隆过滤器?

布隆过滤器是由一个很长的bit数组一组哈希映射函数组成,可以用于检索一个元素是否一定不在集合中或者可能在集合中。

布隆过滤器的原理?

布隆过滤器是一个bit数组,如果我们向把一个key映射到布隆过滤器中,就利用所有的哈希函数对这个key进行映射得到一系列的哈希值,将哈希值当成数组的下标,把下标对应的数组元素置为1。那么当判断一个key是否在bit数组中的时候,就判断以该key经过哈希函数映射的哈希值为下标的元素是不是都为1,如果都为1,那么该key可能在集合中;如果有任何一个不为1,那么该key一定不在该集合中。

为什么全部为1,可能在集合中?

因为经过哈希映射是可能存在哈希冲突的,在发生哈希冲突的时候,如果刚好所有的映射值都被设置为了1,就会影响判断结果,这也是布隆过滤器的一个缺点,为了做到时间和空间上的高效率,布隆过滤器选择牺牲一点准确率。还有一个缺点是,布隆过滤器的删除比较困难,如果要删除一个key的映射,不能简单的把该key哈希值对应位置上的元素置为0,因为要删除的这个key可能会和其他key发生了哈希冲突,另外的key也映射到了该位置,那么直接置为0的话就会影响其他key的判断。

其他应用场景:

  • Google Chrome 使用布隆过滤器识别恶意 URL
  • 使用布隆过滤器避免推荐给用户已经读过的文章/视频
  • 爬虫过滤已抓到的url就不再抓,可用bloom filter过滤
    bit数组一组哈希映射函数组成,可以用于检索一个元素是否一定不在集合中或者可能在集合中。

布隆过滤器的原理?

布隆过滤器是一个bit数组,如果我们向把一个key映射到布隆过滤器中,就利用所有的哈希函数对这个key进行映射得到一系列的哈希值,将哈希值当成数组的下标,把下标对应的数组元素置为1。那么当判断一个key是否在bit数组中的时候,就判断以该key经过哈希函数映射的哈希值为下标的元素是不是都为1,如果都为1,那么该key可能在集合中;如果有任何一个不为1,那么该key一定不在该集合中。

为什么全部为1,可能在集合中?

因为经过哈希映射是可能存在哈希冲突的,在发生哈希冲突的时候,如果刚好所有的映射值都被设置为了1,就会影响判断结果,这也是布隆过滤器的一个缺点,为了做到时间和空间上的高效率,布隆过滤器选择牺牲一点准确率。还有一个缺点是,布隆过滤器的删除比较困难,如果要删除一个key的映射,不能简单的把该key哈希值对应位置上的元素置为0,因为要删除的这个key可能会和其他key发生了哈希冲突,另外的key也映射到了该位置,那么直接置为0的话就会影响其他key的判断。

其他应用场景:

  • Google Chrome 使用布隆过滤器识别恶意 URL
  • 使用布隆过滤器避免推荐给用户已经读过的文章/视频
  • 爬虫过滤已抓到的url就不再抓,可用bloom filter过滤
  • 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值