Redis 存储方案

Redis

RedisPersistence(持久化存储)

Redis提供了不同的持久化方案

  • TheRDB(方案):定期对内存中的数据进行快照,永久存储快照。

  • theAOF(方案):每个修改操作记录在日志中,服务器重启时,根据日志重新构造数据集。

  • 禁止持久化存储,数据全部存在内存中。

  • AOFRDB方案可以结合在一起。

2、分布式控制

目前只支持Master-replication,一个Master用于写,多个Slave用于读。也没有负载均衡,读写分离需要靠客户端显示设置。

Master-replication方案不同的是,Jedis客户端支持一种一致性哈希可以把key-value均匀分布到不同的server上。这种方案有些缺点:1不能使用事务,流水线,pub/sub2,不能动态增加,减少服务器。


3
、代码量

Redissource code is not very big (just 20k lines of code for the 2.2release)


附录一:Redis 永久化存储方案介绍。


以下是不同存储方案的详细介绍,大部分没来的及翻译,主要是一些细节问题。


RDB方案的优点(db代表database?)

YoucanconfigureRedistohaveitsavethedataseteveryNsecondsifthereareatleastMchangesinthedataset,oryoucanmanuallycalltheSAVEorBGSAVEcommands.

For example,this configuration will make Redis automatically dump the dataset todisk every 60 seconds if at least 1000 keys changed:

save 60 1000


  • 压缩的,单文件格式。

  • 易于做数据备份ForinstanceyoumaywanttoarchiveyourRDBfileseveryhourforthelatest24hours,andtosaveanRDBsnapshoteverydayfor30days.Thisallowsyoutoeasilyrestoredifferentversionsofthedatasetincaseofdisasters.

  • RDB文件易于进行故障转移:RDBisverygoodfordisasterrecovery,beingasinglecompactfilecanbetransferedtofardatacenters,oronAmazonS3(possiblyencrypted).

  • RDB方案最大的提升了Redis的性能。父进程fork子进程进行数据的永久性存储。父进程不进行磁盘I/O

  • RDB相比AOF来说,可以使服务器快速重启。

RDB的缺点

  • 会引起数据丢失,因为快照不是实时的。

  • RDB needs tofork() often in order to persist on disk using a child process.Fork() can be time consuming if the dataset is big, and may resultin Redis to stop serving clients for some millisecond or even forone second if the dataset is very big and the CPU performance notgreat.

AOF优点aof代表append-only-file)

  • AOF不同的日志同步方案,可以是数据durable(不知道怎么翻译):

Howdurableistheappendonlyfile?(同步日志文件)

YoucanconfigurehowmanytimesRediswillfsyncdataondisk.Therearethreeoptions:

fsynceverytimeanewcommandisappendedtotheAOF.Veryveryslow,verysafe.(数据不丢失)

Fsynceverysecond.Fastenough(in2.4likelytobeasfastassnapshotting),andyoucanlose1secondofdataifthereisadisaster.(推荐)(最多丢失1s内的数据)

Neverfsync,justputyourdatainthehandsoftheOperatingSystem.Thefasterandlesssafemethod.(不同步日志,数据的同步完全交由OS控制)


  • TheAOFlogisanappendonlylog,sotherearenoseeks,norcorruptionproblemsifthereisapoweroutage.Evenifthelogendswithanhalf-writtencommandforsomereason(diskfullorotherreasons)theredis-check-aoftoolisabletofixiteasily.(append-only格式的日志具有优势).

  • RedisisabletoautomaticallyrewritetheAOFinbackgroundwhenitgetstoobig.TherewriteiscompletelysafeaswhileRediscontinuesappendingtotheoldfile,acompletelynewoneisproducedwiththeminimalsetofoperationsneededtocreatethecurrentdataset,andoncethissecondfileisreadyRedisswitchesthetwoandstartsappendingtothenewone.(可以对太大的日志中的操作进行等价合并重写,生成一个较小的日志)

  • AOFcontainsalogofalltheoperationsoneaftertheotherinaneasytounderstandandparseformat.YoucaneveneasilyexportanAOFfile.ForinstanceevenifyouflushedeverythingforanerrorusingaFLUSHALLcommand,ifnorewriteofthelogwasperformedinthemeantimeyoucanstillsaveyourdatasetjuststoppingtheserver,removingthelatestcommand,andrestartingRedisagain.(不会引起数据不一致)

