设为首页 收藏本站
查看: 529|回复: 0

[经验分享] 认识缓存之redis【2】特点结构

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2016-12-19 08:56:51 | 显示全部楼层 |阅读模式
一、redis持久化
    redis是基于内存的数据库,内存数据库有个严重的弊端;突然宕机或者断电时,内存的数据不会保存。为了解决这个问题,redis提供了两种持久化方式:内存快照(Snapshotting)和日志追加(Append-only file)。
1、内存快照
    内存快照方式是将内存中的数据以快照方式写入二进制文件中,默认文件名为dump.rdb。
    redis每隔一段时间进行一次内存快照操作,客户端使用save或者bgsave命令告诉redis要做一次内存快照操作。save命令在主线程中保存内存快照,redis由单线程处理所有请求,执行save命令可能阻塞其他客户端请求,从而导致不能快速响应请求,所以不建议不要使用save命令。另外要注意,内存快照每次都把内存数据完整的写入硬盘,而不是只写入增量数据。所以如果数据量大,写入操作比较频繁,从而严重影响性能。
    与内存快照相关的配置选项如下:save <seconds> <changes>。该配置表示经过seconds秒或者数据更改changes次进行一次内存快照操作。
2、日志追加
    日志追加(aof)方式是把增加、修改数据的命令通过write函数追加到文件尾部(默认是appendonly.aof)。redis重启时读取appendonly.aof文件中的所有命令并且执行,从而把数据写入内存中。
    另外操作系统内核的I/O接口可能存在缓存,所以日志追加方式不可能立即写入文件中,这样就有可能丢失部分数据。幸运的是redis提供了解决方法,通过修改配置文件告诉redis应该在什么时候使用fsync函数强制操作系统把缓存吸入磁盘。有以下三种方法:


  • appendonly yes   #启动日志追加持久化方式(yes|no)
  • #appendfsync always   #每次收到增加或者修改命令就立刻强制写入磁盘
  • appendfync everysec    #每秒强制写入磁盘一次
  • #appendfsync no          #是否写入磁盘完全依赖操作系统
  日志追加方式有效降低数据丢失的风险,同时也带来另一个问题,即持久化文件不断膨胀。为了压缩日志文件,redis提供了bgrewriteaof命令。当redis收到此命令,就使用类似内存快照方式将内存的数据以命令的方式保存到临时文件中,最后替换原来的日志文件。
二、虚拟内存
    redis的数据保存在内存中,可能出现物理内存不足的情况。物理内存不足时,redis使用“虚拟内存”(VM)解决该问题。
    VM是redis2.0新增功能。之前,redis把数据库中所有数据存放在内存中。随着redis的不断运行,使用的内存会越来越大,最终导致内存不足的情况。redis的VM与操作系统的VM相似,把很少访问的value保存到磁盘中。与此同时,redis把value对应的key都放在内存中,为了能够让redis快速定位被换出的value所在磁盘位置,从而将其导入内存中。
1、redis自己设计VM的原因


  • 操作系统VM是基于页的概念,比如linux系统中每个页是4kB,而redis大多数对象远小于4KB,一页上可能有多个redis对象。另外redis的集合对象类型如list、Set可能存在于多个页上。故redis自己实现可达到控制转入粒度。
  • redis将交换到磁盘的对象压缩,保存到磁盘的对象可以去除指针和对象元数据信息。一般压缩后的对象比内存中的对象小10倍,这样redis的VM比操作系统的VM少做很多I/O操作。
  2、配置文件信息
  要使用VM,在配置文件中开启相关的配置项:

