Redis入门指南
声明:本文内容来自《Redis入门指南》一书,如转载请声明。
一、简介
Redis是一个开源的高性能键值对数据库。Redis是REmote DIctionary Server(远程字典服务器)的缩写
特性:
1.存储结构
Redis支持的键值数据类型有字符串类型、散列类型、列表类型、集合类型、有序集合类型。
2.内存存储与持久化
Redis所有数据保存在内存中,对数据的更新将异步地保存到磁盘上。
3.功能丰富
关于Redis和Memcached优劣的讨论一直是一个热门的话题。在性能上Redis是单线程模型,而Memcached支持多线程,所以在多核服务器上后者的性能更高一些。然而,在绝大部分场合下其性能都不会成为瓶颈。所以在使用时更应该关心的是二者在功能上的区别,如果需要用到高级的数据类型或是持久化等功能,Redis将会是Memcached很好的替代品。
4.简单稳定
Redis的命令比SQL语言要简单很多。Redis使用C语言开发,代码量只有3万多行。
二、准备
启动和停止Redis
redis-server(Redis服务器)如:redis-server redis0.conf
redis-cli (Redis命令行客户端)如:redis-cli -h 127.0.0.1 -p 6379
redis-benchmark(Redis性能测试工具)
redis-check-aof(AOF文件修复工具)
redis-check-dump(RDB文件检查工具)
* 启动Redis
启动Redis有直接启动和通过初始化脚本启动两种方式,分别适用于开发环境和生产环境。
* 停止Redis
正确停止Redis的方式应该是向Redis发送SHUTDOWN命令。当Redis收到SHUTDOWN命令后,会先断开所有客户端连接,然后根据配置执行持久化,最后完成退出。 使用“kill Redis进程的PID”也可以正常结束Redis,效果与发送SHUTDOWN命令一样。
命令返回值
状态回复、错误回复、整数回复、字符串回复、多行字符串回复。
三、入门
热身
1.获得符合规则的键名列表 (KEYS pattern) pattern支持glob风格通配符格式。 glob风格通配符规则:?(匹配一个字符) * (匹配任一个包括0个字符) [] (匹配括号间的任一字符,可以使用“-”符号表示一个范围,如a[b-d]可以匹配"ab","ac","ad") \x (匹配字符x,用于转移符号。如要匹配“?”就需要使用\?)
keys命令需要遍历Redis中的所有键,当键的数量较多时会影响性能,不建议在生产环境中使用。 Redis不区分命令大小写。
2.判断一个键是否存在(EXISTS key)如果键存在则返回整数类型1,否则返回0.
3.删除键(DEL key [key ...])可以删除一个或多个键,返回值是删除的键的个数。
4.获得键值的数据类型(Type key)
字符串类型
1.赋值与取值
set key value
get key
2.递增数字
incr key #字符串类型可以存储任何形式的字符串,当存储的字符串是整数形式时,Redis提供了一个实用的命令INCR,其作用是让当前键值递增,并返回递增后的值。当键值不是整数时,Redis会提示错误。
3.增加指定的整数
incrby key increment #incrby命令与incr命令基本一样,只不过前者可以通过increment参数指定一次增加的数值。
4.减少指定的整数
decr key
decrby key increment
5.增加指定浮点数
incrbyfloat key increment
6.向尾部追加值
append key value #append的作用是向键值的末尾追加value。如果键不存在则将该键的值设置为value,即相当于set key value。返回值是追加后字符串的总长度。如:127.0.0.1:6379>set key hello
OK
127.0.0.1:6379>append key " world!"
(integer)12
127.0.0.1:6379>get key
"hello world!"
127.0.0.1:6379>strlen key
(integer)12
7.获取字符串长度
strlen key #strlen命令返回键值的长度,如果键不存在则返回0。
8.同时获得/设置多个键值
mget key [key ...]
mset key value [key value ...]
9.位操作
getbit key offset #可以获得一个字符串类型键指定位置的二进制位的值(0或1),索引从0开始。如果需要获取的二进制位的索引超出了键值的二进制位的实际长度则默认位值是0.
setbit key offset value #可以设置字符串类型键指定的二进制位的值,返回值是该位置的旧值。如果要设置的位置超过了键值的二进制位的长度,setbit命令会自动将中间的二进制位设置为0,同理设置一个不存在的键的指定二进制位的值会自动将其前面的位赋值为0.
bitcount key [start] [end] #bitcount命令可以获得字符串类型键中值是1的二进制位个数,可以通过参数start和end来限制统计的字节范围。
bitop operation destkey key [key ...] #bitop命令可以对多个字符串类型键进行位运算,并将结果存储在destkey参数指定的键中。bittop命令支持的运算操作有AND、OR、XOR和NOT。
getbit和setbit的时间复杂度都是O(1)。
散列类型(Hash)
Redis是采用字典结构以键值对的形式存储数据的,而散列类型(hash)的键值也是一种字典结构,其存储了字段和字段值的映射,但字段值只能是字符串,不支持其他数据类型。即散列类型不能嵌套其他的数据类型。除了散列类型,Redis的其他数据类型同样不支持数据类型嵌套。比如集合类型的每个元素都只能是字符串,不能是另一个集合或散列表等。
1.赋值与取值
hset key field value
hget key field
hmset key field value [field value ...]
hmget key field [field ...]
hgetall key #返回的结果是字段和字段值组成的列表。
hset命令的方便之处在于不区分插入和更新操作,这意味着修改数据时不用事先判断字段是否存在来决定要执行的是插入操作还是更新操作。当执行的是插入操作时(即之前的字段不存在)hset命令会返回1,当执行的是更新操作时(即之前字段已经存在)heset命令会返回0。当键本身不存在时,hset命令还会自动建立它。
2.判断字段是否存在
hexists key field #用来判断一个字段是否存在,如果存在则返回1,否则返回0(如果键不存在也会返回0)。
3.当字段不存在时赋值
hsetnx key field value #hsetnx命令与hset命令类似,区别在于如果字段已经存在,hsetnx命令将不执行任何操作。
4.增加数字
hincrby key field increment #返回值是增值后的字段值
5.删除字段
hdel key field [field ...] #返回值是被删除的字段个数
6.只获取字段名或字段值
hkeys key
hvals key
7.获得字段数量
hlen key
列表类型
列表类型可以存储一个有序的字符串列表。列表类型内部是使用双向链表实现的,所以像列表两端添加元素的时间复杂度为O(1),获取越接近两端的元素速度就越快。
1.像列表两端增加元素
LPush key value [value ...] #像列表左边增加元素,返回值表示增加元素后列表的长度
RPush key value [value ...] #像列表右边增加元素,返回值表示增加元素后列表的长度
2.从列表两端弹出元素
LPop key #从列表左边弹出一个元素。返回被移除的元素值
RPop key #从列表右边弹出一个元素。返回被移除的元素值
结合上述四个命令可以使用列表类型来模拟栈和队列的操作:
如果想把列表当做栈,则搭配使用LPush和LPop或RPush和RPop。
如果想把列表当做队列,则搭配使用LPush和RPop或RPush和LPop。
3.获取列表中元素的个数
LLen key #当键不存在时LLen会返回0。时间复杂度O(1).
4.获得列表片段
LRange key start stop #返回索引从start到stop之间的所有元素(包含两端的元素)。Redis的列表起始索引为0。LRange命令也支持负索引,表示从右边开始计算序数,如“-1”表示最右边第一个元素,“-2”表示最右边第二个元素。
显然,LRange numbers 0 -1可以获取列表中的所有元素。
另外一些特殊情况如下:
(1)如果start的索引位置比stop的索引位置靠后,则会返回空列表。
(2)如果stop大于实际的索引范围,则会返回到列表最右边的元素。
5.删除列表中指定的值
LRem key count value #LRem命令会删除列表中前count个值为value的元素,返回值是实际删除的元素个数。根据count值的不同,LRem命令的执行方式会略有差异:
当count>0时LRem命令会从列表左边开始删除前count个值为value的元素;
当count<0时LRem命令会从列表右边开始删除前|count|个值为value的元素;
当count=0时LRem命令会删除所有值为value的元素。
6.获得/设置指定索引的元素值
LIndex key index #用来返回指定索引的元素,索引从0开始。如果index是负数则表示从右边开始计算的索引,最右边元素的索引是-1。
LSet key index value #将索引为index的元素赋值为value.
7.只保留列表指定片段
LTrim key start end #可以删除指定索引范围之外的所有元素。
8.像列表中插入元素
LInsert key before|after pivot value #LInsert命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是before还是after来决定将value插入到该元素的前面还是后面。LInsert命令的返回值是插入后列表的元素个数。
9.将元素从一个列表转到另一个列表
RPOPLPUSH source destination #RPOPLPUSH命令会先从source列表类型键的右边弹出一个元素,然后将其加入到destination列表类型键的左边,并返回这个元素的值。(一次只能从source的右边中弹出一个,往destination的左边中压入一个)
集合类型
集合类型与列表类型对比:
存储内容:集合类型至多2^32-1个字符串,列表类型至多2^32-1个字符串。
有序性:集合类型无序,列表类型有序。
唯一性:集合类型唯一,列表类型不唯一。
1.增加/删除元素
SAdd key member [member ...] #返回值是成功加入的元素数量
SRem key member [member ...] #返回删除成功的个数
2.获得集合中的所有元素
SMembers key #返回集合中的所有元素
3.判断元素是否在集合中
Sismember key member #时间复杂度O(1)。当值存在时Sismember命令返回1,当值不存在或键不存在时返回0.
4.集合间运算
Sdiff key [key ...] #用来对多个集合执行差集运算。支持同时传入多个键。
Sdiff setA setB setC计算顺序是先计算setA-setB,再计算结果与setC的差集。
Sinter key [key ...] #用来对多个集合执行交集运算。
Sunion key [key ...] #用来对多个集合执行并集运算。
5.获得集合中元素的个数
Scard key
6.进行集合运算并将结果存储
Sdiffstore destination key [key ...]
SInterstore destination key [key ...]
SUnionstore destination key [key ...]
将结果存储在destination中,而不会直接返回。
7.随机获得集合中的元素
srandmember key [count] #随机从集合中获取一个元素
还可以传递count参数来一次随机获得多个元素,根据count的正负不同,具体表现也不同。
(1)当count为正数时,srandmember会随机从集合里获得count个不重复的元素。如果count的值大于集合中的元素个数,则srandmember会返回集合中的全部元素。
(2)当count为负数时,srandmember会随机从集合里获得|count|个元素,这些元素有可能相同。
8.从集合中个弹出一个元素
SPOP key #从集合中随机选择一个元素弹出
有序集合类型
有序集合类型在某些方面和列表类型有些相似。
(1)二者都是有序的。
(2)二者都可以获得某一范围的元素。
但是二者有着很大的区别,这使得它们的应用场景也是不同的。
(1)列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会较慢,所以它更加适合实现如“新鲜事”或“日志”这样很少访问中间元素的应用。
(2)有序集合类型是使用散列表和跳跃表(Skip list)实现的,所以即使读取位于中间部分的数据也很快(时间复杂度是O(log(N))。
(3)列表中不能简单地调整某个元素的位置,但是有序集合可以(通过更改这个元素的分数)。
(4)有序集合要比列表类型更耗费内存。
1.增加元素
zadd key score member [score member ...] #向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素的个数(不包含之前已经存在的元素)。
2.获得元素的分数
zscore key member
3.获得排名在某个范围的元素列表
zrange key start stop [withscores] #按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包含两端的元素)。如果需要同时获得元素的分数的话可以在zrange命令的尾部加上withscores参数,这时返回的数据格式就从“元素1,元素2,…”变为了“元素1,分数1,元素2,分数2,…”。zrange的时间复杂度为O(logn+m)(其中n为有序集合的基数,m为返回的元素个数)。
zrevrange key start stop [withscores] #zrevrange和zrange的唯一不同在于zrevrange是按照元素分数从大到小的顺序给出结果的。
4.获得指定分数范围的元素
zrangebyscore key min max [withscores] [limit offset count] #按照元素分数从小到大的顺序返回分数在min和max之间(包含min和max)的元素。如果希望分数范围不包含端点值,可以在分数前加上“(”符号。min和max还支持无穷大,-inf和+inf分别表示负无穷和正无穷。limit offset count即在获得的元素列表的基础上向后偏移offset个元素,并且只获取前count个元素。
zrevrangebyscore key min max [withscores] [limit offset count] #与zrangebyscore唯一不同的是,zrevrangebyscore是按照元素分数从大到小的顺序返回分数在min和max之间(包含min和max)的元素。
5.增加某个元素的分数
zincrby key increment member #增加一个元素的分数,返回值是更改后的分数。increment也可以是个负数表示减分。如果指定的元素不存在,Redis在执行命令前会先建立它并将他的分数赋为0在执行操作。
6.获得集合中元素的数量
zcard key
7.获得指定分数范围内的元素个数
zcount key min max #zcount命令的min和max参数的特性与zrangebyscore命令中的一样。
8.删除一个或多个元素
zrem key member [member ...] #返回值是成功删除的元素数量(不包含本来就不存在的元素)。
9.按照排名范围删除元素
zremrangebyrank key start stop #按照元素分数从小到大的顺序(即索引0表示最小的值)删除处在指定排名范围内的所有元素,并返回删除的元素数量。
10.按照分数范围删除元素
zremrangebyscore key min max #删除指定分数范围内的所有元素,min和max参数的特性与zrangebyscore命令中的一样。
11.获得元素的排名
zrank key member #按照元素分数从小到大的顺序获得指定的元素的排名(从0开始,即分数最小的元素排名为0)
zrevrank key member #与zrank命令相反,分数最大的元素排名为0.
12.计算有序集合的交集
zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max] #用来计算多个有序集合的交集并将结果存储在destination键中(同样以有序集合类型存储,返回值为destination键中的元素个数)。
destination键中元素的分数是由aggregate参数决定的。
(1)当aggregate是sum时(也就是默认值),destination键中元素的分数是每个参与计算的集合中该元素分数的和。
(2)当aggregate是min时,destination键中元素的分数是每个参与计算的集合中该元素分数的最小值。
(3)当aggrega是max时,destination键中元素的分数是每个参与计算的集合中该元素分数的最大值。
zinterstore命令还能够通过weights参数设置每个集合的权重,每个集合在参与计算时元素的分数会被乘上该集合的权重。
四、进阶
事务
1.概述
redis中的事务是一组命令的集合。事务同命令一样都是Redis的最小执行单位,一个事务中的命令要么都执行,要么都不执行。事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次执行这些命令。即首先使用MULTI命令告诉Redis下面发送的命令属于同一个事务,你先不要执行而是把他们暂时存起来。Redis返回OK。之后我们发送命令,Redis没有执行而是返回QUEUED表示这两条命令已经进入等待执行的事务队列中了。当把所有要在同一个事务中执行的命令都发给Redis后,再向Redis发送EXEC命令告诉Redis将等待执行的事务队列中的所有命令按照发送顺序一次执行。返回值顺序和命令的顺序相同。
2.错误处理
(1)语法错误。如果事务队列中只要有一个命令有语法错误,执行EXEC命令后Redis就会直接返回错误,连语法正确的命令也不会执行。
(2)运行错误。如果事务队列中的一条命令出现了运行错误,事务里其他的命令依然会继续执行(包括出错命令之后的命令)。
Redis的事务没有关系数据库事务提供的回滚功能。
3.Watch命令介绍
watch命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。监控一直持续到EXEC命令。
生存时间
Expire命令的使用方法为Expire key seconds,其中seconds参数表示键的生存时间,单位是秒。
如果想知道一个键还有多久的时间会被删除,可以使用TTL命令。返回值是键的剩余时间(单位是秒)。(TTL key)当键不存在时TTL命令会返回-1。另外同样会返回-1的情况是没有为键设置生存时间(即永久存在,这是建立一个键后的默认情况)。
如果想取消键的生存时间设置(即将键恢复成永久的),可以使用PERSIST命令。如果生存时间被成功清除则返回1;否则返回0(因为键不存在或键本来就是永久的)。
除了persist命令之外,使用SET或GETSET命令为键赋值也会同时清除键的生存时间。
使用expire命令会重新设置键的生存时间。
pexpire命令与expire命令的唯一区别是前者的时间单位是毫秒,即pexpire key 1000与expire key 1等价。对应地可以用PTTL命令以毫秒为单位返回键的剩余时间。
排序
1.有序集合的集合操作
集合类型提供了强大的集合操作命令,但是如果需要排序就要用到有序集合类型。除了使用有序集合外,还可以使用SORT命令进行排序。
2.SORT命令
Sort命令可以对列表类型、集合类型和有序集合类型键进行排序。
在对有序集合类型排序时会忽略元素的分数,只针对元素自身的值进行排序。
除了可以排列数字外,SORT命令还可以通过ALPHA参数实现按照字典顺序排列非数字元素。(sort key alpha)如果对非数字元素没有添加alpha则会提示错误,因为sort命令尝试将所有元素转换成双精度浮点数来比较,如果无法转换,则会提示错误。
sort命令默认是按照从小到大的顺序排列。sort命令的DESC参数可以实现将元素按照从大到小的顺序排列。sort命令还支持limit参数来返回指定范围的结果。即Limit offset count,表示跳过前offset个元素并获取之后的count个元素。
3.BY参数
BY参数的语法为“BY参考键”。其中参考键可以是字符串类型键或者是散列类型键的某个字段(表示为键名->字段名)。如果提供了BY参数,SORT命令将不再依据元素自身的值进行排序,而是对每个元素使用元素的值替换参考键中的第一个“*”并获取其值,然后依据该值对元素排序。(sort tag:ruby:posts by post:*->time DESC)
除了散列类型外,参考键还可以是字符串类型。如:在redis-cli中输入
lpush sortbylist 2 1 3
set itemscore:1 50
set itemscore:2 100
set itemscore:3 -10
sort sortbylist by itemscore:* desc
当参考键名不包含“*”时(即常量键名,与元素值无关),sort命令将不会执行排序操作。
如果几个元素的参考值相同,则SORT命令会再比较元素本身的值来决定元素的顺序。
当某个元素的参考键不存在时,会默认参考键的值为0.
4.Get参数
Get参数不影响排序,他的作用是使Sort命令的返回结果不再是元素自身的值,而是Get参数中指定的键值。Get参数也支持字符串类型和散列类型的键,并使用“*”作为占位符。(sort tag:ruby:posts by post:*->time DESC get post:*->title)
在一个sort命令中可以有多个get参数(而by参数只能有一个)。
Get #会返回元素本身的值。
5.store参数
默认情况下sort会直接返回排序结果,如果希望保存排序结果,可以使用store参数。(在结尾加上store sort.result)保存到sort.result键中。保存后的键的类型为列表类型,如果键已经存在则会覆盖它。加上store参数后sort命令的返回值为结果的个数。
6.性能优化
Sort命令的时间复杂度是O(n+mlogm),其中n表示要排序的列表(集合或有序集合)中的元素个数,m表示要返回的元素个数。当n较大时,sort命令的性能相对较低。
开发中使用sort命令时需要注意以下几点:
(1)尽可能减少待排序键中元素的数量(使n尽可能小)。
(2)使用limit参数只获取需要的数据(使m尽可能小)。
(3)如果要排序的数据数量较大,尽可能使用store参数将结果缓存。
消息通知
1.任务队列
与任务队列进行交互的实体有两类,一类是生产者,一类是消费者。生产者会将需要处理的任务放入任务队列中,而消费者则不断地从任务队列中读入任务消息并执行。
使用任务队列有如下好处:
(1)松耦合。
(2)易于扩展。消费者可以有多个,而且可以分布在不同的服务器中。借此可以轻易地降低单台服务器的负载。
2.使用Redis实现任务队列
如果要实现任务队列,只需要让生产者将任务使用LPush命令加入到某个键中,另一边让消费者不断地使用RPOP命令从该键中取出任务即可。
BRPOP命令和RPOP命令相似,唯一的区别是当列表中没有元素时BRPOP命令会一直阻塞住连接,直到有新元素加入。
BRPOP命令接收两个参数,第一个是键名,第二个是超时时间,单位是秒。当超过了此时间仍然没有获得新元素的话就会返回nil。如果超时时间为0,表示不限制等待的时间,即如果没有新元素加入列表就会永远阻塞下去。
BLPOP命令与BRPOP命令的区别在于从队列取元素时BLPOP会从队列左边取。
3.优先级队列
BLPOP可以同时接收多个键,其完整的命令格式为:BLPOP key [key ...] timeout。意义是同时检测多个键,如果所有键都没有元素则阻塞,如果其中有一个键有元素则会从该键中弹出元素。
如果多个键都有元素则按照从左到右的顺序取第一个键中的一个元素。
4.发布/订阅模式
发布/订阅模式中包含两种角色,分别是发布者和订阅者。订阅者可以订阅一个或多个频道,而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息。
发布者发布消息的命令是PUBLISH,用法是Publish channel message。返回值表示接收到这条消息的订阅者数量。发出去的消息不会被持久化,也就是说当有客户端订阅该频道后只能收到后续发布到该频道的消息,之前发送的就收不到了。
订阅频道的命令是SUBSCRIBE,可以同时订阅多个频道,用法是SUBSCRIBE channel [channel ...].
执行SUBSCRIBE命令后客户端会进入订阅状态,处于此状态下客户端不能使用除SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PUNSUBSCRIBE这4个属于“发布/订阅”模式的命令之外的命令,否则会报错。
进入订阅状态后客户端可能收到三种类型的回复。每种类型的回复都包含3个值。第一个值是消息的类型,根据消息类型的不同,第二、三个值的含义也不同。消息类型的可能取值有:
(1)Subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个值是当前客户端订阅的频道数量。
(2)message。这个类型的回复是我们最关心的,它表示接收到的消息。第二个值表示产生消息的频道名称,第三个值是消息的内容。
(3)unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量。当此值为0时客户端会退出订阅状态,之后就可以执行其他非“发布/订阅”模式的命令了。
使用unsubscribe命令可以取消订阅指定的频道,用法为unsubscribe [channel [channel ...]],如果不指定频道则会取消订阅所有频道。
5.按照规则订阅
除了可以使用subscribe命令订阅指定名称的频道外,还可以使用psubscribe命令订阅指定的规则。规则支持glob风格通配符格式。使用psubscribe订阅后当收到消息后会返回四个值。第一个值表示这条消息是通过psubscribe命令订阅频道而收到的(pmessage),第二个值表示订阅时使用的通配符,第三个值表示实际收到消息的频道命令,第四个值则是消息内容。
punsubscribe命令可以指定退订的规则,用法是punsubscribe [pattern [pattern ...]],如果没有参数则会退订所有规则。
使用punsubscribe命令只能退订通过psubscribe命令订阅的规则,不会影响直接通过subscribe命令订阅的频道;同样unsubscribe命令也不会影响通过psubscribe命令订阅的规则。另外容易出错的一点是使用punsubscribe命令退订某个规则时不会将其中的通配符展开,而是进行严格的字符串匹配,所以punsubscribe *无法退订channel.*规则,而是必须使用punsubscribe channel.*才能退订。
管道
客户端和Redis使用TCP协议连接。不论是客户端向Redis发送命令还是Redis向客户端返回命令的执行结果,都需要经过网络传输,这两个部分的总耗时称为往返时延。
Redis的底层通信协议对管道提供了支持。通过管道可以一次性发送多条命令并在执行完后一次性将结果返回,当一组命令中每条命令都不依赖于之前命令的执行结果时就可以将这组命令一起通过管道发出。管道通过减少客户端与Redis的通信次数来实现降低往返时延累计值的目的。
节省空间
(1)精简键名和键值
(2)内部编码优化
Redis为每种数据类型都提供了两种内部编码方式。
如果想查看一个键的内部编码可以使用OBJECT ENCODING命令。
五、管理
持久化
Redis的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中以某种形式同步到硬盘中,这一过程就是持久化。
Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用或将二者结合使用。
1.RDB方式
RDB方式的持久化是通过快照完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘上。RDB是Redis默认采用的持久化方式。Redis默认会将快照文件存储在当前目录的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别制定快照文件的存储路径和文件名。
快照的过程:
(1)Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
(2)父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
(3)当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
2.AOF方式
默认情况下Redis没有开启AOF方式的持久化,可以通过appendonly参数开启。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改。
复制
1.配置
同步后的数据库分为两类:主数据库和从数据库。只需要在从数据库的配置文件中加入“slaveof 主数据库IP 主数据库端口”即可,主数据无需进行任何配置。使用“salveof no one”可以使当前数据库停止接收其他数据库的同步转成主数据库。
2.原理
当一个从数据库启动后,会像主数据库发送SYNC命令,主数据库接收到SYNC命令后会开始在后台保存快照,并将保存期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。当主从数据库断开重连后会重新执行上述操作,不支持断点续传。
3.读写分离
主数据库只进行写操作,而从数据库负责读操作。
4.从数据库持久化
为了提高性能,可以通过复制功能建立一个(或若干个)从数据库,并在从数据库中启用持久化,同时在主数据库禁用持久化。当从数据库崩溃时重启后主数据库会自动将数据同步过来,所以无须担心数据丢失。而当主数据库崩溃时,需要在从数据库中使用slaveof no one命令将从数据库提升成主数据库继续服务,并在原来的主数据库启动后使用slaveof命令将其设置成新的主数据库的从数据库,即可将数据同步回来。
-