AOFdisadvantages

  • AOFfilesareusuallybiggerthantheequivalentRDBfilesforthesamedataset.(没有压缩,大量日志信息)

  • AOF通常比RDB方案要慢。

  • In the pastwe experienced rare bugs in specific commands (for instance therewas one involving blocking commands like BRPOPLPUSH) causing the AOFproduced to don't reproduce exactly the same dataset on reloading.This bugs are rare and we have tests in the test suite creatingrandom complex datasets automatically and reloading them to checkeverything is ok, but this kind of bugs are almost impossible withRDB persistence. To make this point more clear: the Redis AOF worksincrementally updating an existing state, like MySQL or MongoDBdoes, while the RDB snapshotting creates everything from scratchagain and again, that is conceptually more robust. However 1) Itshould be noted that every time the AOF is rewritten by Redis it isrecreated from scratch starting from the actual data contained inthe data set, making resistance to bugs stronger compared to analways appending AOF file (or one rewritten reading the old AOFinstead of reading the data in memory). 2) We never had a singlereport from users about an AOF corruption that was detected in thereal world.

Ok,so what should I use?

There aremany users using AOF alone, but we discourage it since to have an RDBsnapshot from time to time is a great idea for doing databasebackups, for faster restarts, and in the event of bugs in the AOFengine.

Whatshould I do if my AOF gets corrupted?

It ispossible that the server crashes while writing the AOF file (thisstill should never lead to inconsistencies), corrupting the file in away that is no longer loadable by Redis. When this happens you canfix this problem using the following procedure:

  • Make abackup copy of your AOF file.

  • Fixtheoriginalfileusingtheredis-check-aoftoolthatshipswithRedis:

$ redis-check-aof --fix <filename>
  • Optionallyusediff-utocheckwhatisthedifferencebetweentwofiles.

  • Restart theserver with the fixed file.

HowI can switch to AOF, if I'm currently using dump.rdb snapshots?

Interactionsbetween AOF and RDB persistence

Redis >=2.4 makes sure to avoid triggering an AOF rewrite when an RDBsnapshotting operation is already in progress, or allowing a BGSAVEwhile the the AOF rewrite is in progress. This prevents two Redisbackground processes from doing heavy disk I/O at the same time.

Whensnapshotting is in progress and the user explicitly requests a logrewrite operation using BGREWRITEAOF the server will reply with an OKstatus code telling the user the operation is scheduled, and therewirte will start once the snapshotting is completed.

In the caseboth AOF and RDB persistence are enabled and Redis restarts the AOFfile will be used to reconstruct the original dataset since it isguaranteed to be the most complete.

Backingup Redis data

Beforestartingthissection,makesuretoreadthefollowingsentence: MakeSuretoBackupYourDatabase.Disksbreak,instancesintheclouddisappear,andsoforth:nobackupsmeanshugeriskofdatadisappearinginto/dev/null.

Redis is verydata backup friendly since you can copy RDB files while the databaseis running: the RDB is never modified once produced, and while itgets produced it uses a temporary name and is renamed into its finaldestination atomically using rename(2) only when the new snapshot iscomplete.

This meansthat copying the RDB file is completely safe while the server isrunning. This is what we suggest:

  • Create acron job in your server creating hourly snapshots of the RDB file inone directory, and daily snapshots in a different directory.

  • Everytimethecronscriptruns,makesuretocallthe find commandtomakesuretoooldsnapshotsaredeleted:forinstanceyoucantakehourlysnapshotsforthelatest48hours,anddailysnapshotsforoneortwomonths.Makesuretonamethesnapshotswithdataandtimeinformation.

  • AtleastonetimeeverydaymakesuretotransferanRDBsnapshot outsideyourdatacenter oratleastoutsidethephysicalmachinerunningyourRedisinstance.

Disasterrecovery

RDB恢复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。

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







发布了29 篇原创文章 · 获赞 4 · 访问量 9万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章