#开启VM功能
vm-enabled yes
#交换出来的value保存的文件路径/tmp/redis.swap
vm-swap-file /tmp/redis.swap
#redis使用的最大内存上限,超过上限后redis开始交换value到磁盘文件中
vm-max-memory  268435456
#设置每个页面的大小为32个字节
vm-page-size 32
#最多在文件中使用多少页面,swap文件的大小等于vm-page-size * vm-pages
vm-pages  134217728
#用于执行value对象换入换出的工作线程数量。0表示不使用工作线程
vm-max-threads 4
  redis的vm只把value交换到磁盘中,而key依然存储在内存中,目的是让开启vm的redis和完全使用内存的redis性能基本保持一致。如果由于太多key而造成内存不足的问题,redis的vm并不能解决。
  和操作系统一样,redis也按照页(page)交换对象。一页只能保存一个对象,但是一个对象可以保存在多个页中。
  当redis使用的内存没有超过设置的vm-max-memory之前,不把任何value交换到磁盘中;当超过最大内存限制后,redis根据以下算法寻找一个对象交换到磁盘中:swappability=age*log(size_in_memory);其中age代表这个对象距离上一次被访问的时间,size_in_memory是这个对象在内存中占用的空间大小。redis采取这个策略是把那些很少访问,而且占据内存又比较大的对象交换到磁盘中,但是第二个因素所占的权重更低,所以在公式中取log值。因为交换大对象时,需要占用更多的I/O和CPU资源。
  应该根据自己的应用设置vm-page-size,设置太大浪费磁盘空间,设置太小造成SWAP文件出现过多碎片。
  vm-max-threads表示用于交换任务的工作线程数量,建议不要将vm-max-threads设置为0,设置为0时交换过程在主线程进行,从而阻塞其他用户。但也不建议设置的越大越好,因为太多的工作线程会导致操作系统使用更多时间来切换线程,从而降低效率。推荐把vm-max-threads设置为服务器的CPU核心数。
  3、对象在swap中的存储
  swap文件中采用rdb文件的存储格式。swap文件被分割成固定数量的页,每页占用固定数量的字节空间。在redis.conf中根据自己业务需求配置一下两个参数:
  ①vm-page-size设置每页的大小,默认值为32.
  ②vm-pages设置能够使用的页数,默认值为134217728.
  redis在内存中保存一个bitmap以映射这些页是否被占用,每bit代表对应磁盘空间的页是否被使用。内存中保存这样一份映射表极大增强了redis性能,同时,对内存的使用有非常少。
  三、redis内存淘汰
  redis是一个内存数据库,当内存不足时,redis有两种处理方式:①启用虚拟内存:将vm-enabled配置项设置为yes; ②启用内存淘汰:将maxmemory配置项设置为一个大于0的整数。
  当redis使用的内存数大于可使用的最大内存数时,进行内存淘汰。redis的淘汰算法较丰富,主要有3种:①随机淘汰算法,从数据库中随机删除一个key;②LRU淘汰算法,从数据库中删除一个最近最少访问的key;③TTL淘汰算法,从数据库中删除一个最快过期的key。通过maxmemory-policy配置项指定使用的淘汰算法。
  四、对象引用计数器
  设想当一个客户端调用get获取一个较大的key时(不能通过一次网络I/O把数据传输完毕),另一个客户端调用del命令删除此key,如果此时没有对key进行任何保护,get操作就有可能导致内存错误(因为del操作已经把key从内存删除,而get操作还在进行,这样get操作就会访问到非法内存地址)。
  为了解决这个问题,redis使用对象引用计数器。原理是:给对象添加一个引用计数器,每当有地方引用它时,计数器值就加1,当引用失效时,计数器值就减1.当引用计数器为0时,redis便把此对象从内存中删除。
  这样当get操作尚未完成时,del命令不能够删除数据。等待get操作完成后,redis就把key的引用计数器减1.当所有的get操作完成后,此key的引用计数器将变为0,此时,redis就把这个key从内存中删除。
  五、自动关闭超时连接
  redis有自动关闭超时连接的功能,当有一个客户端连接在一定时间内不进行任何操作时,redis自动关闭它。因为redis只能处理有限的客户端连接,这个功能有效防止一些用户恶意占用连接。
  开启这个功能在配置文件中把timeout设置为大于0的参数,redis根据客户端最后一次操作时间,判断是否超过timeout配置时间,如果超过timeout配置时间,redis就关闭此连接。
  六、清除过期数据
  redis为每个存储的数据设置一个过期时间,当到达这个设置的过期时间后,redis便会把过期的数据从内存中删除。为了提高效率,redis使用一个HashTable存储数据的过期时间,把数据的key与过期时间相关联,这样就可以通过key来检查数据的过期时间了。
  redis并不会每时每刻去检查数据是否过期,因为这样效率太低。redis清除过期数据分两个阶段进行:第一个阶段在定时器中进行,在redis定时器中,每隔100毫秒进行一次清理过期数据的操作;第二个阶段在用户获取数据时进行,当用户使用get、hget命令获取数据时,redis会判断数据是否过期,如果过期,就从内存中删除。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-316196-1-1.html 上篇帖子: redis主从配置与sentinel配置 下篇帖子: redis 基本 接口
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表