Redis数据结构以及对应存储策略

redis数据结构:

  • String 可以是字符串也可以是数字,以及浮点数
  • List,一个链表,链表上每一个节点都包含一个字符串
  • set 包含字符串的无序手机其,特点是每一个字符都是唯一的
  • hash,包含键值对的无序散列,类似map
  • ZSet,字符串成员,在set的基础上是顺序的,元素的顺序由分值来决定
  • redis的发布与订阅的特性(重点):
    • subscribe channel命令 订阅给定的一个或者多个频道
    • pushlish channel message 给指定频道发送消息,
    • 通过这两个命令redis可以实现发布与订阅功能
  • redis的基本事务功能
    • redis通过multi和exec命令来实现事务的特性,在执行multi命令之后,redis会将这个客户端之后发送的所有命令存储在一个队列中,直到接受到exec命令为止。然后会在不被打断的情况下执行这些操作
  • redis键过期时间:使用expiration设置key存活的时间,之后自动删除
重要的数据结构
  • hyperLogLog:基数计算概念:通常用来统计一个集合中不重复元素个数,比如用来统计网站的UV,或者网站搜索关键字的数量。最简单的办法是用给一个集合做统计,判断新词是否存在,然后添加存在两个问题,数据量会变很大,判断成本会变得很高。bitMap存储1 亿个数据大概要12M内存,redis中HyperLogLog(HLL)中只需要1K内存就能做到
    • hyperLogLog原理(简析):将需要统计的数据进行HASH,得到每个数据对应二进制串,统计得到的二进制串中从低位开始第一次出现1的情况并且进行统计,统计每个key的这种1 的位置,让后用概率和统计的方法推到出统计和数据量之间的关系,HyperLogLog核心在于集合中每个实体对应的Hash串,通过这种统计来预估整体的量,可以大大减少内存的耗费,所以这种方式并没有存储所有的样本,而是通过样本估算的方式推算出总体大小。(数学原理 伯努力分布)
  • GEO redis3.2中的新特性用来存储和获取经纬度,以及地理位置,还有位置距离计算等内容 如下操作
//设置信息
GEOADD beijing 113.2099647 23.593675 五道口  //GEOADD 地址 经度 纬度 地区
GEOADD beijing 113.2099643 23.593674 上地  
//获取信息
GEOPOS beijing 上地 
//获取指定信息地点 900m范围的地点
GEORADIUS  beijing 113.2099647 23.593675 900 m 
  • redis modules:redis4.0 曾加了自定义模块的开发,类似于3.X版本中lua脚本的兼容,但是lua有一定学习量,在4.0中提供了一系列模块源码: https://github.com/RedisLabsModules/redex ,可以通过命令将对应的模块代码导入到redis中,就可以使用对应自定义命令
SADD admins Alice Bob xiaorui.cc
  • BloomFilter:主要功能是用来做去重,我们可以用来对访问UV和购买UV的实时去重,具体原理如下:
    • BloomFilter过滤器会将key做一次Hash,将hash后得到的int分布到一个大的Bit数组中对应的位,判断一个Key是否存在,只要看Hash对应的bit数组位置是否是1,1则被占用,0不被占用
    • 而且redis2.0 以后就支持bigMap的操作,以及Bit操作中的AND,OR,NOT,XOR操作,bitMap支持232 大小,也就是512M,下标最大232-1,可以存2亿左右数据
  • Redis Search:基于redis的搜索插件,可以用来做全局key值的模糊查询,并且可以兼容一部分通配符
  • Redis-ML :用来做机器学习的

