缓存的使用场景:

1. DB缓存,减轻服务器压力  指优先访问缓存, 没有命中找DB

2. 提高系统响应 解决频繁IO而无法响应

3. 做Session分离, 多个服务器共享Session信息

4. 做分布式锁, 控制多个进程并发下产生的问题,以及控制时序性,使用Redis实现的setNX

5. 做乐观锁,Redis可以实现乐观锁 watch + incr

缓存的读写模式:

1. Cache Aside Pattern(常用)

Cache Aside Pattern(旁路缓存),是最经典的缓存+数据库读写模式。

读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。

更新的时候,先更新数据库,然后再删除缓存。
为什么是删除缓存,而不是更新缓存呢?
a. 缓存的值是一个结构:hash、list,更新数据需要遍历
b. 懒加载,使用的时候才更新缓存. 也可以采用异步的方式填充缓存
高并发脏读的三种情况

1、先更新数据库,再更新缓存

2、先删除缓存,再更新数据库

3、先更新数据库,再删除缓存(推荐)

2. Read/Write Through Pattern

3. Write Behind Caching Pattern

缓存架构的设计思路:

1. 多层次, 分布式缓存宕机,本地缓存还可以使用
2. 数据类型, Value是字符串或整数, Value的值比较大(大于100K)只进行setter, gtter(采用Memcached)
3. 复杂数据类型 Value是hash、set、list、zset 需要存储关系,聚合,计算 可采用Redis
4. 分布式缓存集群方案(Redis) 哨兵+主从   RedisCluster
5. 缓存的数据结构设计: 缓存的数据是经常访问的;  需要存储关系,聚合,计算等;比如某个用户的帖子、用户的评论。
key:UID+时间戳(精确到天) 评论一般以天为计算单位
value:Redis的Hash类型。fifield为 id和content
expire:设置为一天

Redis数据类型:

String:

应用场景:
1、key和命令是字符串
2、普通的赋值
3、incr用于乐观锁
incr:递增数字,可用于实现乐观锁 watch(事务)
4、setnx用于分布式锁
当value不存在时采用赋值,可用于实现分布式锁
eg: setnx name zhangsan    当再一次复制时失败
      set age 18 NX PX 1000   NX 原子操作  PX 过期时间
      

list列表类型:

        list列表类型可以存储有序、可重复的元素
        获取头部或尾部附近的记录是极快的
        list的元素个数最多为2^32-1个(40亿)
应用场景:
1、作为栈或队列使用
列表有序可以作为栈和队列使用
2、可用于各种列表,比如用户列表、商品列表、评论列表等。

set集合类型:

命令: 

无序, 唯一性

应用场景: 适用于不能重复的且不需要顺序的数据结构  比如:关注的用户,还可以通过spop进行随机抽奖

sortedset有序集合类型:

元素本身是无序不重复的, 每个元素关联一个分数(score), 可按分数排序,分数可重复
zadd key score1 member1 score2 member2 ...

zrem key mem1 mem2 ....  删除成员

zcount key min max 返回区间的个数

zcard key  获得元素数量

zincrby key increment member   在集合的member上加increment

zscore key member   获得集合中的分数
zrank key member    获得集合中member的排名(按分值从小到大)

zrevrank key member  按分值从大到小排序
zrange key start end    指定区间, 按分数递增排序
zrevrange key start end   指定区间, 按分数递减排序

应用场景:
由于可以按照分值排序,所以适用于各种排行榜。比如:点击排行榜、销量排行榜、关注排行榜等。

hash类型(散列表)

Redis hash 是一个 string 类型的 fifield 和 value 的映射表,它提供了字段和字段值的映射。
hset key fifield value   赋值  不区分新增 | 添加
hmset fifield1 value1 fifield2 value2   批量赋值
hsetnx key fifield value    赋值 存在不操作
hexists key fifiled    查看是否存在
hget key fifield    获取某个字段
hmget key fifield1 fifield2 ...  获取多个字段
hincrby key fifield increment    该字段自增
应用场景:
对象的存储 ,表数据的映射

