5、Redis主从复制php
5.1 redis复制特性html
a 使用异步复制。node
b 一个主服务器能够有多个从服务器。python
c 从服务器也能够有本身的从服务器。nginx
d 复制功能不会阻塞主服务器。redis
f 能够经过复制功能来让主服务器免于执行持久化操做,由从服务器去执行持久化操做便可。数据库
关闭主服务器持久化时,复制功能的数据安全vim
当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。不然的话,因为延迟等问题,部署的服务应该要避免自动拉起。安全
为了帮助理解主服务器关闭持久化时自动拉起的危险性,参考一下如下会致使主从服务器数据所有丢失的例子:ruby
1. 假设节点A为主服务器,而且关闭了持久化。而且节点B和节点C从节点A复制数据
2. 节点A崩溃,而后由自动拉起服务重启了节点A。因为节点A的持久化被关闭了,因此重启以后没有任何数据
3. 节点B和节点C将从节点A复制数据,可是A的数据是空的,因而就把自身保存的数据副本删除
在关闭主服务器上的持久化,并同时开启自动拉起进程的状况下,即使使用Sentinel来实现Redis的高可用性,也是很是危险的。由于主服务器可能拉起得很是快,以致于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,而后仍是会执行上面的数据丢失的流程。
不管什么时候,数据安全都是极其重要的,因此应该禁止主服务器关闭持久化的同时自动拉起。
5.2 主从复制原理
redis 主从同步有两种方式(或者所两个阶段):全同步和部分同步。
主从刚刚链接的时候,进行全同步;全同步结束后,进行部分同步。固然,若是有须要,slave 在任什么时候候均可以发起全同步。
redis 策略是,不管如何,首先会尝试进行部分同步,如不成功,要求从机进行全同步,并启动 BGSAVE……BGSAVE 结束后,传输 RDB 文件;若是成功,容许从机进行部分同步,并传输积压空间中的数据。
下面这幅图,总结了主从同步的机制:
主从复制原理:
1. 从服务器向主服务器发送 SYNC 命令。
2. 接到 SYNC 命令的主服务器会调用BGSAVE 命令,建立一个 RDB 文件,并使用缓冲区记录接下来执行的全部写命令。
3. 当主服务器执行完 BGSAVE 命令时,它会向从服务器发送 RDB 文件,而从服务器则会接收并载入这个文件。
4. 主服务器将缓冲区储存的全部写命令发送给从服务器执行。
命令的传播:
在主从服务器完成同步以后,主服务器每执行一个写命令,它都会将被执行的写命令发送给从服务器执行,这个操做被称为“命令传播”(command propagate)。
命令传播是一个持续的过程:只要复制仍在继续,命令传播就会一直进行,使得主从服务器的状态能够一直保持一致。
5.3 复制中的SYNC与PSYNC
在 Redis 2.8 版本以前,断线以后重连的从服务器总要执行一次完整重同步(full resynchronization)操做。
从 Redis 2.8 开始,Redis 使用 PSYNC命令代替 SYNC 命令。PSYNC 比起 SYNC 的最大改进在于 PSYNC 实现了部分重同步(partial resync)特性:在主从服务器断线而且从新链接的时候,只要条件容许,PSYNC 可让主服务器只向从服务器同步断线期间缺失的数据,而不用从新向从服务器同步整个数据库。
5.4 复制的一致性问题
在读写分离环境下,客户端向主服务器发送写命令 SET n 10086,主服务器在执行这个写命令以后,向客户端返回回复,并将这个写命令传播给从服务器。
接到回复的客户端继续向从服务器发送读命令 GET n ,而且由于网络状态的缘由,客户端的 GET命令比主服务器传播的 SET 命令更快到达了从服务器。
由于从服务器键 n 的值还未被更新,因此客户端在从服务器读取到的将是一个错误(过时)的 n值。
5.5 复制安全性提高
主服务器只在有至少 N 个从服务器的状况下,才执行写操做从 Redis 2.8 开始,为了保证数据的安全性,能够经过配置,让主服务器只在有至少 N 个当前已链接从服务器的状况下,才执行写命令。
不过,由于 Redis 使用异步复制,因此主服务器发送的写数据并不必定会被从服务器接收到,所以,数据丢失的可能性仍然是存在的。
经过如下两个参数保证数据的安全:
min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>
5.6 Redis主从复制实践
在安装redis时就进行了多实例的配置
准备两个或两个以上redis实例
6380/redis-server
6380/redis.conf
6381/redis-server
6381/redis.conf
6382/redis-server
6382/redis.conf
配置文件示例:
bind 127.0.0.1 10.0.0.186
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
loglevel notice
logfile "/var/log/redis_6380.log"
dbfilename dump.rdb
dir /application/redis/6380/
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
slowlog-log-slower-than 10000
slowlog-max-len 128
protected-mode no
启动:
./6380/redis-server ./6380/redis.conf
./6381/redis-server ./6381/redis.conf
./6382/redis-server ./6382/redis.conf
复制环境说明:
主节点:6380
从节点:638一、6382
开启主从(在6381 6382实例中执行)
redis-cli -p 6381/6382
SLAVEOF 127.0.0.1 6380
至此redis主从复制完成
5.7 Redis主从复制管理
主从复制状态监控:info replication
主从切换: slaveof no one
Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis作Master-slave的高可用方案时,假如master宕机了,Redis自己(包括它的不少客户端)都没有实现自动进行主备切换,而Redis-sentinel自己也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。
Sentinel 是一个监视器,它能够根据被监视实例的身份和状态来判断应该执行何种动做。
6.1 Redis Sentinel 功能
监控(Monitoring):
Sentinel 会不断地检查你的主服务器和从服务器是否运做正常。
提醒(Notification):
当被监控的某个 Redis 服务器出现问题时,Sentinel 能够经过 API 向管理员或者其余应用程序发送通知。
自动故障迁移(Automatic failover):
当一个主服务器不能正常工做时,Sentinel 会开始一次自动故障迁移操做,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其余从服务器改成复制新的主服务器;当客户端试图链接失效的主服务器时,集群也会向客户端返回新主服务器的地址,使得集群可使用新主服务器代替失效服务器。
6.2 服务器链接
发现并链接主服务器:
Sentinel 经过用户给定的配置文件来发现主服务器。
Sentinel 会与被监视的主服务器建立
两个网络链接:
命令链接用于向主服务器发送命令。
订阅链接用于订阅指定的频道,从而发现监视同一主服务器的其余 Sentinel。
发现并链接从服务器:
Sentinel 经过向主服务器发送 INFO 命令来自动得到全部从服务器的地址。
跟主服务器同样,Sentinel 会与每一个被发现的从服务器建立命令链接和订阅链接。
发现其余 Sentinel:
Sentinel 会经过命令链接向被监视的主从服务器发送“HELLO” 信息,该消息包含Sentinel 的 IP、端口号、ID 等内容,以此来向其余 Sentinel 宣告本身的存在。与此同时Sentinel 会经过订阅链接接收其余 Sentinel 的“HELLO”信息,以此来发现监视同一个主服务器的其余 Sentinel 。
sentinel1 经过发送HELLO 信息来让sentinel2 和 sentinel3发现本身,其余两个sentinel 也会进行相似的操做。
多个Sentienl之间的连接:
Sentinel 之间只会互相建立命令链接,用于进行通讯。由于已经有主从服务器做为发送和接收 HELLO 信息的中介,因此 Sentinel之间不会建立订阅链接。
6.3 检测实例的状态
Sentinel 使用 PING 命令来检测实例的状态:若是实例在指定的时间内没有返回回复,或者返回错误的回复,那么该实例会被Sentinel 判断为下线。
Redis 的 Sentinel 中关于下线(down)有两个不一样的概念:
主观下线(Subjectively Down,简称 SDOWN)指的是单个Sentinel 实例对服务器作出的下线判断。
客观下线(Objectively Down,简称 ODOWN)指的是多个Sentinel 实例在对同一个服务器作出 SDOWN 判断,而且经过SENTINEL is-master-down-by-addr 命令互相交流以后,得出的服务器下线判断。(一个 Sentinel 能够经过向另外一个Sentinel 发送SENTINEL is-master-down-by-addr 命令来询问对方是否定为给定的服务器已下线。)
若是一个服务器没有在 master-down-after-milliseconds 选项所指定的时间内,对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply),那么 Sentinel 就会将这个服务器标记为主观下线。
6.4 故障转移FAILOVER
一次故障转移操做由如下步骤组成:
1. 发现主服务器已经进入客观下线状态。
2. 基于Raft leader election 协议,进行投票选举
3. 若是当选失败,那么在设定的故障迁移超时时间的两倍以后,从新尝试当选。若是当选成功,那么执行如下步骤。
4. 选出一个从服务器,并将它升级为主服务器。
5. 向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为主服务器。
6. 经过发布与订阅功能,将更新后的配置传播给全部其余 Sentinel,其余 Sentinel 对它们本身的配置进行更新。
7. 向已下线主服务器的从服务器发送 SLAVEOF 命令,让它们去复制新的主服务器。
8. 当全部从服务器都已经开始复制新的主服务器时,leader Sentinel 终止此次故障迁移操做。
6.5 配置sentinel
建立程序目录
cd /application
mkdir 26380
cp /usr/local/redis/src/redis-sentinel ./26380/
cd 26380
编辑配置文件
vim sentinel.conf
port 26380
dir "/tmp"
sentinel monitor mymaster 127.0.0.1 6380 2
sentinel down-after-milliseconds mymaster 60000
sentinel config-epoch mymaster 0
启动sentinel
./redis-sentinel ./sentinel.conf
配置文件说明
# 指定监控master
sentinel monitor mymaster 127.0.0.1 6370 2
# {2表示多少个sentinel赞成}
# 安全信息
sentinel auth-pass mymaster root
# 超过15000毫秒后认为主机宕机
sentinel down-after-milliseconds mymaster 15000
# 当主从切换多久后认为主从切换失败
sentinel failover-timeout mymaster 900000
# 这两个配置后面的数量主从机须要同样,epoch为master的版本
sentinel leader-epoch mymaster 1
sentinel config-epoch mymaster 1
6.6 Sentinel命令操做
命令 | 描述 |
PING | 返回 PONG |
SENTINEL masters | 列出全部被监视的主服务器 |
SENTINEL slaves <master name> | |
SENTINEL get-master-addr-by-name <master name> | 返回给定名字的主服务器的 IP 地址和端口号。 |
SENTINEL reset <pattern> | 重置全部名字和给定模式 pattern 相匹配的主服务器 |
SENTINEL failover <master name> | 当主服务器失效时,在不询问其余 Sentinel 意见的状况下,强制开始一次自动故障迁移。 |
6.7 Sentinel发布与订阅信息
客户端能够将 Sentinel 看做是一个只提供了订阅功能的 Redis 服务器:你不可使用 PUBLISH 命令向这个服务器发送信息,但你能够用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令,经过订阅给定的频道来获取相应的事件提醒。
一个频道可以接收和这个频道的名字相同的事件。好比说,名为 +sdown 的频道就能够接收全部实例进入主观下线(SDOWN)状态的事件。
经过执行 PSUBSCRIBE * 命令能够接收全部事件信息。
如下列出的是客户端能够经过订阅来得到的频道和信息的格式:
注意,当格式中包含 instance details 字样时,表示频道所返回的信息中包
含了如下用于识别目标实例的内容:
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
@ 字符以后的内容用于指定主服务器, 这些内容是可选的, 它们仅在 @ 字符以前的内容指定的实例不是主服务器时使用。
7、Redis cluster
7.1 Redis集群
Redis 集群是一个能够在多个 Redis 节点之间进行数据共享的设施(installation)。
Redis 集群不支持那些须要同时处理多个键的 Redis 命令,由于执行这些命令须要在多个 Redis 节点之间移动数据,而且在高负载的状况下,这些命令将下降 Redis 集群的性能,并致使不可预测的行为。
Redis 集群经过分区(partition)来提供必定程度的可用性(availability):即便集群中有一部分节点失效或者没法进行通信,集群也能够继续处理命令请求。将数据自动切分(split)到多个节点的能力。
当集群中的一部分节点失效或者没法进行通信时,仍然能够继续处理命令请求的能力。
7.2 Redis 集群数据共享
Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot),数据库中的每一个键都属于这 16384 个哈希槽的其中一个, 集群使用公式CRC16(key) % 16384 来计算键 key 属于哪一个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。
节点 A 负责处理 0 号至 5500 号哈希槽。
节点 B 负责处理 5501 号至 11000 号哈希槽。
节点 C 负责处理 11001 号至 16384 号哈希槽。
槽的计算公式
集群使用公式 CRC16(key) & 16383 计算键 key属于哪一个槽。
7.3 集群运行机制
全部的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
节点的fail是经过集群中超过半数的master节点检测失效时才失效。
客户端与redis节点直连,不须要中间proxy层.客户端不须要链接集群全部节点,链接集群中任何一个可用节点便可
把全部的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
为了使得集群在一部分节点下线或者没法与集群的大多数(majority)节点进行通信的状况下,仍然能够正常运做,Redis 集群对节点使用了主从复制功能:集群中的每一个节点都有 1 个至 N 个复制品(replica),其中一个复制品为主节点(master),而其他的N-1 个复制品为从节点(slave)。
在以前列举的节点 A 、B 、C 的例子中,若是节点 B 下线了,那么集群将没法正常运行,由于集群找不到节点来处理5501号至11000号的哈希槽。
假如在建立集群的时候(或者至少在节点 B下线以前),咱们为主节点B添加了从节点 B1,那么当主节点 B下线的时候,集群就会将B1设置为新的主节点,并让它代替下线的主节点B,继续处理5501号至11000号的哈希槽,这样集群就不会由于主节点B的下线而没法正常运做了。
不过若是节点B和B1都下线的话,Redis集群仍是会中止运做。
集群的复制特性重用了 SLAVEOF 命令的代码,因此集群节点的复制行为和SLAVEOF 命令的复制行为彻底相同。
7.4 集群的故障转移
1. 在集群里面,节点会对其余节点进行下线检测。
2. 当一个主节点下线时,集群里面的其余主节点负责对下线主节点进行故障移。
3. 换句话说,集群的节点集成了下线检测和故障转移等相似 Sentinel 的功能。
4. 由于 Sentinel 是一个独立运行的监控程序,而集群的下线检测和故障转移等功能是集成在节点里面的,它们的运行模式很是地不一样,因此尽管这二者的功能很类似,但集群的实现没有重用 Sentinel 的代码。
在集群里面执行命令的两种状况
命令发送到了正确的节点:
命令要处理的键所在的槽正好是由接收命令的节点负责,那么该节点执行命令,就像单机 Redis 服务器同样。
槽位说明:
7000: 槽 0~5000
7001:槽 5001~10000
7002:槽 10001~16383
命令发送到了错误的节点:
接收到命令的节点并不是处理键所在槽的节点,那么节点将向客户端返回一个转向(redirection)错误,告知客户端应该到哪一个节点去执行这个命令,客户端会根据错误提示的信息,从新向正确的节点发送命令。
7.5 关于转向错误
在集群中的节点会互相告知对方,本身负责处理哪些槽。
集群中的每一个节点都会记录 16384 个槽分别由哪一个节点负责,从而造成一个“槽表”(slot table)。
节点在接收到命令请求时,会经过槽表检查键所在的槽是否由本节点处理:
若是是的话,那么节点直接执行命令;
若是不是的话,那么节点就从槽表里面提取出正确节点的地址信息,而后返回转向错误。
7.6 配置集群
前期准备
# EPEL源安装ruby支持
yum install ruby rubygems -y
使用国内源
gem source -a http://mirrors.aliyun.com/rubygems/ -remove https://rubygems.org/
# gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
# 安装redis支持
gem install redis -v 3.3.3
gem sources -l
配置文件
Redis 集群由多个运行在集群模式(cluster mode)下的 Redis 实例组成, 实例的集群模式须要经过配置来开启, 开启集群模式的实例将可使用集群特有的功能和命令。
如下是一个包含了最少选项的集群配置文件示例:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
建立程序目录
cd /application/redis
mkdir 7000 7001 7002 7003 7004 7005
拷贝应用
for i in 0 1 2 3 4 5
do
cp /usr/local/redis/src/redis-server ./700$i
done
建立配置文件
for i in 7000 7001 7002 7003 7004 7005
do
echo "port $i
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes" > $i/redis.conf
done
启动redis集群
for i in 7000 7001 7002 7003 7004 7005
do
cd $i
./redis-server ./redis.conf &
cd ../
done
建立集群
cd /usr/local/redis/src/
./redis-trib.rb --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
给定 redis-trib.rb 程序的命令是 create,这表示咱们但愿建立一个新的集群。
选项 --replicas 1 表示咱们但愿为集群中的每一个主节点建立一个从节点。
7.7 集群管理
写数据,查看集群状态
redis-cli -c -p 7000
set foo bar
get foo
从新分片实践
cd /usr/local/redis/src/
./redis-trib.rb reshard 127.0.0.1:7000
集群状态
redis-cli -p 7000 cluster nodes | grep master
故障转移
redis-cli -p 7002 debug segfault
查看状态
redis-cli -p 7000 cluster nodes | grep master
增长新的节点
./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000
删除一个节点
redis-trib del-node ip:port '<node-id>'
删除master节点以前首先要使用reshard移除master的所有slot,而后再删除当前节点
添加一个从节点
./redis-trib.rb add-node --slave --master-id $[nodeid] 127.0.0.1:7008 127.0.0.1:7000
7.8 状态说明
集群最近一次向节点发送 PING 命令以后,过去了多长时间还没接到回复。
节点最近一次返回 PONG 回复的时间。
节点的配置节点(configuration epoch)
本节点的网络链接状况:例如 connected 。
节点目前包含的槽:例如 127.0.0.1:7001 目前包含号码为 5960 至 10921 的哈希槽。
8.1 PHP使用redis
tar zxvf 2.2.7.tar.gz
cd phpredis-2.2.7
/application/php/bin/phpize
./configure --with-php-config=/application/php/bin/php-config
make && make install
echo 'extension="redis.so"' >> /application/php/lib/php.ini
service php-fpm restart
service nginx restart
链接测试代码
[root@oldboy ~]# cat /application/nginx/html/check.php
<?php
//链接本地的 Redis 服务
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
echo "Connection to server sucessfully";
//查看服务是否运行
echo "Server is running: " . $redis->ping();
?>
字符串操做
<?php
//链接本地的 Redis 服务
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
echo "Connection to server sucessfully";
//设置 redis 字符串数据
$redis->set("tutorial-name", "Redis tutorial");
// 获取存储的数据并输出
echo "Stored string in redis:: " . $redis-
>get("tutorial-name");
?>
8.2 Python链接redis
安装软件包
[root@Redis ~]# yum install python-pip ipython -y
[root@Redis ~]# pip install redis
测试
[root@Redis ~]# ipython
In [1]: import redis
In [2]: oldboy = redis.StrictRedis(host='localhost', port=6379, db=0)
In [3]: oldboy.set('blog','blog.oldboyedu.com')
Out[3]: True
In [4]: oldboy.get('blog')
Out[4]: 'blog.oldboyedu.com'
本文内容来自 老男孩Linux云计算运维优秀学员课后笔记整理
https://mp.weixin.qq.com/s?__biz=MzI4NDM5NzE4Ng==&mid=2247484105&idx=1&sn=a9752cf7be8541a4eabc5084efca66be&chksm=ebfd5924dc8ad032940f036f4abd5a1377d12ee10e252a4e4863c533b547c4530afb41fbbde3&mpshare=1&scene=1&srcid=120313ShBKvyrxrvYtajK1eC#rd