深入学习Redis(二) Redis安装及配置

Redis安装及配置

说明:本系列文档是16年前写的,当时是在WORD里现在粘贴过来。

1. Reids安装

Redis安装非常方便,首先通过官网去下载最新版本,官网地址: http://redis.io/download 

Redis除了可以安装在Linux上还可以安装在Windows上,不过在Windows平台上的Redis并不是Redis官方支持的,它是由Microsoft Open Tech 小组开发并维护的。

Redis并不依赖任何非标准数据库,也没有编译必须要添加的参数,安装非常简单。我们这里使用3.0版本。先安装一下基础环境(CentOS 6.5):

从这里下载: http://download.redis.io/releases/redis-3.0.7.tar.gz 

解压并测试所需条件,该命令是压缩包里自带的命令,提示需要安装tcl 8.5以上版本

安装tcl

安装jemalloc分配器,这个分配器源码已经包含在Redis源码包里了,在dev目录里面,如下图:

安装方式如下:它会把下面这4项进行编译安装,这都是Redis所依赖的

编译安装Redis

这时候再去运行make就不会报错了。可以通过在make PREFIX=目录 install(如果执行了这个命令,就不需要再执行make install了)来设置安装目录,我这里使用默认的。

运行 make install

注意:如果你想安装在不同目录里,必须使用make PERFIX=/DIRECTORY/ install方式,如果这条命令后面没有跟install,那么运行make不会出错,但是最后安装完成后依然是默认的目录而不是你自己指定的目录。如果使用指定目录安装,安装后指定目录里面只有bin文件夹,需要手动建立etc来存放配置文件。

1.2 安装后的程序及配置文件位置

安装后默认的Redis程序放在了/usr/local/bin下面,如下图:

程序名称 用途
redis-server Redis服务的daemon启动程序
redis-cli 命令行工具,当然也可以使用telnet来连接
redis-benchmark 性能测试工具,测试redis在当前硬件条件下的读写性能
redis-check-aof 用于修复出现问题的AOF文件
redis-check-dump 用于修复出现问题的dump.rdb文件
redis-sentinel 用于sentinel集群管理

 

 

 

 

 

 

 

配置文件位置在源码包中,安装并不会复制配置文件,需要手动拷贝配置文件。操作如下:先在/etc/下面建立一个文件夹名称为redis,这也是为了便于管理

这里要把配置文件改个名词,改成6379.conf,为什么呢?因为跟启动脚本里面的CONF这个变量的设置有关,它默认使用的是REDISPORT这个变量为配置文件名称,下一节就会看到。

1.3 设置启动信息

拷贝源码包中的启动脚本文件(源码包中的utils目录下)到/etc/rc.d/init.d目录下,如下图:

修改脚本信息

执行程序(EXEC)路径就是默认的安装路径,如果我们的安装路径改了,这里也需要修改。

PID文件(PIDFILE)是PID路径,可以使用默认,不过我这里修改了,因为我在后面的配置文件中也做了修改,这里的路径一定要和配置文件中的是对应的。

配置文件(CONF)默认路径就是/etc/redis/ 所以我们之前建立这个文件夹并拷贝配置过去,但是这里要注意CONF的文件名称是6379.conf,因为这个路径里面有一个变量。

修改配置文件用于支持daemon启动,默认是no,需要改为yes。如果不修改,那么redis的启动将会占用一个终端界面,修改后将会后台运行。

修改PID和LOG路径,如下图

建立/var/redis/run和/var/redis/log目录,如下图:

修改本地数据库快照和AOF文件存放路径,如下图:
这个目录就行存放快照数据库(扩展名为rdb,默认文件名为dump.rdb)文件的地方,同时如果启用了AOF持久化功能,那么AOF文件也会放到这个目录中。

建立目录,如下图:

1.4 注册服务

下面只是针对于CentOS 6.X的服务器启动脚本设置,如果是CentOS 7.X则不推荐这样设置,建议使用system的方式。

默认情况下redis不支持服务注册,会报错。

在拷贝到/etc/rc.d/init.d/中的redis脚本中修改如下:

加入chkconfig: 2345 90 10。

2345是运行级别,就是告诉chkconfig程序,需要在rc2.d、rc3.d、rc4.d和rc5.d目录下创建名为S90redis的文件链接,链接到/etc/rc.d/init.d目录下的redis脚本。第一个字符是S,系统在启动的时候运行脚本redis,会添加一个start参数告诉脚本现在是启动模式。同时在rc0.d和rc6.d目录下创建名称为K10redis的文件链接,可以字符为K,表示系统在关闭的时候运行这个脚本,添加一个stop的参数,告诉脚本现在是关闭模式。

