zoukankan      html  css  js  c++  java
  • Redis数据类型,持久化,回收策略

           缓存:第一种是内存缓存 比如Map(简单的数据结构),以及EH Cache(Java第三方库),第二种是缓存组件比如Memached,Redis;Redis(remote dictionary server)是一个基于KEY-VALUE的高性能的存储系统,通过提供多种键值数据类型来适应不同场景下的缓存与存储需求。

           Redis官网下载链接:https://redis.io/download (备注Redis约定版本号(第一个小数点后的数字)为偶数,是稳定版,反之)

           1.Redis五种数据类型

             string类型:字符串类型是redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据。你可以用它存储用户的 邮箱、json化的对象甚至是图片。一个字符类型键允许存储的最大容量是512M 。在Redis内部,String类型通过 int、SDS(simple dynamic string)作为结构存储,int用来存放整型数据,sds存放字节/字符串和浮点型数据。在C的标准字符串结构下进行了封装,用来提升基本操作的性能,同时也充分利用已有的C的标准库,简化实现逻辑。

              list类型:    可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素或者获得列表的某一个片段。 列表类型内部使用双向链表实现,所以向列表两端添加元素的时间复杂度为O(1), 获取越接近两端的元素速度就越 快。这意味着即使是一个有几千万个元素的列表,获取头部或尾部的10条记录也是很快的。

             hash类型:  可以看做一个对象,每一个field-value相当于属性和属性值,类似这种数据类型 Map<Object,Map<Object,Object>>。

             set类型:    每个元素都是不同的,也就是不能有重复数据,同时集合类型中的数据是无序的。一个集合类型键可以存储至多232-1个 。集合类型和列表类型的最大的区别是有序性和唯一性 集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在。由于集合类型在redis内部是使用的值 为空的散列表(hash table),所以这些操作的时间复杂度都是O(1)。

             zset有序集合类型:在集合类型的基础上,有序集合类型为集合中的每个元素都关联了一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能获得分数最高(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是他们的分数却可以相同。

         Redis数据结构底层分析:https://mp.weixin.qq.com/s/3TU9qxHJyxHJgVDaYXoluA

         

         Redis发布订阅:Redis提供了发布订阅功能,可以用于消息的传输,这个功能比较鸡肋,即使有这样的业务场景也会选择消息中间件(MQ)来处理。

         2.Redis数据持久化:RDB方式和AOF方式

          RDB方式:Redis借助了fork命令的copy on write机制。在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有的数据,将数据写成RDB文件。Redis的RDB文件不会坏掉,因为写操作是在一个新进程中进行的,Redis先将数据写到一个临时文件中,通过原子性rename系统调用将临时文件重命名为RDB文件 ,即使出现故障,最后一个保存的RDB文件也是可用的,同时,Redis的RDB文件也是Redis主从同步内部实现中的一环。通过Redis的save指令来配置RDB快照生成的时机,比如你可以配置当10分钟以内有100次写入就生成快照,也可以配置当1小时内有1000次写入就生成快照,也可以多个规则一起实施,下面是默认配置:

          Redis还提供了人工干预RDB快照的方式

          用户执行SAVE或BGSAVE命令 除了让Redis自动进行快照以外,当我们对服务进行重启或者服务器迁移我们需要人工去干预备份。

          save命令:当执行save命令时,Redis同步做快照操作,在快照执行过程中会阻塞所有来自客户端的请求。当redis内存中的数据较多时,通过该命令将导致Redis较长时间的不响应。所以不建议在生产环境上        使用这个命令,而是推荐使用bgsave命令。

          bgsave命令:可以在后台异步地进行快照操作,快照的同时服务器还可以继续响应来自客户端的请求。执行BGSAVE后,Redis会立即返回ok表示开始执行快照操作。(默认快照方式)。

          LASTSAVE命令:可以获取最近一次成功执行快照的时间。

          RDB方式缺点:RDB有它的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到 Redis停机这段时间的数据全部丢掉了。在某些业务下,这是可以忍受的,我们也推荐这些业务使用RDB的方式进行持久化,因为开启RDB的代价并不高。 但是对于另外一些对数据安全性要求极高的应用,无法容忍数据丢失的应用,RDB就无能为力了,所以Redis引入了另一个重要的持久化机制:AOF日志。

          AOF方式:AOF日志的全称是Append Only File,从名字上我们就能看出来,它是一个追加写入的日志文件。与一般数据库不同的是,AOF文件是可识别的纯文本,它的内容就是一个个的Redis标准命令。AOF可以将Redis执行的每一条写命令追加到硬盘文件中,这一过程会降低Redis的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。

    下面是redis.conf里面的默认配置:

      开启AOF方式为:appendonly yes 即可。

            AOF重写: 你可能会想,每一条写命令都生成一条日志,那么AOF文件是不是会很大?答案是肯定的,AOF文件会越来越大,所以Redis又提供了一个功能,叫做AOF rewrite。其功能就是重新生成一份AOF文件,新的AOF文件中一条记录的操作只会有一次,而不像一份老文件那样,可能记录了对同一个值的多次操作。其生成过程和RDB类似,也是fork一个进程,直接遍历数据,写入新的AOF临时文件。在写入新文件的过程中,所有的写操作日志还是会写到原来老的 AOF文件中,同时还会记录在内存缓冲区中。当重完操作完成后,会将所有缓冲区中的日志一次性写入到临时文件中。然后调用原子性的rename命令用新的 AOF文件取代老的AOF文件。

    Redis中对AOF调用write写入后,何时再调用fsync将其写到磁盘上,通过appendfsync选项来控制,下面appendfsync的三个设置项,安全强度逐渐变强。

            appendfsync no:当设置appendfsync为no的时候,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上。

            appendfsync everysec:当设置appendfsync为everysec的时候,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。但是当这一 次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞,所以当前的写操作就会阻塞。所以,结论就是:在绝大多数情况下,Redis会每隔一秒进行一次fsync。在最坏的情况下,两秒钟会进行一次fsync操作。这一操作在大多数数据库系统中被称为group commit,就是组合多次写操作的数据,一次性将日志写到磁盘。

            appednfsync always:当设置appendfsync为always时,每一次写操作都会调用一次fsync,这时数据是最安全的,当然,由于每次都会执行fsync,所以其性能也会受到影响。

    Redis 的pipeline的操作,其具体过程是客户端一次性发送N个命令,然后等待这N个命令的返回结果被一起返回。通过采用pipilining 就意味着放弃了对每一个命令的返回值确认。由于在这种情况下,N个命令是在同一个执行过程中执行的。所以当设置appendfsync为everysec 时,可能会有一些偏差,因为这N个命令可能执行时间超过1秒甚至2秒。但是可以保证的是,最长时间不会超过这N个命令的执行时间和。

    利用RDB和AOF启动上区别:启动时间有一些差别。RDB的启动时间会更短,原因有两个,一是RDB文件中每一条数据只有一条记录,不会像 AOF日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。另一个原因是RDB文件的存储格式和Redis数据在内存中的编码格式是一致的,不需要再进行数据编码工作。在CPU消耗上要远小于AOF日志的加载。

     

    3.Redis过期时间设置和内存回收策略          

            过期时间设置:expire命令设置一个键的过期时间,到期以后Redis会自动删除它。这个在我们实际使用过程中用 得非常多。具体用法EXPIRE key seconds,EXPIRE 返回值为1表示设置成功,0表示设置失败或者键不存在,TTL key 当键不存在时,TTL命令会返回-2

           定期删除(active way): 周期性地从设置了失效时间的主键中选择一部分失效的主键删除,对于那些从未被查询的key,即便它们已经过期,被动方式也无法清除。因此Redis会周期性地随机测试一些key,已过期的key将会被删掉。Redis每秒会进行10次操作,具体的流程:1.随机测试 20 个带有timeout信息的key;2.删除其中已经过期的key;3.如果超过25%的key被删除,则重复执行步骤。

           惰性删除(passive way): 在主键被访问时如果发现它已经失效,那么就删除它。

          采用定期删除+惰性删除就万事大吉吗?不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。在redis.conf中有一行配置 # maxmemory-policy volatile-lru

     

          Redis中提供了多种内存回收策略,当内存容量不足时,为了保证程序的运行,这时就不得不淘汰内存中的一些对 象,释放这些对象占用的空间,那么选择淘汰哪些对象呢? 其中,默认的策略为noeviction策略(maxmemory-policy        noeviction ),当内存使用达到阈值的时候,所有引起申请内存的命令会报错 还有allkeys-random,volatile-random,volatile-lru,volatile-ttl。归纳如下

     

           

  • 相关阅读:
    The Future of Middleware and the BizTalk Roadmap
    FW: How to spawn a process that runs under the context of the impersonated user in Microsoft ASP.NET pages
    Strips illegal Xml characters
    luogu P2280 激光炸弹(二维前缀和)
    luogu P2704 炮兵阵地(经典状态压缩DP)
    SP1716 GSS3 Can you answer these queries III (线段树维护最大连续子段和)
    二分图判定、匹配问题
    C++语法综合 | 基于char*设计一个字符串类MyString
    luogu P1044 火车进出栈问题(Catalan数)
    C++设计模式 | 三种设计模式基础
  • 原文地址:https://www.cnblogs.com/dyg0826/p/11082930.html
Copyright © 2011-2022 走看看