stream数据流类型

RedisObject结构:

typedef struct redisObject { unsigned type:4;//类型 五种对象类型 unsigned encoding:4;//编码 void *ptr;//指向底层实现数据结构的指针 //... int refcount;//引用计数 //... unsigned lru:LRU_BITS; //LRU_BITS为24bit 记录最后一次被命令程序访问的时间 //...
}robj;

type:  指存储当前值是什么类型

REDIS_STRING(字符串)、REDIS_LIST (列表)、REDIS_HASH(哈希)、REDIS_SET(集合)     REDIS_ZSET(有 序集合)。    命令: type  key
4encoding: 指每个对象都有着不同的编码格式,  命令: object  encoding key
Redis通过 encoding 属性为对象设置不同的编码
对于少的和小的数据,Redis采用小的和压缩的存储方式,体现Redis的灵活性
大大提高了 Redis 的存储量和执行效率
比如Set对象:intset : 元素是64位以内的整数 hashtable:元素是64位以外的整数

24LRU :  记录着最后一次访问的时间, 高16为记录时间戳, 低8为记录访问计数
refcount
        refcount 记录的是该对象被引用的次数,类型为整型。
        refcount 的作用,主要在于对象的引用计数和内存回收。
        当对象的refcount>1时,称为共享对象
        Redis 为了节省内存,当有一些对象重复出现时,新的程序不会创建新的对象,而是仍然使用原的对象。
ptr:  指着具体的数据   ,比如:set hello world,ptr 指向包含字符串 world 的 SDS。
SDS的优势:
1、SDS 在 C 字符串的基础上加入了 free 和 len 字段,获取字符串长度:SDS 是 O(1),C 字符串是
O(n)。
buf数组的长度=free+len+1
2、 SDS 由于记录了长度,在可能造成缓冲区溢出时会自动重新分配内存,杜绝了缓冲区溢出。
3、可以存取二进制数据,以字符串长度len来作为结束标识
使用场景:
SDS的主要应用在:存储字符串和整型数据、存储key、AOF缓冲区和用户输入缓冲。
跳跃表是有序集合(sorted-set)的底层实现,效率高,实现简单。
将有序链表中的部分节点分层,每一层都是一个有序链表。
字典dict又称散列表(hash),是用来存储键值对的一种数据结构。
Redis整个数据库是用字典来存储的。(K-V结构)
对Redis进行CURD操作其实就是对字典中的数据进行CURD操作。
数组:用来存储数据的容器,采用头指针+偏移量的方式能够以O(1)的时间复杂度定位到数据所在的内 存地址。
快速列表

快速列表(quicklist)是Redis底层重要的数据结构。是列表的底层实现。(在Redis3.2之前,Redis采用双向链表(adlist)和压缩列表(ziplist)实现。)在Redis3.2以后结合adlist和ziplist的优势Redis设 计出了quicklist

 

双向链表优势

1. 双向:链表具有前置节点和后置节点的引用,获取这两个节点时间复杂度都为O(1)。
2. 普通链表(单链表):节点类保留下一节点的引用。链表类只保留头节点的引用,只能从头节点插
入删除
3. 无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问都是以 NULL 结
束。
4. 带链表长度计数器:通过 len 属性获取链表长度的时间复杂度为 O(1)。
5. 多态:链表节点使用 void* 指针来保存节点值,可以保存各种不同类型的值。
数据压缩
quicklist每个节点的实际数据存储结构为ziplist,这种结构的优势在于节省存储空间。为了进一步降低
ziplist的存储空间,还可以对ziplist进行压缩。Redis采用的压缩算法是LZF。其基本思想是:数据与前
面重复的记录重复位置及长度,不重复的记录原始数据。

缓存过期和淘汰策略