再次注册就不会报错了

我们看一下rc2.d里面的文件,如下图:

其实这个90或者10这2个号码是自定义的,号码重了也没关系毕竟整体名字不同。上面的注册服务过程并不是表示在2345级别就自动启动了, 只是表示可以自动启动或关闭,如果要想设置成35运行级别启动,还需要运行下面的命令:

chkconfig --level 35 redis on

总结一下:

  • 真正的脚本程序在/etc/rc.d/init.d里面,而/etc/rc-0-6.d里面的都是链接文件,链接的都是/etc/rc.d/init.d里面的真正脚本程序。

  • rc0-6.d对应的是7个不同运行级别
  • 链接文件的的命名规则是S+数字+服务名称或者K+数字+服务名称,S表示start,K表示kill。
  • 系统会根据设置的启动级别,来找对应的rcN.d文件,然后去执行链接文件,S开头的表示当前运行级别需要启动这程序,K则表示不启动需要停止。

如果还是对chkconfig不太了解可以去查看相关资料我这里给大家推荐两个:

http://blog.csdn.net/chenxiaohua/article/details/4056302
http://blog.csdn.net/monkey_d_meng/article/details/5573580

1.5 关于分配器(Allocator)说明

查看压缩包目录下的README文档,如下图:

Redis安装时使用的默认分配器为jemalloc,如果你的系统没有那么安装Redis就会报错,如下图:

提示说没有这个文件或者目录

MALLOC是一个环境变量,如果有这个环境变量就会用这个变量去建立Redis,如果没有就需要在安装的时候指定这个参数。一般情况下系统是没有这个环境变量的。

libc并不是Redis默认的分配器,默认的是jemalloc,因为这个分配器的性能比libc要好,主要反映在内存碎片率上(内存碎片太多,对纯内存数据的性能是有很大影响的)。Redis在编译的时候,先判断是否使用tcmalloc(是google的内存分配管理模块),如果是,就会用tcmalloc对应的函数替换掉标准的libc中的函数。如果没有就会判断是否使用jemalloc(BSD提供的内存分配管理模块),如果都没有就会使用标准的libc中的内存管理函数。

如果不想使用jemalloc分配器,那么在make MALLOC=libc 就可以解决上面那个报错。

1.6 启动服务

运行redis命令行工具,并建立一个简单的KEY-VALUE

2. 配置持久化

2.1 RDB持久化(快照方式)

配置过程:

默认快照方式是开启的,Redis会根据快照保存策略把快照写入到dump.rdb(默认名称)文件中,该文件保存位置可以在配置文件中设置,就是dir配置项。

默认保存策略如下:

命令行有一个save或者gbsave命令,作用是把数据同步到dump.rdb中,不过这两个命令的是有区别的,在原理部分会谈到。

如果想从dump.rdb中恢复数据,只需把这个文件放到工作目录即可。

原理:

RDB持久化可手动运行也可以自动定期执行,然后把某个时间点的数据库状态保存到RDB文件中,默认是dump.rdb,该文件是一个经过压缩的二进制文件,上面已经说了如何去配置策略和使用命令。下面来说一下save和gbsave的区别。

SAVE命令运行后会阻塞Redis服务器进程,直到RDB文件创建完毕,在阻塞过程过程中服务器不处理任何来自外界的请求无论读还是写(阻塞所有请求)。

BGSAVE命令与SAVE不同,该命令会产生一个子进程,由此子进程来处理创建RDB文件任务,而服务器的父进程继续响应外部请求。

BGSAVE在执行过程中不会阻塞请求,但是并不是说任何请求都可以被执行,在服务器执行BGSAVE期间,对于执行SAVE、BGSAVE和BGREWRITEAOF这三个命令会有所有不同:

在服务器执行gbsave期间
执行save命令 会被服务器拒绝,服务器禁止SAVE命令和BGSAVE同时执行,因为不可能让两个命令去调用同一函数然后去操作同一个RDB文件。
执行bgsave命令 会被服务器拒绝,因为已经有一个在进行了,没必要再允许一个。
执行bgrewriteaof命令 会被延迟执行,BGSAVE子进程完成后,才会执行BGREWRITEAOF命令

 

 

 

 

