Redis是一个开源(BSD许可),内存数据结构存储,用做数据库,缓存和消息代理。它支持数据结构,如 字符串,散列,列表,集合,带有范围查询的排序集,位图,超级日志和带有半径查询的地理空间索引。Redis具备内置复制,Lua脚本,LRU驱逐,事务和不一样级别的磁盘持久性,并经过Redis Sentinel提供高可用性和Redis Cluster自动分区。linux
你能够 对这些类型运行原子操做,例如附加到字符串 ; 递增哈希值 ; 将元素推送到列表中 ; 计算集合交集, 并集和差别 ; 或者在排序集中得到排名最高的成员。git
为了实现其出色的性能,Redis使用 内存数据集。根据您的使用状况,您能够经过 每隔一段时间将数据集转储到磁盘或经过将每一个命令附加到日志来保留它。若是您只须要功能丰富的网络内存缓存,则能够选择禁用持久性。github
Redis还支持简单到设置的主从异步复制,具备很是快速的非阻塞第一次同步,自动从新链接以及在网络分割上的部分从新同步。redis
官方没有windows版本的支持,可是微软维护这一个windows 64位的redis版本,代码托管在github上,可使用该地址进行下载,https://github.com/MicrosoftArchive/redis/releases数据库
按照须要进行下载文件,解压后redis对应的服务程序为redis-server.exe,配置文件为 redis.windows.conf,启动完成后,使用redis-cli.ext -h127.0.0.1 -p6379 来对redis数据库进行操做。windows
到官网下载redis的安装包 Redis官网 下载对应的linux的操做系统的安装包(分为稳定,不稳定和测试三个版本)。数组
具体操做以下:缓存
# 下载源码包
wget http://download.redis.io/releases/redis-4.0.11.tar.gz
# 解压
tar xzf redis-4.0.11.tar.gz
# 切换工做目录
cd redis-4.0.11
# make 编译
make
# 编译好的二进制文件在src目录下。
# 能够自行拷贝进行使用,也可使用make install命令安装。
# 若是执行make install 默认文件被放到/usr/local/bin/下,也可使用 PREFIX=/to/path 参数来指定存放位置
make install PREFIX=/usr/local/
redis的配置文件位于redis目录下,文件名为redis.conf,配置文件的修改能够经过修改配置文件重启redis来使配置文件生效,或者使用CONFIG SET|GET 命令来进行动态配置。安全
Redis是个支持持久化的内存数据库,redis须要常常将内存中的数据同步到磁盘来保证持久化。服务器
RDB 方式为默认的快照方式。
配置
# 该配置通常为默认配置
save 900 1 #在900秒(15分钟)以后,若是至少有1个key发生变化,则dump内存快照。
save 300 10 #在300秒(5分钟)以后,若是至少有10个key发生变化,则dump内存快照。
save 60 10000 #在60秒(1分钟)以后,若是至少有10000个key发生变化,则dump内存快照。
工做原理
RDB方式持久化命令以下:
命令 | 说明 |
---|---|
SAVE | 运行后会阻塞Redis服务器进程,直到RDB文件建立完毕,在阻塞过程过程当中服务器不处理任何来自外界的请求不管读仍是写(阻塞全部请求)。 |
BGSAVE | 会产生一个子进程,由此子进程来处理建立RDB文件任务,而服务器的父进程继续响应外部请求。 |
BGREWRITEAOF | 用于异步执行一个 AOF(AppendOnly File) 文件重写操做。重写会建立一个当前 AOF 文件的体积优化版本。 即便 Bgrewriteaof 执行失败,也不会有任何数据丢失,由于旧的 AOF 文件在 Bgrewriteaof 成功以前不会被修改。 (注意: 从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操做。 ) |
LASTSAVE | 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示。 |
BGSAVE
在执行过程当中不会阻塞请求,可是不是任何请求均可以执行,在服务器执行BGSAVE
期间,对于执行SAVE
、BGSAVE
和BGREWRITEAOF
这三个命令会有全部不一样。
在BGSAVE执行期间 | |
---|---|
执行SAVE命令 | 会被服务器拒绝,服务器禁止SAVE命令和BGSAVE同时执行,由于不可能让两个命令去调用同一函数而后去操做同一个RDB文件。 |
执行BGSAVE命令 | 会被服务器拒绝,由于已经有一个在进行了,不必再容许一个 。 |
执行BGREWRITEAOF命令 | 会被延迟执行,BGSAVE子进程完成后,才会执行BGREWRITEAOF命令 。 |
在BGSAVE执行期间 | |
---|---|
执行BGSAVE命令 | 会被拒绝,这两个命令没有冲突的地方,只是同时执行会产生大量磁盘写操做,会影响性能,因此这是一个规则上的拒绝,不是一个技术上的拒绝 |
BGSAVE 工做原理
Redis使用fork函数复制一份当前进程(父进程)的副本(子进程)。
父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件。
当子进程写入完全部数据后会用该临时文件替换旧的RDB文件,至此一次快照操做完成。
查看rds文件配置
经过使用CONFIG GET
命令能够查看持久化数据保存的位置。
> config get dir
1) "dir"
2) "E:\\redis\\redis3.0"
> config get dbfilename
1) "dbfilename"
2) "dump.rdb"
RDB方式优势
RDB是个很是紧凑的文件,保存了redis在某个时间点上的数据集,使得咱们能够经过定时备份RDB文件来实现Redis数据库备份和灾难恢复,也能够将其传送到其余的数据中心用于保存。
RDB能够最大化redis的性能,执行RDB持久化时只须要fork一个子进程,并由子进程进行持久化工做,父进程不须要处理任何磁盘I/O操做。
RDB在恢复大数据集时比AOF要快,启动效率要高许多。
RDB文件是通过压缩(能够配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,因此占用的空间会小于内存中的数据大小,更加利于传输。
RDB方式缺点
每次快照持久化都是将内存数据完整写入到磁盘一次,并非增量的只同步增数据。若是数据量大的话,并且写操做比较多,必然会引发大量的磁盘io操做,可能会严重影响性能。
快照方式是在必定间隔时间作一次的,因此若是redis意外down掉的话,就会丢失最后一次快照后的全部修改,有一些数据丢失的风险。
client的save
或者bgsave
命令通知redis作一次快照持久化不推荐。
缘由:save操做是在主线程中保存快照的,因为redis是用一个主线程来处理全部 client的请求,这种方式会阻塞全部client请求。因此不推荐使用。
RDB 方式注意事项
Redis模式会运行16个数据库(编号为0---15),在执行保存的过程当中不管是SAVE
触发仍是BGSAVE
触发,都是会把全部非空
数据库进行保存的。
默认AOF 方式是关闭的。
RDB方式若是redis 服务意外中止运行后,会将最新写入的数据丢失,在某些严格要求的项目中不是一个可行的方案。此时AOF能够解决这个问题,AOF 方式是在redis 1.1 版本中可用。
AOF 方式是在写入内存数据的同时将操做命令保存到日志文件中。 当你从新启动redis 服务时,它将从新根据AOF以重建状态。这种方式相似于传统数据库服务器的事务日志 。
若是遇到在追加日志的时候遇到意外,可使用redis-check-aof工具进行日志修复。
由于采用了追加方式,因此AOF会愈来愈大(这一点又和传统数据库不同,传统数据库事务日志文件都比较小),所以redis有另一个机制就是AOF文件重写,当AOF文件达到一个设定的阈值后,会自动启动AOF文件压缩,只保留能够恢复数据的最小指令集。
配置
# 在配置文件中打开AOF
appendonly yes
# aof方式文件名
appendfilename "appendonly.aof"
# 每次执行写入都会执行同步,最安全也最慢,执行write()和fsync()系统调用。
# appendfsync always
# 每秒执行一次同步,默认,执行write()和fsync()系统调用。
appendfsync everysec
# 不主动进行同步操做,而是彻底交由操做系统来作(即每30秒一次),最快也最不安全,只执行write()。
# appendfsync no
AOF 持久化原理
当AOF 持久化开启后,对数据库进行一次更新操做后,更新命令会被追加到aof_buf
缓冲区的末尾,而后缓冲区写入到AOF 文件。
AOF文件中记录的内容就是对数据更新操做的指令。这个文件自己就是以文原本记录的。
对redis
进行了以下操做:
> set 40kuai 40
OK
> get 40kuai 40
(error) ERR wrong number of arguments for 'get' command
> get 40kuai
"40"
> del 40kuai
(integer) 1
下面咱们来查看下appendonly.aof
文件的内容:
*2
$6
SELECT
$1
0
*3
$3
set
$6
40kuai
$2
40
*2
$3
del
$6
40kuai
分别解释下各个字段的含义:
字符 | 含义 |
---|---|
*2 | 表示2个参数 |
$6 | 第一个参数长度为6 |
SELECT | 第一个参数 |
$1 | 第二个参数的长度为1 |
0 | 第二个参数 |
注意:这里能够看出 appendonly.aof
文件中记录的都是对数据进行操做的命令,对于用户使用GET
进行查询的操做并无记录。
AOF 重写实现原理
由于AOF持久化是经过记录命令的方式来保存数据库状态的,随着时间的推移AOF文件确定会逐渐增大,若是不加以控制会对AOF持久化性能以及数据恢复形成影响。
以一个列表为例来讲明重写的意义:
> rpush list a b
(integer) 2
> rpush list c
(integer) 3
> lrange list 0 1
1) "a"
2) "b"
根据AOF的原理,上面的操做须要将2条命令追加到appendonly.aof
文件当中,其实咱们看到list
最后的状态是值a,b,c
。当使用appendonly.aof
文件进行恢复时,要实现最后的状态,须要追加2 条命令,因此在大量内存读写的业务里AOF文件增加的很快。为了解决这个问题,Redis提供了AOF重写功能。
AOF重写就是建立一个新的AOF文件来替换现有的AOF文件,实际上AOF重写并不对现有的旧AOF文件进行操做。当进行重写的时候直接从数据库里去获取list的最新状态,而后在新的AOF文件中直接写一条rpushlist B C D E F命令,从而避免写5条的操做,这样AOF文件的增加速度就会下降,同时容量也不会特别大。
AOF重写程序aof_rewrite函数去完成建立新的AOF文件的任务,可是该函数并不会由Redis主进程去直接调用,而是使用子进程后台去执行(BGREWRITEAOF,该命令其实就是执行aof_rewrite,只不过是由子进程去调用的),这时主进程就会不被阻塞,那么就能够在执行重写的过程当中父进程能够继续对外提供响应。整个过程以下:
当重写被触发时父进程调用一个函数,该函数建立一个子进程用于执行BGREWRITEAOF
,该子进程建立一个临时文件,而后父进程继续对外提供读写服务。
子进程遍历数据库,将每一个键值的最新状态输出到临时文件中,在BGREWRITEAOF过程当中,父进程把全部对数据库的更新命令同时写入到AOF缓冲区和AOF重写缓冲区(aof_rewrite_buf_blocks),AOF缓冲区(aof_buf)会继续同步到现有AOF文件中(通常状况下在AOF重写期间不建议把AOF缓冲区的内容同步到现有的AOF文件中,这会下降性能,默认为NO)。
AOF重写完成后子进程通知父进程,父进程调用信号处理函数。
信号处理函数会阻塞父进程对外提供读写操做(时间很短,不阻塞就又会出现数据不一致的状况),而后将AOF重写缓冲区的内容写入到新的AOF文件中,最后用新的AOF文件替换现有AOF文件(改名操做)。
# yes : 在日志重写时,不进行命令追加操做,而只是将其放在缓冲区里,避免与命令的追加形成DISK IO上的冲突。
# no : 在日志重写时,命令追加操做照常进行。
no-appendfsync-on-rewrite no
# 当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,若是以前没有重写过,则以启动时的AOF文件大小为依据
auto-aof-rewrite-percentage 100
# 容许重写的最小AOF文件大小
auto-aof-rewrite-min-size 64mb
AOF 方式优势
该机制能够带来更高的数据安全性,即数据持久性。
因为该机制对日志文件的写入操做采用的是append模式,所以在写入过程当中即便出现宕机现象,也不会破坏日志文件中已经存在的内容。然而若是咱们本次操做只是写入了一半数据就出现了系统崩溃问题,不用担忧,在Redis下一次启动以前,咱们能够经过redis-check-aof工具来帮助咱们解决数据一致性的问题。
若是日志过大,Redis能够自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会建立一个新的文件用于记录此期间有哪些修改命令被执行。所以在进行rewrite切换时能够更好的保证数据安全性。
AOF包含一个格式清晰、易于理解的日志文件用于记录全部的修改操做。事实上,也能够经过该文件完成数据的重建。
AOF 方式缺点
对于相同数量的数据集而言,AOF文件一般要大于RDB文件,持久化文件会变的愈来愈大。
根据同步策略的不一样,AOF在运行效率上每每会慢于RDB。
虚拟内存方式和diskstore方式这里不作说明
redis 键
Redis的键是二进制安全的,这意味着您可使用任何二进制序列做为键 。
Redis String类型是能够与Redis密钥关联的最简单的值类型。它是Memcached中惟一的数据类型。
使用SET和GET命令是咱们设置和检索字符串值的方式。请注意,即便密钥与非字符串值相关联,SET也将替换已存在于密钥中的任何现有值。
SET命令有有趣的选项,这是做为附加参数。例如,若是密钥已经存在,我可能会要求SET失败,或者相反,若是密钥已经存在,它只会成功:详情
> set mykey newval nx
(nil)
> set mykey newval xx
OK
# EX seconds - 设置指定的过时时间,以秒为单位。
# PX 毫秒 - 设置指定的过时时间,以毫秒为单位。
# NX - 仅设置密钥(若是密钥尚不存在)。
# XX - 仅设置密钥(若是密钥已存在)。
字符串的操做还有一些其余的命令,以下:
> set counter 100
OK
> incr counter
(integer) 101
> incr counter
(integer) 102
> incrby counter 50
(integer) 152
INCR
: 解析字符串值做为整数,以一增长它,最后将得到的值做为新的值。还有其余相似的命令,如INCRBY, DECR和DECRBY。在内部,它始终是相同的命令,以稍微不一样的方式运做。 (INCR是原子操做,即便是针对相同密钥发布INCR的多个客户端也不会进入竞争状态 )
GETSET
: 将键设置为新值,并将旧值做为结果返回 。
在单个命令中设置或检索多个键的值的能力对于减小延迟也是有用的。所以,有MSET和MGET命令:
> mset a 10 b 20 c 30
OK
> mget a b c # 使用MGET时,Redis返回值数组。
1) "10"
2) "20"
3) "30"
EXISTS
:返回1或0以表示数据库中是否存在给定键。
DEL
:删除键和关联值,不管值是什么。
> set mykey hello
OK
> exists mykey
(integer) 1
> del mykey
(integer) 1
> exists mykey
(integer) 0
能够看到DEL自己如何返回1或0,具体取决于密钥是否被删除(它是否存在)(没有具备该名称的密钥)。
有许多与密钥空间相关的命令,但上面两个是与TYPE命令一块儿必不可少的命令,它返回存储在指定键中的值的类型:
> set mykey x
OK
> type mykey
string
> del mykey
(integer) 1
> type mykey
none
redis strings 其余命令说明
命令 | 说明 |
---|---|
INCR key | 将 key 中储存的数字值增一。 |
INCRBY key num | 将 key 所储存的值加上给定的增量值(num)。 |
DECR key | 将 key 中储存的数字值减一。 |
DECRBY key num | key 所储存的值减去给定的减量值。 |
APPEND key value | 若是 key 已经存在而且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值的末尾。 |
默认状况下键是没有生存时间的,永不过时,除非使用del来清除键。
设置到期时间
设置到期时间方法入下:
strings类型,SET命令是能够直接经过EX,PX来指定过时时间。
全部类型均可以使用,EXPIRE、PEXPIRE、EXPIREAT、PEXPIREAT 这四个命令来进行生存时间的设置。
命令 | 说明 |
---|---|
EXPIRE KEY #s | 将KEY的生存时间设置为#秒 |
PEXPIRE KEY #ms | 将KEY的生存时间设置为#毫秒 |
EXPIREAT KEY timestamp | 将KEY的生存时间设置为UNIX时间戳,单位为秒 |
PEXPIREAT KEY timestamp | 将KEY的生存时间设置为UNIX时间戳,单位为毫秒 |
TIME | 一个包含两个字符串的列表: 第一个字符串是当前时间(以 UNIX 时间戳格式表示),而第二个字符串是当前这一秒钟已经逝去的微秒数。 |
上面这4个命令只是单位和表现形式上的不一样,但实际上EXPIRE、PEXPIRE以及EXPIREAT命令的执行最后都会使用PEXPIREAT来实行。
查看key的到期时间
Key的到期时间可使用 TTL
和PTTL
来进行查看,分别返回秒和毫秒单位级别。
清除key的到期时间
可使用PERSIST
命令移除一个键的过时时间 。
> set key 100
OK
> EXPIRE key 100
(integer) 1
> get key
"100"
> ttl key
(integer) 92
> PERSIST key
(integer) 1
> ttl key
(integer) -1
到期时间返回值说明
返回值 | 说明 |
---|---|
-2 | 过时且已删除 |
-1 | 没有过时时间设置,即永不过时 |
>0 | 表示距离过时还有多少秒或者毫秒 |