`
zl198751
  • 浏览: 278761 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

对redis数据持久化的一些想法

阅读更多

数据持久化通俗讲就是把数据保存到磁盘上,保证不会因为断电等因素丢失数据。

redis需要经常将内存中的数据同步到磁盘来保证持久化。redis支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另一种是Append-only file(缩写aof)的方式。先介绍下这两种dump方式再讲讲自己遇到的一些现象和想法,前面的内容是从网上整理出来的。

Snapshotting
快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久 化的方式。我们可以配置redis在n秒内如果超过m个key被修改就自动做快照,下面是默认的快照保存配置

save 900 1  #900秒内如果超过1个key被修改,则发起快照保存
save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
save 60 10000

下面介绍详细的快照保存过程

1.redis调用fork,现在有了子进程和父进程。

2. 父进程继续处理client请求,子进程负责将内存内容写入到临时文件。由于os的写时复制机制(copy on write)父子进程会共享相同的物理页面,当父进程处理写请求时os会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程的地址空间内的数 据是fork时刻整个数据库的一个快照。

3.当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。

client 也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主线程中保存快照的,由于redis是用一个主线程来处理所有 client的请求,这种方式会阻塞所有client请求。所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不 是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,可能会严重影响性能。

另外由于快照方式是在一定间隔时间做一次的,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用aof持久化方式。下面介绍

Append-only file

aof 比快照方式有更好的持久化性,是由于在使用aof持久化方式时,redis会将每一个收到的写命令都通过write函数追加到文件中(默认是 appendonly.aof)。当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。当然由于os会在内核中缓存 write做的修改,所以可能不是立即写到磁盘上。这样aof方式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置文件告诉redis我们想要 通过fsync函数强制os写入到磁盘的时机。有三种方式如下(默认是:每秒fsync一次)

appendonly yes              //启用aof持久化方式
# appendfsync always      //每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
appendfsync everysec     //每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
# appendfsync no    //完全依赖os,性能最好,持久化没保证

aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件。redis提供了bgrewriteaof命令。收到此命令redis将使用与快照类似的方式将内存中的数据 以命令的方式保存到临时文件中,最后替换原来的文件。具体过程如下

1. redis调用fork ,现在有父子两个进程
2. 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
3.父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。
4.当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
5.现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。

需要注意到是重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。

运维上的想法

其实快照和aof一样,都使用了Copy-on-write技术。多次试验发现每次做数据dump的时候,内存都会扩大一倍(关于这个问题可以参考我去年写的redis的内存陷阱 ,很多人用redis做为缓存,数据量小,dump耗时非常短暂,所以不太容易发现),这个时候会有三种情况:

一:物理内存足以满足,这个时候dump非常快,性能最好

二:物理内存+虚拟内存可以满足,这个时候dump速度会比较慢,磁盘swap繁忙,服务性能也会下降。所幸的是经过一段比较长的时候数据dump完成了,然后内存恢复正常。这个情况系统稳定性差。

三: 物理内存+虚拟内存不能满足,这个时候dump一直死着,时间久了机器挂掉。这个情况就是灾难!

如果数据要做持久化又想保证稳定性,建议留空一半的物理内存。如果觉得无法接受还是有办法,下面讲:

快照和aof虽然都使用Copy-on-write,但有个不同点,快照你无法预测redis什么时候做dump,aof可以通过bgrewriteaof命令控制dump的时机。

根据这点我可以在一个服务器上开启多个redis节点(利用多CPU),使用aof的持久化方式。

例如在24G内存的服务器上开启3个节点,每天用bgrewriteaof定期重新整理数据,每个节点dump的时间都不一样,这 样理论上每个节点可以消耗6G内存,一共使用18G内存,另外6G内存在单个节点dump时用到,内存一下多利用了6G! 当然节点开的越多内存的利用率也越高。如果带宽不是问题,节点数建议 = CPU数。

我的应用里为了保证高性能,数据没有做dump,也没有用aof。因为不做dump发生的故障远远低于做dump的时候,即使数据丢失了,自动修复脚本可以马上数据恢复。毕竟对海量数据redis只能做数据分片,那么落到每个节点上的数据量也不会很多。

redis的虚拟内存建议也不要用,用redis本来就是为了达到变态的性能,虚拟内存、aof看起来都有些鸡肋。

现在还离不开redis,因为它的mget是现在所有db里性能最好的,以前也考虑过用tokyocabinet hash方式做mget,性能不给力。直接用redis,基本上单个redis节点mget可以达到10W/s

纠错

之前说过redis做数据dump的时候内容会扩大一倍,后来我又做了些测试,发现有些地方说的不对。

top命令并不是反映真实的内存占用情况,在top里尽管fork出来的子进程占了和父进程一样的内存,但是当做dump的时候没有写操作,实际使 用的是同一份内存的数据。当有写操作的时候内存才会真实的扩大(具体是不是真实的扩大一倍不确定,可能数据是按照页分片的),这才是真正的Copy- on-write。

基于这点在做数据持久化会更加灵活。

分享到:
评论

相关推荐

    疫情校园访客系统 功能1访客访问 2学生访问 3疫情信息登记 4信息发布 5信息评论 springboot+redis+mysq

    - **Redis**:作为内存数据存储,Redis用于缓存频繁访问的数据,减少数据库的读写压力,提高系统响应速度。例如,它可以存储登录状态、热门信息等。 - **MySQL**:作为关系型数据库管理系统,MySQL用于存储系统的...

    Nginx安装包

    与一般数据库不同,redis是使用内存作为主存,而使用硬盘来实现数据持久化,而且redis是周期性的将数据写到硬盘上。这就意味着一旦我们服务器出现断电、重启之类的情况,我们很可能会出现数据丢失的情况,所以不建议...

    duratom:Clojure的持久原子类型

    内置的后端是: 本地文件系统上的文件Postgres DB表行一个AWS-S3存储桶密钥Redis DB密钥(*) (**) 注意:从“和“获得/适应/结合的一些想法之间的主要区别duratom & enduro是一个enduro原子不是直接替代定期...

    个人博客系统

    5. **数据持久化**:使用Hibernate,需要设计数据库表结构,如用户表、文章表、评论表和留言表,然后将Java对象映射到这些表,实现数据的持久化存储。 6. **前端展示**:HTML、CSS和JavaScript构成了前端界面,使用...

    jsp多媒体博客系统 sqlserver

    在这个博客系统中,SQLServer用于存储用户信息、博客文章、评论等数据,确保数据的持久化和一致性。 3. **Tomcat**:Tomcat是一个开源的Servlet容器,它实现了Java EE中的Web应用服务部分,尤其是Servlet和JSP规范...

    基于SpringBoot的博客系统设计与实现.docx

    系统采用SpringBoot作为核心开发框架,结合Mybatis作为持久层框架,实现数据的CRUD操作。SpringBoot的自动配置特性大大减少了初始化工作,而Mybatis则提供了灵活的SQL查询,两者结合使得数据操作更为便捷。 1.3.2 ...

    ssm个人博客网站(源码+数据库)051539

    4. **Redis**:作为缓存数据库,Redis用于提升数据读取速度,比如存储用户的会话信息或者热门博客等。 5. **MyBatis**:MyBatis是持久层框架,负责将Java对象与SQL语句映射,简化了数据库操作。 在“CS942120_...

    N-Layer-Architecture-Typescript:在N层体系结构上进行尝试,以支持将所有事物解耦到我们可以轻松在技术之间交换的点的想法

    -核心->数据数据这一层都是关于持久化数据的。 无论它是使用Redis进行缓存,具有模拟的内存数据库,还是orm,odm ...都属于此处。 您应该非常清楚,数据取决于Core 。核核心层是发生所有与业务相关的事情的地方。 它...

    数字化校园整体解决方案共40页.ppt

    技术栈主要基于Web容器(如Apache Tomcat、WebLogic)、Spring MVC、SOA框架等,持久层使用Mybatis、Hibernate,数据层涉及Oracle、MySQL、SQL Server等多种数据库,以及NoSQL数据库如MongoDB、Redis和消息队列系统...

    基于JavaEE的快速开发框架

    dao——持久化模块。 ctrl——控制层模块。 ctrl-http——HTTP(S)模块。 ctrl-socket——Socket模块。 script——脚本(JavaScript)模块。 wormhole——Wormhole访问支持。 carousel——Carousel访问支持。 hadoop...

    基于springboot的cosplay网站的设计与实现.doc

    6. **Redis缓存**:Redis作为一个高性能的键值存储系统,用于缓存频繁访问的数据,提高网站的访问速度和用户体验。 7. **RESTful API**:前后端交互采用RESTful风格的JSON格式接口,这种设计模式使接口清晰、简洁,...

    java面试题综合

    持久化可以选择Cookie、Session或数据库。 2. 分布式处理:涉及分布式计算、负载均衡、分布式缓存(如Redis或Memcached)以及分布式事务管理(如2PC或补偿事务)。 3. 数据库版本:关注数据库管理系统(DBMS)的...

    express-it:为您的Express应用服务定制翻译变体

    redis :用于将持久性翻译存储在内存中。目的如果您曾经想根据不同的场合向用户提供不同的消息副本,那么这是正确的工具。 该工具也可以用作i18n (国际化)的轻量级解决方案,但是请注意,该项目的范围并非旨在...

Global site tag (gtag.js) - Google Analytics