在服务器执行brwriteaof期间:执行bgsave,会被拒绝,这两个命令没有冲突的地方,只是同时执行会产生大量磁盘写操作,会影响性能,所以这是一个规则上的拒绝,不是一个技术上的拒绝。

上面提到了保存策略,那么这个保存策略是如何被执行的呢?

简单来说就是三个内容,条件、计数器与上次保存时间、检查器。检查器周期性(默认100毫秒,由serverCron服务器周期性函数执行)检测计数器与上次保存时间是否满足条件组合之一(save 900 1、save 300 10、save 60 10000),是则执行BGSAVE。

计数器dirty:用于记录修改次数、上次保存时间lastsave:用于保存上次保存的时间。

注意:Redis模式会运行16个数据库(编号为0---15),在执行保存的过程中无论是SAVE触发还是BGSAVE触发,都是会把所有非空数据库进行保存的。
另外我们可以通过od命令来查看dump.rdb文件内容,如下图:

2.2 AOF持久化

2.2.1 配置

AOF持久化的配置,默认AOF方式是关闭的,如下图:

如果要开启就把 no 改成 yes

默认文件名称appendonly.aof,你也可以修改文件名。默认保存目录同样也是配置文件中dir配置项中的设置,它和RDB共用一个目录。如下图:

默认同步策略是秒

我们对数据库做一些操作然后查看一下appendonly.aof文件内容

含义
*2 表示2个参数
$6 表示第一个参数长度为6
SELECT 第一个参数值
$1 第二个参数长度为1
0 第二个参数值

 

 

 

 

 

自动重写策略:

2.2.2 AOF持久化实现原理

当AOF持久化开启后,当对数据库进行一次更新操作后,更新命令就会被追加到aof_buf缓冲区的末尾,然后由缓冲区写入到AOF文件。

AOF文件中记录的内容就是对数据更新操作的指令。这个文件本身就是以文本来记录的,如下图:

2.2.3 AOF重写实现原理

因为AOF持久化是通过记录命令的方式来保存数据库状态的,随着时间的推移AOF文件肯定会逐渐增大,如果不加以控制会对AOF持久化性能以及数据恢复造成影响。下面举例

来更加形象的说明重写的必要:

我们以一个压缩列表为例

根据AOF的原理,那么上面红色方框中的5条命令都要追加到AOF文件中,其实我们看到最后list的状态就是BCDEF值。也就是说为例实现最后的状态,需要追加5条命令。所以在大量内存读写的业务里AOF文件增长的很快,为例解决这个问题,Redis提供了AOF重写功能。

AOF重写就是创建一个新的AOF文件来替换现有的AOF文件,实际上AOF重写并不对现有的旧AOF文件进行操作。

以上面例子来说,当进行重写的时候直接从数据库里去获取list的最新状态,然后在新的AOF文件中直接写一条rpush list 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文件中,这会降低性能。)
  • AOF重写完成后子进程通知父进程,父进程调用信号处理函数
  • 信号处理函数会阻塞父进程对外提供读写操作(时间很短,不阻塞就又会出现数据不一致的情况),然后将AOF重写缓冲区的内容写入到新的AOF文件中,最后用新的AOF文件替换现有AOF文件(更名操作)

APPENDFSYNC选项说明:

在Redis配置文件中关于AOF同步频率有3个可选项,如下:

参数 说明
always 将aof_buf缓冲区中的所有内容写入并同步到AOF文件中,立即执行write()和fsync()系统调用。对于数据的安全性最高,但是执行最慢,如果出现故障只会丢失一个事件循环的内容.
everysec 将aof_buf缓冲区的所有内容写入到AOF文件,如果上次同步AOF的时间距离本次超过1秒,则执行同步,每隔一秒执行一次write()和fsync()系统调用。数据安全性居中,执行快,仅会丢失1秒的数据。
no 将aof_buf缓冲区的所有内容写入到AOF文件,但是何时同步由操作系统决定,仅执行write()系统调用。写入动作效率高,但是不执行同步,但是单次同步消耗时间最长,数据安全性最低,会丢失上一次同步之后的所有数据。

 

 

 

 

这里要特别说明一下Linux系统的文件写入和同步原理,为什么要说这个,因为不解释一下这个过程,你就很难理解APPENDFSYNC选项中的no参数,如果把Always理解为总是、一直或者实时;而把everysec理解为每秒的话,那no的含义难道是不执行AOF文件同步吗?如果不同步文件,那开启AOF持久化干嘛呢?

