Redis知识点

Stella981
• 阅读 730

1. 应用场景

缓存:根据键值过期时间设置

请求频率限制:比如短信验证码120秒内只能发送一次,则将标志性的key-value键值对设置过期时间为120秒,用户请求的时候判断一下【SET key value EX 120 NX

排行榜:利用zset数据类型

计数器:利用 INCR KEY 命令,key不存在初始化为0,存在则自增1

用户爱好:利用set集合,其特有的命令方法能够计算用户共同爱好

消息队列:利用list数据类型的lpush和brpop

分布式锁:利用 SET key value [EX seconds] [PX milliseconds] [NX|XX]

2.速度快的原因

  • 纯内存访问
  • 底层I/O用多路复用技术epoll实现
  • 单线程避免了线程切换和竞争

3. 数据类型

  • 字符串(String):内部编码【8个字节长整型:int】【小于等于39个字节的字符串:embstr】【大于39个字节的字符串:raw】
  • 哈希(Hash):内部编码【元素个数小于512个并且每个值都小于64字节:ziplist-压缩列表】【否则是hashtable-哈希表】
  • 列表(List):内部编码【元素个数小于512个并且每个值都小于64字节:ziplist-压缩列表】【否则是linkedlist-链表】
  • 集合(Set):内部编码【元素都是整数并且个数小于512个:intset-整数集合】【否则是hashtable-哈希表】
  • 有序集合(ZSet):内部编码【元素个数小于128个并且每个值都小于64字节:ziplist-压缩列表】【否则是skiplist-跳跃表】

4. 持久化-RDB

触发:save或者bgsave命令。不同的是save会阻塞服务器,直到持久化完成;bgsave会fock子进程,子进程负责完成持久化的任务,这种只在fock的时候会阻塞很短一部分时间。

RDB持久化流程:

  • 执行bgsave命令,如果已存在相关的子进程,则直接返回。
  • 父进程执行fock操作创建子进程。fock完成后不再阻塞父进程。
  • 子进程创建RDB文件,根据父进程的内存生成临时快照文件,完成后对原有文件进行原子替换。
  • 最后给父进程发送完成信号,父进程更新统计信息。

Redis默认采用LZF算法对生成的RDB文件做压缩处理,压缩后的文件远远小于内存大小。

5. 持久化-AOF

工作流程:

  • 命令写入:所有的写入命令都会追加到AOF缓冲区(处于性能的考量,不追加到硬盘)
  • 文件同步:缓冲区根据对应的策略向硬盘做同步操作(策略:always,everysec,no,默认everysec)
  • 文件重写:AOF文件越来越大,所以定期对AOF文件进行重写,达到压缩的目的(无效命令比如del、set,文件只保留最终数据的写入命令;多条命令合并成一条)
  • 重启加载:Redis服务器重启后,会根据AOF文件进行数据恢复

AOF重写流程:

首先主进程会fock一个子进程。Redis会维护一个AOF重写缓冲区,该缓冲区会在子进程创建新的AOF文件期间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件之后,服务器会将重写缓冲区中的所有内容追加到新的AOF文件的末尾。最后,服务器用新的AOF文件替换旧的AOF文件,以此来完成AOF文件重写操作。

如果同时配置了RDB和AOF,则Redis会优先加载AOF

6. 数据分区

分布式环境下要解决把数据映射到多个节点的问题。

A:节点取余分区

【对key取hash】%【节点数量】,来决定数据打到哪一个节点上。

B:一致性哈希分区

为系统中每个节点分配一个token,范围为2的32次幂,这些token构成一个hash环。读写数据的时候,根据key取hash,然后顺时针找到第一个大于等于该hash值的token所对应的节点。

一致性哈希存在的问题:

  • 加减节点会导致一部分数据无法命中,需要手动处理或者忽略,所以一致性哈希常用语缓存场景。
  • 节点比较少的情况,节点发生变化将影响很大一部分数据命中,所以不适合节点少的情况。

C:虚拟槽分区

Redis Cluser采用虚拟槽分区,所有的键根据哈希函数映射到0~16383整数槽内,计算公式:slot=CRC16(key)&16383。每一个节点负责维护一部分槽以及槽所映射的键值数据

优点:解耦数据和节点之间的关系,简化了节点扩容和收缩难度。

7. 集群功能限制

不支持批量操作比如:mget,mset

不支持多数据库空间,即只有一个db0

8. 缓存穿透

原因:请求不存在的数据,而导致每次请求都要跳过缓存直接去存储层拿数据,失去了缓存保护后端存储的意义。

解决:

  • 方法一:存储层不命中,依然缓存空对象,之后再访问这个数据就会从缓存中获取。可是:如果是恶意攻击,意味着这部分无意义的数据会占用内存,可以通过设置过期时间来缓解。
  • 方法二:利用布隆过滤器把存在的key缓存起来,作为访问的第一层,之后才是缓存和数据库,如果布隆过滤器认为请求的key不存在,则不会访问数据库,进而保护了存储层。
  • 比较:存储空对象适用于:数据频繁变化实时性高的场景。布隆过滤器适用于:数据相对固定实时性低的场景。

9. 缓存击穿

原因:比如有个热点key承载了大量请求,在key失效的一瞬间,大量请求跳过缓存直接去请求了数据库

解决:

  • 方法一:一般是因为做促销活动导致key成为这种热点,对于这类key要么设置过期时间长一些以至于熬过高峰期,要么直接设置成永不过期。
  • 方法二:加互斥锁,即如果缓存不存在,则加锁去读取数据库并更新缓存,保证失效的时候只有一个线程能去访问数据库。

10. 缓存雪崩

原因:

  • 在同一时间点,承载大量请求的缓存集中失效,大量请求会到达存储层,进而造成存储层压力过大而宕机。
  • 缓存层由于异常不能提供服务后,大量请求会到达存储层,进而造成存储层压力过大而宕机。

解决:

  • 保证缓存服务高可用
  • 将key的过期时间设置随机,这样避免同一时间大量失效

11. 淘汰策略(6种)

这6种策略的前提都是:当内存不足以容纳新写入数据时

noeviction:新写入操作会报错(默认策略)

范围:在主键空间中

allkeys-lru:移除最近最少使用的key

allkeys-random:随机移除某个key

范围:在设置了过期时间的键空间中

volatile-lru:移除最近最少使用的key

volatile-random:随机移除某个key

volatile-ttl:有更早过期时间的key优先移除

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这