长期使用,key会不断增加,Redis作为缓存使用,物理内存也会满
内存与硬盘交换(swap) 虚拟内存 ,频繁IO 性能急剧下降
maxmemory
不设置最大内存的场景:
key是固定的, 不会增加, 
Redis作为DB使用,保证数据的完整性,不能淘汰 , 可以做集群,横向扩展
        淘汰策略: 禁止驱除
设置的场景:
        key在不断增加
        默认为0时, 不限制, 直到超过物理内存, 崩溃

设置maxmemory后,当趋近maxmemory时,通过缓存淘汰策略,从内存中删除对象

expire数据结构

命令:  expire key ttl(单位秒)
数据结构中:  dict存储key-value,   expires则维护了Redis了设置失效时间的key
当我们使用 expire命令设置一个key的失效时间时,Redis 首先到 dict 这个字典表中查找要设置的key是 否存在,如果存在就将这个key和失效时间添加到 expires 这个字典表。
当我们使用 setex命令向系统插入数据时,Redis 首先将 Key 和 Value 添加到 dict 这个字典表中,然后 将 Key 和失效时间添加到 expires 这个字典表中。

删除策略
Redis的数据删除有定时删除、惰性删除和主动删除三种方式。
Redis目前采用惰性删除+主动删除的方式。
定时删除
在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除 操作。
需要创建定时器,而且消耗CPU,一般不推荐使用。
惰性删除
在key被访问时如果发现它已经失效,那么就删除它。
调用expireIfNeeded函数,该函数的意义是:读取数据之前先检查一下它有没有失效,如果失效了就删 除它。
主动删除
在redis.conf文件中可以配置主动删除策略,默认是no-enviction(不删除)
maxmemory-policy allkeys-lru
LRU
LRU (Least recently used) 最近最少使用,算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
通过LinkedHashMap来维护缓存数据
1. 新数据插到表头
2. 每当有数据命中, 提到对头
3. 当链表满时, 删除队尾数据
RedisLRU 数据淘汰机制
在服务器配置中保存了 lru 计数器 server.lrulock,会定时(
redis 定时程序 serverCorn())更新, server.lrulock 的值是根据 server.unixtime 计算出来的。

另外在RedisObject中有lru的属性, 则每次访问数据, 都会更新
LRU 数据淘汰机制是这样的:在数据集中随机挑选几个键值对,取出其中 lru 最大的键值对淘汰。
volatile-lru
从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
allkeys-lru
从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
LFU
LFU (Least frequently used) 最不经常使用,如果一个数据在最近一段时间内使用次数很少,那么在将 来一段时间内被使用的可能性也很小
volatile-random
从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-random
从数据集(server.db[i].dict)中任意选择数据淘汰
ttl
volatile-ttl
从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
redis 数据集数据结构中保存了键值对过期时间的表,即 redisDb.expires。
TTL 数据淘汰机制:从过期时间的表中随机挑选几个键值对,取出其中 ttl 最小的键值对淘汰。
noenviction
禁止驱逐数据,不删除 默认
缓存淘汰策略的选择
allkeys-lru : 在不确定时一般采用策略。
volatile-lru : 比allkeys-lru性能差 存 : 过期时间
allkeys-random : 希望请求符合平均分布(每个元素以相同的概率被访问)
自己控制:volatile-ttl 缓存穿透