在Redis调用appendfsync函数的时候,其实是先调用一个write()函数,然后再调用sync()或者fsync()函数(对于任何程序来说只要想把数据写入磁盘其过程都一样,有些也有例外)。

用户空间:常规进程所在区域,用户发起的,此区域的代码不能直接访问硬件

内核空间:操作系统所在区域,能和设备控制器通讯

当调用了write()函数时,该函数一旦返回正常值,我们可能就认为数据已经写入到了磁盘,但实际上,操作系统在实现磁盘文件的IO时,为了保证IO的效率,会在内存中使用一段专门的地址空间,该空间叫做内核空间,而内核空间之内又会有一段是用作IO的数据缓冲区(这个缓冲区和之前说的aof_buf缓冲区不是一个概念,虽然都在内存中),write()函数的作用就是把数据写入到内核空间的IO缓冲区中。

内核空间的IO缓冲区也有一定大小,当该缓冲区没有写满时或者没有到一个同步周期时,会持续的把write()函数传递的数据写入到该缓冲区中,而当该缓冲区写满或者到了一个同步周期,则会把该缓冲区的内容提交到输出队列,当需要数据到达队列队首的时候,开始执行真正的磁盘IO操作,把数据写入磁盘(这里虽然用来写入磁盘,但是真正的动作不是移动而是复制,复制完成之后,内核空间的IO缓冲区才会释放该数据占用的空间)。这种方式叫做延迟写入。

所以这就会出现一个问题,当调用了write()函数后并不等于数据真的保存到了磁盘,但是这里又会有一个错觉,就是你再次请求该文件的时候,可以显示你最后一次更新的内容,其实这个内容并不是从磁盘上读取过来的,而是从用户空间的缓冲区读取的。接着刚才提到的问题,如果数据在内核空间的IO缓冲区内,而此时操作系统出现故障、断电等异常情况就会造成数据丢失。

为了解决数据丢失问题,Unix系统提供了sync、fsync和fdatasync三个函数。

  • sync:函数返回0表示成功,该函数负责把所有内核空间中IO缓冲区内修改过的内容推送到输入队列,然后就返回,它并不等待所有磁盘IO操作完成。所以即使调用了sync函数,也不等于成功保存到磁盘了。
  • fsync:函数返回0表示成功,与sync不同,它只会对指定文件描述符的单一文件生效,强制与该文件相连的所有修改过的数据传送到磁盘上,并且等待磁盘IO完毕,然后返回。当该函数返回0时,才真正表示成功保存到磁盘。数据库会在调用了write()之后调用fsync()。
  • fdatasync:它与fsync类似,它只影响文件数据部分,不涉及数据属性,比如inode信息。所以相对于fsync它需要较少的写磁盘操作。

所以看了上面的内容,你就知道APPENDFSYNC中no参数的含义。

2.3 RDB和AOF的优先级

AOF文件更新频率比RDB高,所以如果服务器同时开启了AOF和RDB持久化功能,那么服务器会优先使用AOF进行数据恢复而不会使用RDB文件进行恢复。只有当AOF处于关闭状态时,服务器才会用RDB文件来恢复。

3. Redis配置文件主要参数说明

