redis数据类型与底层原理
Redis提供了RDB持久化和AOF持久化
RDB机制的优势和略施
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写⼊磁盘。
也是默认的持久化⽅式,这种⽅式是就是将内存中数据以快照的⽅式写⼊到⼆进制⽂件中,默认的⽂件名为dump.rdb。
可以通过配置设置⾃动做快照持久化的⽅式。我们可以配置redis在n秒内如果超过m个key被修改就⾃动做快照,下⾯是默认的快照保存配置
save 900 1 #900秒内如果超过1个key被修改,则发起快照保存
save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
save 60 10000
RDB⽂件保存过程
redis调⽤fork,现在有了⼦进程和⽗进程。
⽗进程继续处理client请求,⼦进程负责将内存内容写⼊到临时⽂件。由于os的写时复制机制(copy on write)⽗⼦进程会共享相同的物理页⾯,当⽗进程处理写请求时os会为⽗进程要修改的页⾯创建副本,⽽不是写共享的页⾯。所以⼦进程的地址空间内的数 据是fork时刻整个数据库的⼀个快照。
当⼦进程将快照写⼊临时⽂件完毕后,⽤临时⽂件替换原来的快照⽂件,然后⼦进程退出。
client 也可以使⽤save或者bgsave命令通知redis做⼀次快照持久化。save操作是在主线程中保存快照的,由于redis是⽤⼀个主线程来处理所有 client的请求,这种⽅式会阻塞所有client请求。所以不推荐使⽤。
另⼀点需要注意的是,每次快照持久化都是将内存数据完整写⼊到磁盘⼀次,并不 是增量的只同步脏数据。如果数据量⼤的话,⽽且写操作⽐较多,必然会引起⼤量的磁盘io操作,可能会严重影响性能。
优势
⼀旦采⽤该⽅式,那么你的整个Redis数据库将只包含⼀个⽂件,这样⾮常⽅便进⾏备份。⽐如你可能打算没1天归档⼀些数据。
⽅便备份,我们可以很容易的将⼀个⼀个RDB⽂件移动到其他的存储介质上
RDB 在恢复⼤数据集时的速度⽐ AOF 的恢复速度要快。
RDB 可以最⼤化 Redis 的性能:⽗进程在保存 RDB ⽂件时唯⼀要做的就是 fork 出⼀个⼦进程,然后这个⼦进程就会处理接下来的所有保存⼯作,⽗进程⽆须执⾏任何磁盘 I/O 操作。
劣势
如果你需要尽量避免在服务器故障时丢失数据,那么 RDB 不适合你。 虽然 Redis 允许你设置不同的保存点(save point)来控制保存 RDB ⽂件的频率, 但是, 因为RDB ⽂件需要保存整个数据集的状态, 所以它并不是⼀个轻松的操作。 因此你可能会⾄少 5 分钟才保存⼀次 RDB ⽂件。 在这种情况下, ⼀旦发⽣故障停机, 你就可能会丢失好⼏分钟的数据。
redis支持的五种数据类型每次保存 RDB 的时候,Redis 都要 fork() 出⼀个⼦进程,并由⼦进程来进⾏实际的持久化⼯作。 在数据集⽐较庞⼤时, fork() 可能会⾮常耗时,造成服务器在某某毫秒内停⽌处理客户端; 如果数据集⾮常巨⼤,并且 CPU 时间⾮常紧张的话,那么这种停⽌时间甚⾄可能会长达整整⼀秒。 虽然 AOF 重写也需要进⾏ fork() ,但⽆论 AOF 重写的执⾏间隔有多长,数据的耐久性都不会有任何损失。
AOF⽂件保存过程
redis会将每⼀个收到的写命令都通过write函数追加到⽂件中(默认是 appendonly.aof)。
当redis重启时会通过重新执⾏⽂件中保存的写命令来在内存中重建整个数据库的内容。当然由于os会在内核中缓存 write做的修改,所以可能不是⽴即写到磁盘上。这样aof⽅式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置⽂件告诉redis我们想要 通过fsync 函数强制os写⼊到磁盘的时机。有三种⽅式如下(默认是:每秒fsync⼀次)
appendonly yes //启⽤aof持久化⽅式
1
2
3
4
5
6
1
2
3
4
5
# appendfsync always //每次收到写命令就⽴即强制写⼊磁盘,最慢的,但是保证完全的持久化,不推荐使⽤ appendfsync
everysec //每秒钟强制写⼊磁盘⼀次,在性能和持久化⽅⾯做了很好的折中,推荐 # appendfsync no //完全依赖os,性能最好,持久化没保证
aof 的⽅式也同时带来了另⼀个问题。持久化⽂件会变的越来越⼤。例如我们调⽤incr test命令100次,⽂件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实⽂件中保存⼀条set test 100就够了。
为了压缩aof的持久化⽂件。redis提供了bgrewriteaof命令。收到此命令redis将使⽤与快照类似的⽅式将内存中的数据 以命令的⽅式保存到临时⽂件中,最后替换原来的⽂件。具体过程如下
redis调⽤fork ,现在有⽗⼦两个进程
⼦进程根据内存中的数据库快照,往临时⽂件中写⼊重建数据库状态的命令
⽗进程继续处理client请求,除了把写命令写⼊到原来的aof⽂件中。同时把收到的写命令缓存起来。这样就能保证如果⼦进程重写失败的话并不会出问题。
当⼦进程把快照内容写⼊已命令⽅式写到临时⽂件中后,⼦进程发信号通知⽗进程。然后⽗进程把缓存的写命令也写⼊到临时⽂件。
现在⽗进程可以使⽤临时⽂件替换⽼的aof⽂件,并重命名,后⾯收到的写命令也开始往新的aof⽂件中追加。
需要注意到是重写aof⽂件的操作,并没有读取旧的aof⽂件,⽽是将整个内存中的数据库内容⽤命令的⽅式重写了⼀个新的aof⽂件,这点和快照有点类似。
优势
使⽤ AOF 持久化会让 Redis 变得⾮常耐久(much more durable):你可以设置不同的 fsync 策略,⽐如⽆ fsync ,每秒钟⼀次fsync ,或者每次执⾏写⼊命令时 fsync 。 AOF 的默认策略为每秒钟 fsync ⼀次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发⽣故障停机,也最多只会丢失⼀秒钟的数据( fsync 会在后台线程执⾏,所以主线程可以继续努⼒地处理命令请求)。
AOF ⽂件是⼀个只进⾏追加操作的⽇志⽂件(append only log), 因此对 AOF ⽂件的写⼊不需要进⾏ seek , 即使⽇志因为某些原因⽽包含了未写⼊完整的命令(⽐如写⼊时磁盘已满,写⼊中途停机,等等), redis-check-aof ⼯具也可以轻易地修复这种问题。
Redis 可以在 AOF ⽂件体积变得过⼤时,⾃动地在后台对 AOF 进⾏重写: 重写后的新 AOF ⽂件包含了恢复当前数据集所需的最⼩命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF ⽂件的过程中,会继续将命令追加到现有的 AOF ⽂件⾥⾯,即使重写过程中发⽣停机,现有的 AOF ⽂件也不会丢失。 ⽽⼀旦新 AOF ⽂件创建完毕,Redis 就会从旧 AOF ⽂件切换到新 AOF ⽂件,并开始对新 AOF ⽂件进⾏追加操作。
AOF ⽂件有序地保存了对数据库执⾏的所有写⼊操作, 这些写⼊操作以 Redis 协议的格式保存, 因此 AOF ⽂件的内容⾮常容易被⼈读懂, 对⽂件进⾏分析(parse)也很轻松。 导出(export) AOF ⽂件也⾮常简单: 举个例⼦, 如果你不⼩⼼执⾏了
FLUSHALL 命令, 但只要 AOF ⽂件未被重写, 那么只要停⽌服务器, 移除 AOF ⽂件末尾的 FLUSHALL 命令, 并重启 Redis ,就可以将数据集恢复到 FLUSHALL 执⾏之前的状态。
劣势
对于相同的数据集来说,AOF ⽂件的体积通常要⼤于 RDB ⽂件的体积。
根据所使⽤的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在⼀般情况下, 每秒 fsync 的性能依然⾮常⾼, ⽽关闭 fsync 可以让AOF 的速度和 RDB ⼀样快, 即使在⾼负荷之下也是如此。 不过在处理巨⼤的写⼊载⼊时,RDB 可以提供更有保证的最⼤延迟时间(latency)。
AOF 在过去曾经发⽣过这样的 bug : 因为个别命令的原因,导致 AOF ⽂件在重新载⼊时,⽆法将数据集恢复成保存时的原样。
(举个例⼦,阻塞命令 BRPOPLPUSH 就曾经引起过这样的 bug 。) 测试套件⾥为这种情况添加了测试: 它们会⾃动⽣成随机的、复杂的数据集, 并通过重新载⼊这些数据来确保⼀切正常。 虽然这种 bug 在 AOF ⽂件中并不常见, 但是对⽐来说, RDB ⼏乎是不可能出现这种 bug 的。
抉择
⼀般来说, 如果想达到⾜以媲美 PostgreSQL 的数据安全性, 你应该同时使⽤两种持久化功能。
如果你⾮常关⼼你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使⽤ RDB 持久化。
其余情况我个⼈喜好选择AOF
Redis 数据类型
Redis⽀持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
String(字符串)
string 是 redis 最基本的类型,你可以理解成与 Memcached ⼀模⼀样的类型,⼀个 key 对应⼀个 value。
string 类型是⼆进制安全的。意思是 redis 的 string 可以包含任何数据。⽐如jpg图⽚或者序列化的对象。
string 类型是 Redis 最基本的数据类型,string 类型的值最⼤能存储 512MB。
实例
redis 127.0.0.1:6379> SET runoob "菜鸟教程"
OK
redis 127.0.0.1:6379> GET runoob
"菜鸟教程"
Hash(哈希)
Redis hash 是⼀个键值(key=>value)对集合。
Redis hash 是⼀个 string 类型的 field 和 value 的映射表,hash 特别适合⽤于存储对象。
实例
DEL runoob ⽤于删除前⾯测试⽤过的 key,不然会报错:(error) WRONGTYPE Operation against a key holding the wrong kind of value
redis 127.0.0.1:6379> DEL runoob
redis 127.0.0.1:6379> HMSET runoob field1 "Hello" field2 "World"
"OK"
redis 127.0.0.1:6379> HGET runoob field1
"Hello"
redis 127.0.0.1:6379> HGET runoob field2
"World"
实例中我们使⽤了 Redis HMSET, HGET 命令,HMSET 设置了两个 field=>value 对, HGET 获取对应 field 对应的 value。
每个 hash 可以存储 232 -1 键值对(40多亿)。
List(列表)
Redis 列表是简单的字符串列表,按照插⼊顺序排序。你可以添加⼀个元素到列表的头部(左边)或者尾部(右边)。
实例
redis 127.0.0.1:6379> DEL runoob
redis 127.0.0.1:6379> lpush runoob redis
(integer) 1
redis 127.0.0.1:6379> lpush runoob mongodb
(integer) 2
redis 127.0.0.1:6379> lpush runoob rabitmq
(integer) 3
redis 127.0.0.1:6379> lrange runoob 0 10
1) "rabitmq"
2) "mongodb"
3) "redis"
redis 127.0.0.1:6379>
列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。
Set(集合)
Redis 的 Set 是 string 类型的⽆序集合。
集合是通过哈希表实现的,所以添加,删除,查的复杂度都是 O(1)。
sadd 命令
添加⼀个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。
sadd key member
实例
redis 127.0.0.1:6379> DEL runoob
redis 127.0.0.1:6379> sadd runoob redis
(integer) 1
redis 127.0.0.1:6379> sadd runoob mongodb
(integer) 1
redis 127.0.0.1:6379> sadd runoob rabitmq
(integer) 1
redis 127.0.0.1:6379> sadd runoob rabitmq
(integer) 0
redis 127.0.0.1:6379> smembers runoob
1) "redis"
2) "rabitmq"
3) "mongodb"
注意:以上实例中 rabitmq 添加了两次,但根据集合内元素的唯⼀性,第⼆次插⼊的元素将被忽略。
集合中最⼤的成员数为 232 - 1(4294967295, 每个集合可存储40多亿个成员)。
zset(sorted set:有序集合)
Redis zset 和 set ⼀样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联⼀个double类型的分数。redis正是通过分数来为集合中的成员进⾏从⼩到⼤的排序。zset的成员是唯⼀的,但分数(score)却可以重复。
zadd 命令
添加元素到集合,元素在集合中存在则更新对应score
zadd key score member
实例
redis 127.0.0.1:6379> DEL runoob
redis 127.0.0.1:6379> zadd runoob 0 redis
(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 mongodb
(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 rabitmq
(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 rabitmq
(integer) 0
redis 127.0.0.1:6379> > ZRANGEBYSCORE runoob 0 1000
1) "mongodb"
2) "rabitmq"
3) "redis"
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论