缓存原理设计(Redis)相关推荐

  1. Spring Cache 缓存原理与 Redis 实践

    说到Spring Boot缓存,那就不得不提JSR-107规范,它告诉我们在Java中如何规范地使用缓存. JSR是Java Specification Requests的简称,通常译为"J ...

  2. 高级架构师_Redis_第1章_缓存原理与设计

    高级架构师_Redis_第1章_ 缓存原理与设计 文章目录 高级架构师_Redis_第1章_ 缓存原理与设计 第一节 缓存原理与设计 1.1 缓存基本思想 1.11 缓存的使用场景 1.12 什么是缓 ...

  3. 案例:同程凤凰缓存系统基于Redis的设计与实践。

    本文和大家分享一下同程凤凰缓存系统在基于Redis方面的设计与实践.在本文中除了会列举我们工作过程中遇到各种问题和误区外,还会给出我们相应的解决办法,希望能够抛砖引玉为大家带来一定的启示. 同程凤凰缓 ...

  4. Camstar开发:缓存的设计与实现(整合Redis实例)

    目录 1引言 2实例描述 3开发分析 4 实例类图 5 代码分析 5.1 RedisHelper 5.2 ReceiveOrderCache 5.3 IReceiveOrder 5.4 AbsRece ...

  5. Redis的缓存原理

    Redis的缓存原理 Redis是什么? Redis 是一个高性能的开源的.C语言写的Nosql(非关系型数据库),数据保存在内存中. Redis 是以key-value形式存储,和传统的关系型数据库 ...

  6. Redis一(缓存的工作原理、redis的介绍、hashmap缓存)

    文章目录 一.缓存 二.redis 三.hashmap模拟缓存工作原理 1)首先查看数据库中存储的数据格式 2)连接数据库,利用spring在浏览器中显示 3)测试,运行spring接口 一.缓存 当 ...

  7. Redis缓存策略设计及常见问题

    Redis缓存设计及常见问题 缓存能够有效地加速应用的读写速度,同时也可以降低后端负载,对日常应用的开发至关重要.下面会介绍缓存使用技巧和设计方案,包含如下内容:缓存的收益和成本分析.缓存更新策略的选 ...

  8. 缓存层设计套路(一)

    一.背景 对于传统的后端业务场景(或者单机应用)中,访问量以及对响应时间的要求均不高,通常只使用DB即可满足要求.这种架构简单,便于快速部署,很多网站发展初期均考虑使用这种架构.但是随着访问量的上升, ...

  9. Redis源码-String:Redis String命令、Redis String存储原理、Redis String三种编码类型、Redis字符串SDS源码解析、Redis String应用场景

    Redis源码-String:Redis String命令.Redis String存储原理.Redis String三种编码类型.Redis字符串SDS源码解析.Redis String应用场景 R ...

最新文章

  1. CTF--base64编码过程中隐藏信息解密脚本
  2. ttf能改成gfont吗_如何编辑ttf字体文件
  3. 2014/School_C_C++_B/2/调和级数
  4. 一次性缴纳6万元,退休后每月领1500元养老金,你愿意吗?
  5. 找出最大值和最小值(算法导论第三版9.1-2)
  6. Android 创建文件,删除文件,加载本地txt文件,string转txt文件,创建文件夹,读取文件夹,open failed: ENOENT
  7. php文件上传到虚拟主机,php源码上传到虚拟主机(php源码上传到服务器)
  8. 他从阿里离职,放弃“好几个亿”,他的英语课20000元/天,现在,你可以免费学!...
  9. 图片服务 - thumbor启用AutoJPG
  10. Java 算法 一元一次方程
  11. 袁隆平杂交水稻创新团队发布“农业芯片”,世界顶级科学家点赞拼多多新农人...
  12. Linux下利用脚本全自动搭建论坛
  13. 解决Junit问题的方法
  14. 十六进制编辑器--ImHex
  15. 电脑分屏没有声音_怎样解决qq屏幕分享没有声音问题
  16. Python获取对象所占内存大小方法
  17. 详解分级基金(杠杆基金)【精华】 【转】
  18. Windows操作系统注册表registry
  19. meteor使用简介
  20. 【蓝凌表单】流程表单JS汇总

热门文章

  1. 鸿蒙hap捷豹,鸿蒙手表真机展示Hello World!
  2. 从AtomicLong 到 LongAdder
  3. 用python实现一个计算Fibonacci数的函数
  4. vscode html文件自动补充html骨架失效
  5. python 爬取直播_python爬虫,轻快爬取直播平台热度排行
  6. Javascript 遍历NodeList
  7. oracle 算列总数,Oracle认证:Oracle统计符合条件列总数
  8. Spring 中的 Bean
  9. JavaScript设计模式(7)-设配器模式
  10. Layui中textarea如何进行表单序列化并回显