当前位置:   article > 正文

一、redis-万字长文读懂redis

一、redis-万字长文读懂redis

高性能分布式缓存Redis

第一篇章

1.1 缓存发展史&缓存分类

大型网站中缓存的使用-做缓存

在这里插入图片描述
分析:直接从数据库中的数据,是存储在磁盘中的,需要多次的IO,而且请求数据库是基于TCP连接,单机的mysql qps 1W+,而redis的qps达到10w+;所以可以在Tomcat和mysql中加入屏障,将热点数据放入redis,非热点数据放入数据库中,流程如下
在这里插入图片描述

带来的问题

  • 读写缓存策略
    • 读写穿透
    • 异步缓存写入
  • 数据库和缓存如何保证数据一致性
    • 写策略
      • 先更新缓存,再删除缓存
      • 先删除缓存,再更新数据库

其它应用

  1. 数据库
    Redis可以作为一个高性能的内存数据库使用,支持持久化存储和数据备份,可以处理大量的读写操作。

  2. 消息队列
    Redis的发布/订阅功能可以用于构建简单的消息队列系统,可以实现消息的发布、订阅和传递。

  3. 分布式锁
    Redis的原子性和分布式特性可以用于实现分布式锁,保证在分布式环境下的数据一致性。

  4. 计数器
    Redis的原子性操作和高性能可以用于实现各种计数器,比如网站的访问量统计、点赞数统计等。

  5. 地理位置应用
    Redis的地理位置功能可以用于存储和查询地理位置信息,比如附近的人、附近的店铺等。

1.2 与memcache对比

共同点
1. 都是基于内存的数据库,一般都用来当做缓存使用。
2. 都有过期策略。
3. 两者的性能都非常高。

区别
1. Redis 支持的数据类型更丰富(String、Hash、List、Set、zset),而 Memcached 只支持最简单的 key-value 数据类型;
2. Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可 以再次加载进行使用,而 Memcached 没有持久化功能,数据全部存在内存之中,Memcached 重启或者挂掉后,数据就没了
3. Redis 原生支持集群模式,Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;
4. Redis 支持发布订阅模型、Lua 脚本、事务等功能,而 Memcached 不支持
5. 特性丰富:Redis可用于缓存,消息,按key设置过期时间,过期后将会自动删除
所以,很少使用memcached了

1.3 数据类型选择&应用场景

数据类型对比表格

  • 常见的五种数字类型:string、hash、list、set、zset
    在这里插入图片描述

1)string

  • 定义
    • redis并不是简单的使用c的string,而是构建了简单动态字符串,不光可以保存文本数据还可以保存二进制,并且获取字符串的长度为0
  • 常用命令:set,get,strlen,exists
  • 应用场景:缓存对象、常规计数、分布式锁、共享session
    • 对象缓存:直接缓存整个对象的json
    • 分布式锁:setnx product:10001 true;setnx product:10001 false
  • 优点
    • 获取字符串长度的复杂度为O(1)
    • 杜绝缓冲区溢出
    • 减少修改字符串长度时所需要的内存分配次数
    • 二进制安全

2)hash

  • key-value,适合存储
  • 适合做对象缓存
  • 比如:电商购物车-用户id为key;商品id为field;商品数量为value;
Hest cart:1 1001 1 //向id为1的商品1001添加1间商品
  • 1

3) 链表

  • 特点

    • c的链表查询比较难,所以redis使用了双向链表,支持反向查找和遍历,更方便操作,不过带了了额外的内存开销:每个链表节点由一个listNode结构来表示,每个节点都有一个指向前置节点和后置节点的指针
    • 因为链表表头的前置节点和表尾节点的后置节点都指向NULL,所以Redis的链表实现是无环链表。
    • 通过为链表设置不同的类型特定函数,Redis的链表可以用于保存各种不同类型的值。
  • 内部实现:quicklist

  • 常用命令:rpush、lpop、lpush

  • 应用场景:发布与订阅或者说消息队列,慢查询
    在这里插入图片描述

  • 常用数据结构

    • Stack(栈)=LPUSH(左边放)+LPOP(左边取)–> FILO
    • Queue(队列)=LPUSH(左边放)+RPOP右边取)
    • BLocking queue(阻塞队列)=LPUSH(左边放)+ BRPOP(右边阻塞取:没有数据就阻塞!)

4) set

  • 是一个无序并唯一的键值集合,它的存储顺序不会按照插入的先后顺序进行存储。一个集合最多可以存储 2^32-1 个元素。概念和数学中个的集合基本类似,可以交集,并集,差集等等,所以 set 类型除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集
  • 底层实现:哈希表或整数集合
  • 常用命令: sadd,spop,smembers,sismember,scard,sinterstore,sunion 等
  • 应用场景: 需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景

5) sortedset有序集合类型

  • Zset 类型的底层数据结构是由压缩列表或跳表实现的:如果有序集合的元素个数小于 128 个,并且每个元素的值小于 64 字节时,Redis 会使用压缩列表作为 Zset 类型的底层数据结构,压缩列表的查找操作是顺序查找,时间复杂度为O(n)
  • 如果有序集合的元素不满足上面的条件,Redis 会使用跳表作为 Zset 类型的底层数据结构,跳表查询任意数据的时间复杂度就是 O(logn)