redis数据安全与性能保障

  • redis提供两种不同持久化方式来将数据存储到硬盘:

    • 快照模式(RDB)可以将存在某一个时间点上所有数据写入硬盘

      • RDB模式通过配置信息来启动,并且设置触发的配置,比如save 60 10000 在最近一次快照算起,60秒以内有10000次写操作,自动执行一次BGSAVE命令做备份
      • 快照生成一个rdb文件,可以拷贝,但是在心快照创建完毕之前,redis,系统,硬件有一个出现问题,那么redis将会丢失最近一次快照之后的所有写入数据。
      • 可以手动创建快照:通过BGSAVE命令,redis会调用fork来创建一个子进程,他来完成写入,父子进程共享内存,直到父进程有写入操作的时候共享结束
      • 只适合哪些可以容忍少部分数据丢失的业务场景
      • rdb方式需要找到save配置的点,因为如果过于频繁会浪费资源,过于稀少可能丢失大量数据,我们一般做法是在测试机器上尽量模拟线上环境
      • 执行BGSAVE会使redis停顿一定时间取决于系统以及硬件
    • 追加文件模式(AOF),在执行写命令时候将这条命令复制到硬盘

      • AOF方式也可以通过配置方式打开,他会将所有写命令追加到aof文件末尾,redis只需要执行一次aof文件就可以恢复所有记录。
      • 配置写入频率:always:每个写入都同步aof文件到硬盘,效率极低。everysec:每一秒同步一次 no:让操作系统来决定何时同步。
      • 一般使用everysec,每秒执行一次和不适用任何持久化的性能比差不多,这样可以保证做多丢失一秒的数据
      • aof文件可能会变得很大甚至沾满硬盘,这时候redis重启需要执行AOF文件中所有命令这个执行时间会很长
      • 可以通过向redis发送BGREWRITEAOF命令来移除荣誉的命令,来重写aof文件,但是如果文件太大,删除一个十几G的文件redis可能会处于挂起状态数秒
    • 方式可以同时使用也可以单独,也可以不用

redis过期策略
  1. 惰性删除:当读/写一个已经过期的Key的时候,会发生惰性删除策略,直接删除这个Key,很明显,太被动了
  2. 定期删除:由于惰性删除策略无法保证冷数据被几及时删除,所以redis会定期主动淘汰一批已经过期的Key
  3. 主动删除:当前已有的数据内存超过MaxMemory的时候,触发自动清策略,该策略由启动参数的配置决定
    • volatile-lru:从已经设置过期时间的数据集合中通过LRU算法淘汰数据,3.0以前的默认策略:
    • volatile-ttl:从过期数据集合中挑选过期时间最小的数据删掉
    • volatile-random:从已过期集合中所见删除数据
    • allkey-lru:从所有数据聚合中通过lru删掉
    • allkey-random:从所有数据集合中随机删除
    • noenviction:禁止从内存中删除数据 3.0默认策略
  • redis过期策略只在主库中进行所有很容易在从库中读到脏数据:以下方式避免
    • 通过sca命令扫库,相当于访问这个key,充分发挥惰性删除,但是确定在于会在扫库的时候给数据库带来一定压力,所有需要找好时间点去执行。
    • 升级redis到3.0版本,在3.0 以后的版本中修复了这个问题,可以在源码中看到,曾加了对key值的主从库的判断,然后key为空,择返回null