daemonize
# 如果为yes,则启动服务的时候为后台运行,如果是no,则相反
pidfile
# 指定存储redis进程号的文件路径
Port
# 指定当前redis服务的端口号,默认问6379
tcp-backlog
#确定了TCP连接中已完成队列(完成三次握手之后)的长度,此值不应大于linux系统定义的/proc/sys/net/core/somaxconn值。默认是511,而Linux的默认参数是128。当系统并发量大且客户端速度缓慢的时候,可以将这两个参数一起参考设定。
timeout
# 客户端和redis服务器连接超时时间,默认是0,永不超时。
tcp-keepalive
# 如果值是非0,单位是秒,表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,避免服务器一致阻塞,官方建议是60s。
loglevel
# 日志级别,总共有4个级别:
#   Debug:记录更多信息,用于开发和测试
#   Varbose:有用的信息,比debug记录的少
#   Notice:普通的varbose,常用于生产环境
#   Warning:只有非常重要或者严重的信息会被记录到日志
# 默认为notice级别
logfile
# 日志存储路径
databases
# 可用的数据库数量,默认值为16,默认数据库为0,数据库范围在0---(database-1)之间,这个DB概念类似于命名空间。
Save
# 保存数据库快照到磁盘,其对应的值有2个,比如save 300 10,表示300秒内至少有10个key被改变时,触发保存信息到磁盘事件。默认有3个保存策略。
stop-writes-on-bgsave-error
# 当持久化出现错误之后,是否继续提供写服务。
rdbcompression
# 持久化到RDB文件时,是否压缩,yes为压缩,no为不压缩
rdbchecksum
# 读取和写入的时候是否支持CRC64校验,默认是开启的
dbfilename
# 本地数据库快照文件名称,默认为dump.rdb
dir
# 本地数据库快照及AOF文件存放路径。
masterauth
# 设置访问master服务器的密码。
requirepass
# 用户设置连接密码, 任何尝试连接该服务器的客户端都需要提供密码才可以。在主从复制模式下,需在从节点的配置文件中的masterauth字段设置与此相同的密码;另外使用redis-cli客户端连接也需要加-p参数来指定密码。
slaveof
# 主从复制结构中,从服务器要配置此项,填写主服务的IP和端口。
slave-serve-stale-data
# 当slave服务器和master服务器失去连接后,或者当数据正在复制传输的时候,如果此参数值设置“yes”,slave服务器可以继续接受客户端的请求,否则,会返回给请求的客户端如下信息“SYNC with master in progress”
slave-read-only
# 是否允许slave服务器节点只提供读服务
repl-disable-tcp-nodelay
# 指定向slave同步数据时,是否禁用socket的NO_DELAY选 项。若配置为“yes”,则禁用NO_DELAY,则TCP协议栈会合并小包统一发送,这样可以减少主从节点间的包数量并节省带宽,但会增加数据同步到 slave的时间。若配置为“no”,表明启用NO_DELAY,则TCP协议栈不会延迟小包的发送时机,这样数据同步的延时会减少,但需要更大的带宽。 通常情况下,应该配置为no以降低同步延时,但在主从节点间网络负载已经很高的情况下,可以配置为yes。
slave-priority
# 指定slave的优先级。在不只1个slave存在的部署环境下,当master宕机时,Redis Sentinel会将priority值最小的slave提升为master。需要注意的是,若该配置项为0,则对应的slave永远不会自动提升为master。
appendonly
# 开启append only 模式之后,redis 会把所接收到的每一次写操作请求都追加到appendonly.aof 文件中,当redis 重新启动时,会从该文件恢复出之前的状态。但是这样会造成appendonly.aof 文件过大,所以redis 还支持了BGREWRITEAOF 指令,对appendonly.aof 进行重新整理。默认是不开启的。
maxmemory
# 最大内存使用设置,单位为bytes,达到最大内存后,Redis会先尝试清除已到期或即将到期的key,当使用此方法处理后仍然达到最大每次,那么将无法执行写入操作。
appendfilename
# Aof更新日志文件名称,默认为appendonly.aof。
appendfsync
# 设置aof的同步频率,有三种选择always、everysec、no,默认是everysec表示每秒同步一次。
no-appendfsync-on-rewrite
# 指定是否在后台aof文件rewrite期间调用fsync,默认为no,表示要调用fsync(无论后台是否有子进程在刷盘)。Redis在后台写RDB文件或重写afo文件期间会存在大量磁盘IO,此时,在某些linux系统中,调用fsync可能会阻塞。
auto-aof-rewrite-percentage
# 指定Redis重写aof文件的条件,默认为100,表示与上次rewrite的aof文件大小相比,当前aof文件增长量超过上次afo文件大小的100%时,就会触发background rewrite。若配置为0,则会禁用自动rewrite
auto-aof-rewrite-min-size
# 指定触发rewrite的aof文件大小。若aof文件小于该值,即使当前文件的增量比例达到auto-aof-rewrite-percentage的配置值,也不会触发自动rewrite。即这两个配置项同时满足时,才会触发rewrite。
lua-time-limit
# 一个Lua脚本最长的执行时间,单位为毫秒,如果为0或负数表示无限执行时间,默认为5000
notify-keyspace-events
# 见参考3,按键通知事件
aof-rewrite-incremental-fsync
# aof rewrite过程中,是否采取增量文件同步策略,默认为“yes”。 rewrite过程中,每32M数据进行一次文件同步,这样可以减少aof大文件写入对磁盘的操作次数

 

posted @ 2018-08-25 18:04  昀溪  阅读(281)  评论(0)    收藏  举报