介绍

  • zset 类型(有序集合类型)相比于 Set 类型多了一个排序属性 score(分值),对于有序集合zSet 来说,每个存储元素相当于有两值组成的,一个是有序集合的元素值,一个是排序值。
  • 内部实现: 压缩列表或跳表
    • Redis的跳跃表实现由zskiplist和zskiplistNode两个结构组成,其中zskiplist用于保存跳跃表信息(比如表头节点、表尾节点、长度),而zskiplistNode则用于表示跳跃表节点
    • 每个跳跃表节点的层高都是1至32之间的随机数
    • 在同一个跳跃表中,多个节点可以包含相同的分值,但每个节点的成员对象必须是唯一的。
    • 跳跃表中的节点按照分值大小进行排序,当分值相同时,节点按照成员对象的大小进行排序。
    • 跳表是一种实现起来很简单,单层多指针的链表,它查找效率很高,堪比优化过的二叉平衡树,且比平衡树的实现。
  • 常用命会: zadd,zcard,zscore,zrange,zrevrange,zrem等
  • 应用场景: 需要对数据根据某个权重进行排序的场景。比如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息。

redis中的zset实现字典序排序,应该如何做

使用ZADD命令将需要排序的字符串添加到有序集合中。例如:

ZADD myset 1 "apple"
ZADD myset 2 "banana"
ZADD myset 3 "cherry"
  • 1
  • 2
  • 3

使用ZRANGE命令获取按字典序排序的有序集合。例如:

ZRANGE myset 0 -1
  • 1

这将返回按字典序排序的所有元素。
如果你想要逆序排序,可以使用ZREVRANGE命令。例如:

ZREVRANGE myset 0 -1
  • 1

1.4 Redis高级应用&拓展功能

1)发布订阅

  • redis提供发布订阅功能,可用于消息的传输
  • redis的发布订阅包含三个部分,publisher(redis客户端),subscriber(redis客户端)、channel(服务器)
    在这里插入图片描述
  • 指令详情
    • SUBSCRIBE/PSUBSCRIBE:订阅,精确、或者按匹配符UNSUBSCRIBE/PUNSUBSCRIBE:退订,精确、或者按匹配
    • PUBLISH:发送;PUBSUB:查看消息列表
  • 使用场景
    • 在Redis哨兵模式中,哨兵通过发布与订阅的方式与Redis主服务器和Redis从服务器进行通信Redisson是一个分布式锁框架,在Redisso
    • 分布式锁释放的时候,是使用发布与订阅的方式通知的注:重业务的消息,推荐用消息队列

2)事务-redis事务虽不支持回滚,但…

  • redis事务不支持回滚

    • 所谓事务,是指作为单个逻辑工作单元执行的一系列操作
    • mysql在执行事务时,会提供回滚机制,当事务执行发生错误时,事务中的所有操作都会撤销,已修改的数据也会被恢复到事务执行前的状态,但是redis并没有提供回滚机制,redis事务不一定能保证原子性
  • redis 事务

    • redis事务的本质是一组命令的集合:单词执行多个命令,一次性、排他性、顺序性
      • redis事务是通过multi、exec、discrd、watch这四个命令来完成的
      • redis的单个命令都是原子性的,所以这里需要确保事务的对象是命令集合
      • redis将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执
      • redis不能保障失败回滚
  • 原理刨析

    • 在exec执行事务的一瞬间,判断监控的key是否变动
    • 变动则取消事务队列,直接不执行
    • 无变动则执行,提交事务
      在这里插入图片描述

3) redis+lua脚本保持原子性

  • lua定义

    • lua是一种轻量小巧的脚本语言用标准C语言编写并以源代码形式开放,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
  • Lua应用场景

    • 游戏开发、独立应用脚本、web应用脚本、查询库存扣减库存
    • Nginx+lua开发高性能web应用,限流、防止Sql注入
  • 时间复杂度 取决于执行的脚本。

  • 使用Lua脚本的好处:

    • 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延。原子操作。redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的过程中无需担心会出现竞态条件,无换事务。
    • 复用。客户端发送的脚本会永久存在redis中,这样,其他客户端可以复用这一脚本而不需要使用代码完成相同的逻辑。

4)慢查询日志

  • 日常使用redis为什么要用慢查询日志

  • 客户端请求的生命周期的完整生命周期,4个阶段

  • 慢查询只统计步骤3的时间,在生产环境中,慢查询功能可以有效地帮助我们找到Redis可能存在的瓶颈,但在实际使用过程中要注意以下几点
    在这里插入图片描述

    • slowog-max-en:线上建议调大慢查询列表,记录慢査询时Redis会对长命令做阶段操作,并不会占用大量内存,增大慢查询列表可以减缓慢查询被剔除的可能,例如线上可设置为1000以上.
    • slowlog-log-slower-than:默认值超过10毫秒判定为慢查询,需要根据Redis并发量调整该值,慢查询只记录命令的执行时间,并不包括命令排队和网络传输时间,因此客户端执行命令的时间会大于命令的实际执行时间,因为命2令执行排队机制,慢查询会导致其他命令级联阻塞,因此客户端出现请求超时时,需要检査该时间点是否有对应的慢查询,从而分析是否为慢查询导致的命令级联阻塞.

第二篇章

2.1 持久化

1 ) 原理

redis是内存数据,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将redis中方的数据以某种形式从内存存储到硬盘。当下次redis重启的时候,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程的位置

2) 持久化流程

redis

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/992358?site=
推荐阅读
相关标签
  

闽ICP备14008679号