redis缓存遇到的问题
  • 缓存穿透:一般缓存系统按照key去缓存查询,value不存在,就去后端系统查找,如果key对应的value不存在,并且这个key访问量巨大,这样会给后端DB造成很大的压力,这就叫缓存穿透:

    • 解决方案一:对查询结果为空的情况也进行缓存一个null,之后如果insert了之后在清理这个null的缓存
    • 对一定不存在的key进行过滤,放到一个足够大的bitMap中,不存在数据会被这个bitMap拦截
  • 缓存雪崩:如果我们设置缓存时候在同一个时刻过期,导致某一个时刻缓存几乎失效,请求都装法DB,DB瞬时压力过大雪崩

    • 解决方案:如果需要集中社会缓存过期时间,那么我们一般会在缓存失效时间的计算上加一个随机数,这样缓存到期时间就可以分散开
  • 缓存击穿:对于设置了过期时间的key,如果这些key在某些时间点被高超并发访问,这个时候必须考虑呗击穿的问题,和雪崩区别在于这是某一个key,正好过期的时候高并发访问一个key

    • 解决方案一:使用互斥锁,mutex key,就是在缓存失效的时候并不立马去load db,而是先使用缓存工具中某一些带成功操作返回值的操作,比如 redis的setNx实现的互斥锁,他去set一个mutex key,当操作返回成功之后在去load db并且设置到缓存中,如果返回失败,重试get方法,这样就可以只有一个请求到DB层,代码如下
      public String get(String key) {String value = redis.get(key);if (value == null) { //代表缓存值过期//设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load dbif (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表设置成功value = db.get(key);redis.set(key, value, expire_secs);redis.del(key_mutex);} else {  //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可sleep(50);get(key);  //重试}} else {return value;}}
    
    • 解决方案二:可以设置无过期时间,做逻辑过期,在redis上不做过期的设置,就不会出现这种情况,但是在value中设置一个过期的时间,在获取value之后判断是否过期,过期择重新load到cache,这样可能会有其他线程读到过期的数据,但是应该影响不大
redis 分布式锁
  • redis中有一个命令 setNx(key存在时候设置值),成功返回1,可以用setNx来争夺锁,在通过expire来设置过期时间防止忘记释放,也可以直接通过redis.setnx(key_mutex, 1, 3 * 60),同时设置值与时间,如下jedisclient源码:
 while(true) {result = this.jedisCluster.set(lockKey, lockKey, "NX", "EX", 30L);if("OK".equals(result)) {return true;}try {Thread.sleep(1000L);} catch (InterruptedException var4) {;}}
redis可能有的问题
  • redis中有1亿个key,其中10万个是一样的前缀开头,如何全部找出来:
    • 可以用keys命令,因为redis是单线程的,如果用keys会造成服务停顿
    • 用scan遍历所有key,可以无阻塞的提取指定模式的列表,但是可能会有重复,时间更长
  • Redis做异步消息队列:
    • 用list结构可以,通过repush生产消息,lpop消费消息,没有消息可以sleep之后再做,或者用blpop命令,他会阻塞直到获取消息。
    • 可以用pub/sub命令做消息队列并且可以实现一次消息消费多次 1:N
    • 延迟队列可以用sort命令对一个set进行排序,排期的对象是时间戳,这样我们可以通过逻辑去匹配一定时间之前的消息。
  • 大量的key需要设置同一时间过期一般需要注意缓存雪崩效应:
    • 所有值统一时刻过期,导致直接到DB查询,可以通过随机值,分散过期的时间
  • redis如何做数据持久化:
    • rdb模式我们可以通过bgsave方式主动去触发,同时也做aof做持久化,bgsave会持续一段时间,不够实时性,如果机器有问题可能会丢比较多的数据,aof是记录写命令,这个丢失的数据比较少,在重启的时候,会用bgsave的文件进行数据恢复,然后在用aof来恢复没有备份到文件中的数据,这样做到最小丢失。
    • rdb原理如上:redis通过fork出一个子进程来做bgsave操作,父子进程共享内存直到父进程有写操作,共享结束。
  • redis同步机制:
    • redis一般是主从同步,从从同步,master在同步时候,先bgsave一次,期间所有写入都在缓存buffer,然后将rdb文件同步到从节点,从节点loader到内存,通知主节点将缓存中的写入同步。
redis集群
  • redis3.0 的新特性就是自带集群功能,3.0 下的集群没有中心节点,RedisCluster 将所有的key映射到16385个slot中,每一个redis实例负责一部分最少三个实例一个集群,业务程序通过任务一个redisCluster都可以访问所有的数据,如果数据不再这个节点,那么这个节点会引导客户端去对应节点获取信息,redisCluster的管理实通过节点之间的通讯完成,定期交互,定期更新
  • 每一个节点都可以配置一个从节点,集群中三个redisCluster某个挂了,从节点将顶替他的位置,,主从复制的功能 和单机的时候一直,所以叫他基于主从配置的redis集群。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AVL树(平衡二叉树)讲解,入门篇,适合新手观看

1.1 概念 平衡二叉树就是为了让二叉搜索树的平均查找长度更短,时间复杂度更靠近logN,如果一个二叉搜索树不平衡了就会出现图1情况,完全变成一个数组,时间复杂度也变为了O(N)。 平衡因子:平衡因子就是针对于树中某一结点&#xff…

读源码,对开发者重要吗?

.NET 5.0 Peview 2发布4月2日,微软发布了.NET 5.0 Preview 2,带来功能和性能方面的改进。这一版本包括.NET 5.0.0 Preview 2与.NET SDK 5.0.100 Preview 2。.NET 5是.NET Framework和.NET Core的未来,最终将成为一个统一平台,.NET…

Redis和DB数据一致性解决方案

问题出现原因 并发时候无法保证读写的先后顺序,如果删掉了缓存还没来得及写库,另外一个县城就多来读取,发现缓存为空就去读取数据库并且写入缓存,这时候缓存中就是脏数据如果先写库,在删除缓存前,写库的线…

数据结构堆的时间复杂度(最大堆,最小堆)

创建堆的方式有两种,一种是一边插入结点,一边调用堆的插入方法调整堆,这样的时间复杂度就是 O(NlogN),而第二种方式就把时间复杂度缩减到了O(N),它是采用先把结点插入好了,然后再来调整堆,并不是…

中国速度之二神山建设(3):有力的技术保障,基建世界里的云原生缩影 | IDCF DevOps案例研究...

内容来源:DevOps案例深度研究第4期 – 火神山雷神山 DevOps实践研究战队(本文只展示部分PPT及研究成果,全程视频请移步文末)本案例内容贡献者:赖泽薇、张扬、邓茜芸、韦一、刘德权、候利涛、冯利娟、常相宇、张力、韩丰…

Rx2.0后台开发分享

Rxjava2.x 微软的一个函数库,Rx是一个编程模型,模板是提供一致的编程接口,帮助开发者更方便的处理异步数据流,现在Rx已经支持几乎全部的流行编程语言。比较流行的有Rxjava,RxJs,Rx.NET,社区网站…

中国速度之二神山建设(4):全能运维,召之即来,来之即战 | IDCF DevOps案例研究...

内容来源:DevOps案例深度研究第4期 – 火神山雷神山 DevOps实践研究战队(本文只展示部分PPT及研究成果,全程视频请移步文末)本案例内容贡献者:赖泽薇、张扬、邓茜芸、韦一、刘德权、候利涛、冯利娟、常相宇、张力、韩丰…

JAVA两类比较器的区别(Comparable,Comparator)

内部比较器Comparable 一个类实现了Comparable接口,那么它就有了一个内部比较器,实现了Comparable的类可以调用Collections工具类或Arrays的sort方法进行比较 外部比较器Comparator 一个类实现了Comparator接口,那么它就是一个外部比较器&…

Spring Cloud部分源码分析Eureka,Ribbon,Feign,Zuul

Eureka SpringCloud Eureka使用NetFlix Eureka来实现的,它包括了服务端组件和客户端组件,并且都是用java 编写的。 Eureka服务端就是服务注册中心,Eureka客户端主要处理服务的注册发现,通过注解和参数配置的方式,客户…

C++ class实现邻接表存储的图(完整代码)

代码如下: #include <iostream> #include <queue>using namespace std; const int MaxVertexNum 30; typedef int InfoType; typedef int VertexType;class Node {friend class VNode;friend class ALGraph; private:int adjvertex;InfoType info;Node *next; };…

世界上首个被数学证明安全的OS微内核seL4成立基金会

Linux 基金会正在与澳大利亚国家科学机构 CSIRO 合作&#xff0c;打造 seL4 操作系统微内核生态。近日 Linux 基金会宣布托管 seL4 基金会&#xff0c;该基金会以澳大利亚国家科学机构 CSIRO 的数字机构 Data61 创建的 seL4 操作系统微内核为基础项目。seL4 是一个安全操作系统…

数据结构(哈夫曼树,哈夫曼编码)入门篇,JAVA实现

什么是哈夫曼树 哈夫曼树就是一种最优判定树&#xff0c;举个例子&#xff0c;如下一个判断逻辑 if(s<60) g1; else if(s<70) g2 else if(s<80) g3 else if(s<90) g4 else g5; 分数概率图如下 如果按照代码从上到下顺序构造判定树&#xff0c;那么如下图所示&am…

C++ class实现十字链表存储的图(完整代码)

代码如下: #include <iostream> #include <queue> using namespace std; typedef int InfoType; typedef int VertexType; const int MaxVertexNum 30;class ArcNode {friend class OLGraph;friend class VertexNode; private:int tailvertex, headvertex;ArcNod…

hystrix隔离策略对比

hystrix隔离策略 zuul的隔离实现是基于hystrix实现的&#xff0c;hystrix支持线程池隔离和信号量的隔离 # 信号量隔离&#xff1a; it executes on the calling thread and concurrent requests are limited by the semaphore count --引自官网单每次调用线程&#xff0c;当…

中国速度之二神山建设(1):坚强的领导核心,“小团队大后台”组织结构 | IDCF DevOps案例研究...

内容来源&#xff1a;DevOps案例深度研究第4期 – 火神山雷神山 DevOps实践研究战队&#xff08;本文只展示部分PPT及研究成果&#xff0c;全程视频请移步文末&#xff09;本案例内容贡献者&#xff1a;赖泽薇、张扬、邓茜芸、韦一、刘德权、候利涛、冯利娟、常相宇、张力、韩丰…

通过Java编写一个服务器理解动态Web,静态Web

静态Web 说到Servlet自然就要说到Web,Web分为静态Web和动态Web&#xff0c;之前我一直都傻傻分不清两者的区别&#xff0c;直到用JAVA编写了一个服务器后才明白二者的区别&#xff0c;所谓静态Web&#xff0c;实际上就是指&#xff0c;客户端要请求的资源文件&#xff0c;服务器…

Hystrix在网关Zuul使用中遇到问题

Hystrix在网关Zuul使用中遇到问题 Zuul默认隔离策略级别是信号量隔离&#xff0c;默认最大隔离信号量是100 信号量隔离和线程隔离的区别&#xff1a;https://blog.csdn.net/liaojiamin0102/article/details/94394956默认的设置如源码&#xff1a; //在ZuulProperties 类下游…

C++ 实现无向图的最小生成树Prim算法(附完整代码)

实现Prim算法&#xff0c;需设置两个辅助一维数组lowcost和closevertex。 其中lowcost用来保存集合V-U中各顶点与集合U中各顶点构成的边中具有最小权值的边的权值&#xff1b;数组closevertex用来保存依附于该边的在集合U中的顶点。 过程: 假设初始状态时&#xff0c;U{u0}&a…

中国速度之二神山建设(2):完善的项目计划,高效能价值流 | IDCF DevOps案例研究...

内容来源&#xff1a;DevOps案例深度研究第4期 – 火神山雷神山 DevOps实践研究战队&#xff08;本文只展示部分PPT及研究成果&#xff0c;全程视频请移步文末。&#xff09;本案例内容贡献者&#xff1a;赖泽薇、张扬、邓茜芸、韦一、刘德权、候利涛、冯利娟、常相宇、张力、韩…

C++ 实现无向图的最小生成树Kruskal算法(完整代码)

按照Kruskal思想&#xff0c;n个结点的生成树有n-1条边&#xff0c;故反复上述过程&#xff0c;直到选取了n-1条边为止&#xff0c;就构成了一棵最小生成树。 实现Kruskal算法的关键问题是&#xff1a; 当一条边加入T的边集中后&#xff0c;如何判断是否构成回路。 一种解决方…