一、简介 Redis是基于内存的存储,所有数据都工作与内存中,基于键值存储(key-value store),经常拿来跟memcached做比较;memcached没有持久能力,Redis有持久能力,可以把内存中的数据写入到磁盘中;memcached是多线程服务器,redis是单线程服务器,一个线程响应所有的客户端请求。
Redis的数据的持久可以有两种机制来实现:一是基于RDB,另一种机制是基于AOF来实现。
从本质上来讲Redis是一个高级的key-value store 和数据结构存储,Redis出了能存储键值这种简单的格式的数据,还能存储列表、集合、字典、hash等数据类型的数据。
Redis 也支持主从,默认有一个工具sentinel来实现redis的主从架构,并实现主服务器的高可用。
官方网站:https://redis.io/
二、试验环境
CentOS 6.6
IP: node1: 10.0.0.6 node2: 10.0.0.7 node3: 10.0.0.8
二、安装部署
可以源码安装(官方下载),也可以yum安装(需要epel源),我这里yum安装。
[root@linux-node1 ~]# yum install redis [root@linux-node1 ~]# rpm -ql redis
yum安装redis的配置文件默认: /etc/redis.conf
daemonize yes //以守护进程的方式启动,如果以脚本的方式来启动redis,即便这项设为no,也会以守护进程的方式启动,不然以redis-server启动就会占据前台
port 6379 //默认为6379端口
bind 0.0.0.0 //监听端口,这样是监听本机所有地址
tcp-backlog 511 // tcp-backlog的长度
unixsocket /tmp/redis.sock //也可以使用sock的方式进行通信
unixsocketperm 700 //sock 文件的访问权限
timeout 0 //设置客户端连接超时时间,一个客户端连接空闲多长时间以后让他超时,0表示禁用此功能,客户端连接不超时
pidfile /var/run/redis_6379.pid //pid文件
logfile /var/log/redis/redis.log //日志文件
databases 16 //默认我们把所有数据都放在0号数据库中,
# save "" //持久化存储的频率,为空表示禁用
save 900 1
save 300 10
save 60 10000
redis的启动脚本: /etc/rc.d/init.d/redis
启动redis的方式:
service redis start
# redis-server /etc/redis.conf
检查启动的结果:
[root@linux-node1 ~]# ss -tnl | grep 6379
LISTEN 0 128 *:6379 *:*
客户端: redis-cli
[root@linux-node3 ~]# redis-cli -h 10.0.0.9 -p 6379 10.0.0.6:6379>
三、Redis持久化
Redis数据是工作在内存中,无论是否实现持久化,数据都是存储在内存中的,如果数据不重要就可以不用持久化,如果数据非常重要就必须实现其持久化。
两种机制的持久化:RDB和AOF(Appending Only File)
RDB是一种快照机制,按照某周策略周期性的将数据写入到磁盘中,数据文件默认为:dumo.rdb,这种持久化的缺点是可能数据会不完整,因为它的这种持久化是有时间差的。
AOF从本质上来讲就是将redis每一个操作的命令,都以顺序IO的方式附加在指定文件的尾部,记录每一个redis的写操作命令,类似于mysql的binlog机制。但是这种持久化也有缺点:因为以追加的方式向文件中写数据,文件会越来越大,而且有些命令是冗余的,AOF的重写机制可以解决这种问题。
RDB:
vim /etc/redis.conf
SAVE 900 1
SAVE 300 10
SAVE 60 10000
SAVE "" //关闭RDB功能
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
AOF:
vim /etc/redis.conf
appendonly no //默认为没有开启aof功能
appendfilename "appendonly.aof" //aof文件
# appendfsync always //每次收到写命令就写入磁盘的aof文件,这种方式最安全,但是会有大量的io,影响性能
appendfsync everysec //每秒将写命令写入磁盘aof文件,这是在性能和持久化二者之间做了一个折中的操作,是推荐使用的方式
# appendfsync no //append的功能不会触发写操作,所有写操作都是提交给os,由操作系统自行决定是如何写入磁盘
no-appendfsync-on-rewrite no //在重写时对新写的操作不做fsync,而是暂存在内存中,如果确保内存足够可高,建议写成yes,以提升起性能
auto-aof-rewrite-percentage 100 //当前的aof文件是上次重写时的1倍时,就开始aof文件的重写
auto-aof-rewrite-min-szie 64mb //当aof文件超过64mb时才重写aof文件,如果小于64mb,即使当前aof文件是上次重写时的一倍时也不会重写,否则文件重写频繁了
注意:上述配置也可以在命令行中设置"CONFIG SET XXX",但是在命令行中配置只对当前进程有效,如果想一直生效,就必须使用 CONFIG REWRITE命令,将配置写入到配置文件中去。
示例:
[root@linux-node1 ~]# redis-cli
127.0.0.1:6379> CONFIG SET appendonly yes //表示开启aof功能
特别强调: 持久并不能取代数据备份,还应制定备份策略,对redis数据库进行定期备份,如果我们同时启动了RDB和AOF功能,如果RDB正在创建快照,并且其他条件也触发了AOF重写,这个时候对磁盘的IO影响非常大,一般而言redis会自动禁止这种情况发生,也就是说BGSAVE的过程中,对应的BGREWRITEAOF不会执行,反之也亦然。如果BGSAVE正在执行,用户自己手动执行了BGREWRIGEAOF命令,这个时候服务器会向用户返回一个OK,并告诉用户请求已收到,但是不服务器不会执行这个命令,服务器会等BGSAVE完成以后再来执行BGREWRITEAOF命令。
RDB和AOF同时启动时: 1、redis的RBD和AOF重写是不能同时进行的 2、在redis服务器启动时用于恢复数据时,会优先使用AOF
四、Redis 复制(replication)
特点: 一个Master可以有多个slave 支持链式复制
Master 以非阻塞方式同步数据只slave,这也就意味着master会继续处理一个或多个请求,我们可以只放master进行写操作,slave端进行读操作, 当用户向主服务器端写数据时,redis通过sync机制,将数据发往slave,slave也会执行相同的操作,也就是说master可以有多个slave,一个slave也可以是其他slave的master,这样就实现了链式复制。
启动一个slave后,slave会向master发送一个sync命令,请求同步主库上的数据,无论slave是第一次连接还是重新连接,master都会启动一个后台子进程,将数据快照保存至数据文件中,把数据文件发送给slave,slave收到数据文件后会保存到本地,并将文件的数据载入到内存中,以实现数据在slave端的重建,实现数据的复制。
node1: 10.0.0.6 master
node2: 10.0.0.7 slave
node3: 10.0.0.8 slave
配置主从复制很简单:
slave: vim /etc/redis.conf
vim /etc/redis.conf //rpm包安装的路径,源码安装路径有所不同
slaveof MASTER_IP MASTER_PORT
slave: 命令行接口
> SLAVEOF host port
执行过程:
node1:
[root@linux-node1 ~]# service redis start
启动 : [确定]
[root@linux-node1 ~]# redis-cli -h 10.0.0.6 -p 6379
10.0.0.6:6379>
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0 //还没有slave加入进来
master_repl_offset:99
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:98
node2:
[root@linux-node2 ~]# redis-server /usr/local/redis/redis.conf
[root@linux-node2 ~]# redis-cli
127.0.0.1:6379>
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:608f508dfbc0ae2684af034e53083b7e2bb664d7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> SLAVEOF 10.0.0.9 6379
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:10.0.0.9
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:449
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:ea8c42a38cb835dce9fa02d1dcc367f6e54d3d4e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:449
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:450
repl_backlog_histlen:0
再在node1上检查:
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1 //可以看到slave的信息
slave0:ip=10.0.0.16,port=6379,state=online,offset=547,lag=0
master_repl_offset:547
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:546
测试主从:
node1:
127.0.0.1:6379> SET student jerry
OK
127.0.0.1:6379> GET student
"jerry"
node2:
127.0.0.1:6379> GET student
"jerry"
五、sentinel实现master的高可用
配置文件: /etc/redis-sentinel.conf
vim /etc/redis-sentinel.conf
port 26379 //默认监听端口
# sentinel monitor <master-name> <ip> <redis-port> <quorum> //这项最重要,指明监控的master
sentinel monitor mymaster 10.0.0.6 6379 2
# Default is 30 seconds. //sentinel认为服务器不在线最少经过的秒数,判断某节点不在线的超时时间,默认为毫秒
sentinel down-after-milliseconds mymaster 30000
# sentinel parallel-syncs <master-name> <numslaves> //指定了在执行故障转移时,最多可以有多少个从服务器对新主服务器进行同步
entinel parallel-syncs mymaster 1
# sentinel failover-timeout <master-name> <milliseconds> //故障转移超时时长,也就是说master故障时,把一个slave提升为master的最长时间
# Default is 3 minutes.
sentinel failover-timeout mymaster 180000
示例:三个节点(1个master节点,2 slave节点,1 sentinel)
node1: master 10.0.0.6
node2: slave 10.0.0.7
node3 : slave 10.0.0.8
在 node1, node2, node3安装redis(需要有epel源)
# yum -y install redis
在node1, node2, node3修改配置文件
# vim /etc/redis.conf
daemonize yes //以守护进程的方式启动
bind 0.0.0.0 //监听在本机的所有地址
启动node1, node2,node3 redis,还没有设置主从复制
node1:
[root@linux-node1 ~]# redis-server /etc/redis.conf
[root@linux-node1 ~]# ss -tnl | grep redis-server
[root@linux-node3 ~]# ss -tnl | grep 6379
LISTEN 0 128 *:6379 *:*
[root@linux-node1 ~]# redis-cli
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379>
node2: //这个是CentOS 7下手动源码安装的 redis-4.0.10,这个没有没有影响
[root@linux-node2 ~]# redis-cli
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:0
master_replid:6678af3be5f3af43963f5018fc767c8991945239
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379>
node3:
[root@linux-node3 ~]# redis-cli
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379>
设置主从:设置node2,node3为slave
node2:
> CONFIG SLAVEOF 10.0.0.6
node3:
> CONFIG SLAVEOF 10.0.0.8
验证主从:
node1:
[root@linux-node3 ~]# redis-cli
127.0.0.1:6379> INFO replication
# Replication
role:master //master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.7,port=6379,state=online,offset=365,lag=1
slave1:ip=10.0.0.8,port=6379,state=online,offset=365,lag=0
master_repl_offset:365
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:364
127.0.0.1:6379>
node2:
[root@linux-node2 ~]# redis-cli
127.0.0.1:6379> SLAVEOF 10.0.0.6 6379
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave //slave
master_host:10.0.0.6
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:57
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:d1c08312fe30d1259d943f1a09bd7aa5b7bebf01
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:57
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:30
repl_backlog_histlen:28
127.0.0.1:6379>
node3:
[root@linux-node3 ~]# redis-cli
127.0.0.1:6379> SLAVEOF 10.0.0.6 6379
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave //slave
master_host:10.0.0.6
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:253
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379>
这样我们的主从复制就配置好了,为了进一步验证主从复制,我们在master上写入数据,查看下slave上面的数据情况
node1:
127.0.0.1:6379> SET cache memcached
OK
127.0.0.1:6379> GET cache
"memcached"
node2:
127.0.0.1:6379> GET cache
"memcached"
node3:
127.0.0.1:6379> GET cache
"memcached"
启动sentinel服务监控master
为了节约机器,我们把node1设置为sentinel
修改配置文件: /etc/redis-sentinel.conf
# vim /etc/redis-sentinel.conf
port 26379 //默认监听26379端口
daemonize yes //工作在守护进程模式
sentinel monitor mymaster 10.0.0.6 6379 1 //设置监控的master,因为只有sentinel节点,所以quorum置为1,这个参数必须设置
sentinel down-after-milliseconds mymaster 5000 //默人为30000,做实验可以设置为时间短一点,5秒以后认为master不在线
sentinel failover-timeout mymaster 60000 //故障转移多长时间不成功就认为是失败的,默人为180000(3分钟)
我们就修改这几项,保存退出
启动sentinel: redis-server 或者redis-sentinel
root@linux-node1 ~]# redis-sentinel /etc/redis-sentinel.conf
[root@linux-node1 ~]# ss -tnl | grep 26379
LISTEN 0 128 *:26379 *:*
LISTEN 0 128 :::26379 :::*
root@linux-node1 ~]# redis-server /etc/redis-sentinel.conf --sentinel
[root@linux-node1 ~]# ss -tnl | grep 26379
LISTEN 0 128 *:26379 *:*
LISTEN 0 128 :::26379 :::*
验证sentinel对master的HA
sentinel节点(node1):
[root@linux-node1 ~]# redis-cli -h 127.0.0.1 -p 26379
127.0.0.1:26379> SENTINEL slaves mymaster
127.0.0.1:26379> SENTINEL masters
下线node1 上的master查看master是否会自动转移,是否会从2个slave中选一个作为master
127.0.0.1:26379> SENTINEL masters
1) 1) "name"
2) "mymaster"
3) "ip"
4) "10.0.0.7" //可以看出master已经转移
在node2上查看
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
让node1上的redis上线,查看主从复制情况,node1上的redis是slave,而不会成为master,因此当一个下线的master重新上线时,也不会成为master,而是slave。