一、简介 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。