赞
踩
前言:由于生产环境虚拟机全部挂掉,40台redis集群在全部重启恢复后,出现集群master挂了后,slave并没有主动升为master,导致线上业务受阻和部分数据丢失。加班加点搞验证,出一份合理的分析报告。
Redis版本:4.0.1
Linux系统:redhat 7.2
操作用户:root
Serviceportal服务安装jdk1.7.0_65.tar.gz
API服务安装jdk-8u121-linux-x64.tar.gz
安装步骤:
1、 直接解压JDK源码压缩包
tar –xvf jdk1.7.0_65.tar.gz
2、 配置path环境变量
tar –xvf jdk-8u121-linux-x64.tar.gz
3、 生效环境变量
source profile文件
如:source /etc/profile
4、 查看环境变量
echo $PATH 或 echo $JAVA_HOME
安装zlib-1.2.8.tar.gz
1、cd/home/setup/redis
2、tar -xvf./zlib-1.2.8.tar.gz
3、cdzlib-1.2.8
4、./configure --prefix=/usr/local/zlib
5、make&& make install
安装ruby-2.3.3.tar.gz
1、cd/home/setup/redis
2、tar -xvf./ruby-2.3.3.tar.gz
3、cdruby-2.3.3
4、./configure--prefix=/usr/local/ruby
5、make
6、makeinstall
7、cp/usr/local/ruby/bin/ruby /usr/local/bin/
8、cd./ext/zlib
9、ruby./extconf.rb --with-zlib-dir=/usr/local/zlib
10、make&& make install
安装rubygems-2.6.7.zip
1、cd/home/setup/redis
2、unziprubygems-2.6.7.zip
3、cdrubygems-2.6.7
4、rubysetup.rb
5、cp bin/gem/usr/local/bin
安装redis-3.0.0.gem
1、cd/home/setup/redis
2、gem install-l ./redis-3.2.2.gem
到此redis-cluster依赖安装完成
安装redis-3.2.3.tar.gz
1、cd/home/setup/redis
2、tar -xvfredis-3.2.3.tar.gz
3、cdredis-3.2.3
4、make
5、make test
6、make install
mkdir /usr/redis
cd /usr/redis
mkdir data
mkdir logs
mkdir cluster
cd/home/setup/redis/redis-3.2.3/src
cpredis-benchmark redis-cli redis-server redis-trib.rb /usr/redis/
如果make test 报如下错误,请安装这个依赖包
hadoop@stormspark:~/workspace/redis2.6.13/src$make test
Youneedtcl8.5ornewerinordertorun the Redis test
make: *** [test] Error 1
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
sudo tar xzvf tcl8.6.1-src.tar.gz -C /usr/local/
cd /usr/local/tcl8.6.1/unix/
sudo ./configure
sudo make
sudo make install
IP:192.168.1.250
192.168.1.248
192.168.1.247
192.168.1.188
192.168.1.184
192.168.1.165
192.168.1.158
192.168.1.157
192.168.1.156
192.168.1.155
bind192.168.1.155 //绑定客户端连接指定计算机
protected-mode yes //当开启后,禁止公网访问redis。它启用的条件有两个,第一是没有使用bind,第二是没有设置访问密码。
port 6381 //指定该redis server监听的端口号。默认是6379,如果指定0则不监听
tcp-backlog511 //TCP连接中已完成队列(完成三次握手之后)的长度
timeout30 //当客户端闲置多少秒后关闭连接,如果设置为0表示关闭该功能。
tcp-keepalive300 //表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,避免服务器一直阻塞
daemonize yes //是否以守护模式启动,默认为no,配置为yes时以守护模式启动,会将进程号pid写入默认文件
supervisedno //可以通过upstart和systemd管理Redis守护进程,这个参数是和具体的操作系统相关的。
pidfile"/usr/redis/cluster/redis_6381.pid" //配置pid文件路径
loglevel warning //日志级别。可选项有:debug(记录大量日志信息,适用于开发、测试阶段); verbose(较多日志信息); notice(适量日志信息,使用于生产环境);warning(仅有部分重要、关键信息才会被记录)。
logfile"/usr/redis/logs/redis_6381.log" //日志文件的位置
databases16 //设置数据库的数目。默认的数据库是DB 0
save900 1 //保存数据到磁盘。格式是:save <seconds> <changes> Snapshotting(快照)->rdb
save300 10
save60 10000
stop-writes-on-bgsave-erroryes //如果redis 最后一次的后台保存(持久化)失败,redis 将停止接受写操作
rdbcompressionyes //启动rdb文件压缩,耗费CPU资源,默认为yes -消耗CUP资源,减少数据集大小
rdbchecksumyes //对rdb数据进行校验,耗费CPU资源,默认为yes
dbfilename"dump_6381.rdb" //rdb文件名
dir"/usr/redis/data" //数据存放地址
slave-serve-stale-datayes //当一个slave与master失去联系时,或者复制正在进行的时候,是否应答客户端请求
slave-read-onlyyes //设置slave是否是只读的
repl-diskless-syncno //主从数据复制是否使用无硬盘复制功能
repl-diskless-sync-delay5 //无磁盘diskless方式在进行数据传递之前会有一个时间的延迟
repl-disable-tcp-nodelayno //假如设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加同步延迟(40ms),造成master与slave数据不一致假如设置成no,则redis master会立即发送同步数据,没有延迟
slave-priority100 //当master 不能正常工作的时候,Redis Sentinel 会从 slaves 中选出一个新的 master,这个值越小,就越会被优先选中,但是如果是 0 , 那是意味着这个 slave 不可能被选中。 默认优先级为 100。
appendonlyyes //是否启用aof持久化方式
appendfilename"appendonly_6381.aof" //aof文件名
appendfsynceverysec //每秒钟都调用fsync刷新到AOF文件
no-appendfsync-on-rewriteno //指定是否在后台aof文件rewrite期间调用fsync
auto-aof-rewrite-percentage100 //当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写 。
auto-aof-rewrite-min-size64mb //当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写
aof-load-truncatedyes //redis在启动时可以加载被截断的AOF文件
lua-time-limit5000 //一个Lua脚本最长的执行时间
cluster-enabledyes //配置yes则开启集群功能
cluster-config-file"/usr/redis/cluster/nodes_6381.conf" //集群节点信息保存
cluster-node-timeout15000 //这是集群中的节点能够失联的最大时间,超过这个时间,该节点就会被认为故障
cluster-require-full-coverageno //在部分key所在的节点不可用时,如果此参数设置为"yes"(默认值), 则整个集群停止接受操作;如果此参数设置为”no”,则集群依然为可达节点上的key提供读操作。
slowlog-log-slower-than10000 // SlowLog是Redis用来记录慢查询执行时间的日志系统
slowlog-max-len128 // slowlog-max-len表示慢查询最大的条数,当slowlog超过设定的最大值后,会将最早的slowlog删除,是个FIFO队列
latency-monitor-threshold0 //预定时间是通过latency-monitor-threshold配置, 系统仅仅记录那个执行时间大于或等于预定时间(毫秒)的操作
notify-keyspace-events"" // Redis能通知Pub/Sub 客户端关于键空间发生的事件,默认关闭
hash-max-ziplist-entries 512 //当hash只有少量的entry时,并且最大的entry所占空间没有超过指定的限制时,会用一种节省内存的,数据结构来编码。可以通过下面的指令来设定限制, 表示当hash项(field,value)数>512即ziplist项>1024的时候转为dict
hash-max-ziplist-value64 //表示当hash中的value长度超过64的时候转为dict。
list-max-ziplist-size-2 //每个quicklist节点上的ziplist大小不能超过8 Kb。(默认值)
list-compress-depth0 // list设计最容易被访问的是列表两端的数据,中间的访问频率很低,如果符合这个场景,list还有一个配置,可以对中间节点进行压缩(采用的LZF——一种无损压缩算法),进一步节省内存。0: 是个特殊值,表示都不压缩。这是Redis的默认值。
set-max-intset-entries512 //如果set中整型元素的数量不超过512时,Redis将会采用该特殊编码。
zset-max-ziplist-entries128 //当sortedset的元素个数及 元素大小 小于一定限制时,它是用ziplist来存储。
zset-max-ziplist-value64
hll-sparse-max-bytes 3000 // HyperLogLog稀疏结构表示字节的限制。该限制包括16个字节的头。当HyperLogLog使用稀疏结构表示这些限制,它会被转换成密度表示。
activerehashingyes //启用哈希刷新,每100个CPU毫秒会拿出1个毫秒来刷新Redis的主哈希表(顶级键值映射表)
client-output-buffer-limitnormal 0 0 0 //客户端输出缓冲区限制可用于强制断开客户端连接由于某种原因,不能以足够快的速度从服务器读取数据(常见的原因是Pub / Sub客户端不能像消息一样快速地使用消息发布者可以制作它们)。
client-output-buffer-limitslave 256mb 64mb 60
client-output-buffer-limitpubsub 32mb 8mb 60
hz10 // Redis server执行后台任务的频率,默认为10,此值越大表示redis对"间歇性task"的执行次数越频繁(次数/秒)。"间歇性task"包括"过期集合"检测、关闭"空闲超时"的连接等,此值必须大于0且小于500。此值过小就意味着更多的cpu周期消耗,后台task被轮询的次数更频繁。此值过大意味着"内存敏感"性较差。建议采用默认值。
aof-rewrite-incremental-fsyncyes // aof rewrite过程中,是否采取增量"文件同步"策略,默认为"yes",而且必须为yes.
#requirepass"XXX"
#masterauth"XXX"
#Generated by CONFIG REWRITE
masterauth"XXX" // slave服务连接master的密码
requirepass"XXX" //客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭
创建启动、停止脚步
redis_start(启动redis服务) redis_stop(停止服务) create_cluster(创建集群)
redis_start:
cd /usr/redis
vi redis_start
加入以下内容并保存
#!/bin/bash
#port为实际配置端口,如6379
./redis-server./cluster/redis_port.conf
./redis-server./cluster/redis_port.conf
添加文件可执行权限
chmod 755 ./redis_start
redis_stop:
cd /usr/redis
vi redis_stop
加入以下内容并保存(注意修改IP和端口)
#!/bin/bash
#port为实际配置端口,如6379
./redis-cli -h ip -p port shutdown
./redis-cli -h ip -p port shutdown
添加文件可执行权限
chmod 755./redis_start
create_cluster:
cd /usr/redis
vi create_cluster
加入以下内容并保存(注意修改IP和端口,必须是主从交叉一主一从)
#!/bin/sh
./redis-trib.rbcreate --replicas 1 ip:port ip:port ip:port .....
添加文件可执行权限
chmod 755./create_cluster
查看集群状态
./redis-trib.rbcheck ip:port
验证方法
在第一台机器上连接集群的6379端口的节点,在另外一台连接6379节点,连接方式为 redis-cli -h ip -c -p 6379 ,加参数 -C 可连接到集群,因为上面 redis.conf 将 bind 改为了ip地址,所以 -h 参数不可以省略。
在6379节点执行命令 set hello world ,执行结果如下:
//集群(cluster)
CLUSTER INFO
打印集群的信息
CLUSTER NODES
列出集群当前已知的所有节点(node
),以及这些节点的相关信息。
//节点(node)
CLUSTER MEET
<ip><port>将 ip
和 port
所指定的节点添加到集群当中,让它成为集群的一份子。 CLUSTER MEET
127.0.0.16380
CLUSTER FORGET
<node_id>从集群中移除 node_id
指定的节点。
CLUSTER REPLICATE
<node_id>将当前节点设置为 node_id
指定的节点的从节点。
CLUSTER SAVECONFIG
将节点的配置文件保存到硬盘里面。
//槽(slot)
CLUSTER ADDSLOTS
<slot> [slot ...]
将一个或多个槽(slot
)指派(assign
)给当前节点。
CLUSTER DELSLOTS
<slot> [slot ...]
移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS
移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT
<slot> NODE
<node_id>将槽 slot
指派给 node_id
指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>
,然后再进行指派。
CLUSTER SETSLOT
<slot> MIGRATING
<node_id>将本节点的槽 slot
迁移到 node_id
指定的节点中。
CLUSTER SETSLOT
<slot> IMPORTING
<node_id>从 node_id
指定的节点中导入槽 slot
到本节点。
CLUSTER SETSLOT
<slot> STABLE
取消对槽 slot
的导入(import
)或者迁移(migrate
)。
//键 (key)
CLUSTER KEYSLOT
<key>计算键 key
应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT
<slot>返回槽 slot
目前包含的键值对数量。
CLUSTER GETKEYSINSLOT
<slot><count>返回 count
个 slot
槽中的键。
1) 节点握手
CLUSTERMEET 192.168.1.2506381
CLUSTERMEET 192.168.1.2486381
CLUSTERMEET 192.168.1.2476381
CLUSTERMEET 192.168.1.1886381
CLUSTERMEET 192.168.1.1846381
CLUSTERMEET 192.168.1.1656381
CLUSTERMEET 192.168.1.1586381
CLUSTERMEET 192.168.1.1576381
CLUSTERMEET 192.168.1.1566381
CLUSTERMEET 192.168.1.1556381
2) 槽点分配
./redis-cli-h 192.168.1.155 -p 6381 -c -a XXX cluster addslots {0..4096}
./redis-cli-h 192.168.1.156 -p 6381 -c -a XXX cluster addslots {4097..8193}
./redis-cli-h 192.168.1.157 -p 6381 -c -a XXX cluster addslots {8194..12290}
./redis-cli-h 192.168.1.158 -p 6381 -c -a XXX cluster addslots {12291..16383}
3) 从节点配置
CLUSTERREPLICATE master_ID
1. AOF
AOF
默认关闭,开启方法,修改配置文件reds.conf
:appendonly
yes
##此选项为aof功能的开关,默认为“no”,可以通过“yes”来开启aof功能
##只有在“yes”下,aof重写/文件同步等特性才会生效
appendonly
yes
##指定aof文件名称
appendfilename appendonly.aof
##指定aof操作中文件同步策略,有三个合法值:always everysec no,默认为everysec
appendfsync everysec
##在aof-rewrite期间,appendfsync是否暂缓文件同步,"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”
no-appendfsync-on-rewrite
no
##aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb”
auto-aof-rewrite-min-size 64mb
##相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比。
##每一次rewrite之后,redis都会记录下此时“新aof”文件的大小(例如A),那么当aof文件增长到A*(1 + p)之后
##触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸。
auto-aof-rewrite-percentage 100
AOF
是文件操作,对于变更操作比较密集的server
,那么必将造成磁盘IO
的负荷加重;此外linux
对文件操作采取了“延迟写入”手段,即并非每次write
操作都会触发实际磁盘操作,而是进入了buffer
中,当buffer
数据达到阀值时触发实际写入(
也有其他时机)
,这是linux
对文件系统的优化,但是这却有可能带来隐患,如果buffer
没有刷新到磁盘,此时物理机器失效(
比如断电)
,那么有可能导致最后一条或者多条aof
记录的丢失。
redis
提供了3
种aof
记录同步选项:
always
:每一条aof
记录都立即同步到文件,这是最安全的方式,也以为更多的磁盘操作和阻塞延迟,是IO
开支较大。
everysec
:每秒同步一次,性能和安全都比较中庸的方式,也是redis
推荐的方式。如果遇到物理服务器故障,有可能导致最近一秒内aof
记录丢失(
可能为部分丢失)
。
no:redis
并不直接调用文件同步,而是交给操作系统来处理,操作系统可以根据buffer
填充情况/
通道空闲时间等择机触发同步;这是一种普通的文件操作方式。性能较好,在物理服务器故障时,数据丢失量会因OS
配置有关。
其实,我们可以选择的太少,everysec
是最佳的选择。如果你非常在意每个数据都极其可靠,建议你选择一款“关系性数据库”吧。
AOF
文件会不断增大,它的大小直接影响“故障恢复”的时间,
而且AOF
文件中历史操作是可以丢弃的。AOF rewrite
操作就是“压缩”AOF
文件的过程,当然redis
并没有采用“基于原aof
文件”来重写的方式,而是采取了类似snapshot
的方式:基于copy-on-write
,全量遍历内存中数据,然后逐个序列到aof
文件中。因此AOF rewrite
能够正确反应当前内存数据的状态,这正是我们所需要的;*rewrite
过程中,对于新的变更操作将仍然被写入到原AOF
文件中,同时这些新的变更操作也会被redis
收集起来(buffer
,copy-on-write
方式下,最极端的可能是所有的key
都在此期间被修改,将会耗费2
倍内存)
,当内存数据被全部写入到新的aof
文件之后,收集的新的变更操作也将会一并追加到新的aof
文件中,此后将会重命名新的aof
文件为appendonly
。aof,
此后所有的操作都将被写入新的aof
文件。如果在rewrite
过程中,出现故障,将不会影响原AOF
文件的正常工作,只有当rewrite
完成之后才会切换文件,因为rewrite
过程是比较可靠的。
触发rewrite
的时机可以通过配置文件来声明,同时redis
中可以通过bgrewriteaof
指令人工干预。
redis-cli -h
ip -p
port bgrewriteaof
因为rewrite
操作/aof
记录同步/snapshot
都消耗磁盘IO
,redis
采取了“schedule
”策略:无论是“人工干预”还是系统触发,snapshot
和rewrite
需要逐个被执行。
AOF rewrite
过程并不阻塞客户端请求。系统会开启一个子进程来完成。
2. RDB
RDB默认开启,redis.conf中的具体配置参数如下;
#dbfilename:持久化数据存储在本地的文件
dbfilenamedump.rdb
#dir:持久化数据存储在本地的路径,如果是在/redis/redis-3.0.6/src下启动的redis-cli,则数据会存储在当前src目录下
dir ./
##snapshot触发的时机,save <seconds><changes>
##如下为900秒后,至少有一个变更操作,才会snapshot
##对于此值的设置,需要谨慎,评估系统的变更操作密集程度
##可以通过“save “””来关闭snapshot功能
#save时间,以下分别表示更改了1个key时间隔900s进行持久化存储;更改了10个key300s进行存储;更改10000个key60s进行存储。
save 900 1
save 30010
save 6010000
##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等
stop-writes-on-bgsave-erroryes
##是否启用rdb文件压缩,默认为“yes”,压缩往往意味着“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间
rdbcompressionyes
snapshot触发的时机,是有“间隔时间”和“变更次数”共同决定,同时符合2个条件才会触发snapshot,否则“变更次数”会被继续累加到下一个“间隔时间”上。snapshot过程中并不阻塞客户端请求。snapshot首先将数据写入临时文件,当成功结束后,将临时文件重名为dump.rdb。
使用RDB恢复数据:
自动的持久化数据存储到dump.rdb后。实际只要重启redis服务即可完成(启动redis的server时会从dump.rdb中先同步数据)
客户端使用命令进行持久化save存储:
./redis-cli-h ip -p port save
./redis-cli-h ip -p port bgsave
一个是在前台进行存储,一个是在后台进行存储。我的client就在server这台服务器上,所以不需要连其他机器,直接./redis-cli bgsave。由于redis是用一个主线程来处理所有 client的请求,这种方式会阻塞所有client请求。所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,可能会严重影响性能。
3. AOF和RDB总结
1) AOF更加安全,可以将数据更加及时的同步到文件中,但是AOF需要较多的磁盘IO开支,AOF文件尺寸较大,文件内容恢复数度相对较慢。
2) snapshot,安全性较差,它是“正常时期”数据备份以及master-slave数据同步的最佳手段,文件尺寸较小,恢复数度较快。
可以通过配置文件来指定它们中的一种,或者同时使用它们(不建议同时使用),或者全部禁用,在架构良好的环境中,master通常使用AOF,slave使用snapshot,主要原因是master需要首先确保数据完整性,它作为数据备份的第一选择;slave提供只读服务(目前slave只能提供读取服务),它的主要目的就是快速响应客户端read请求;但是如果你的redis运行在网络稳定性差/物理环境糟糕情况下,建议你master和slave均采取AOF,这个在master和slave角色切换时,可以减少“人工数据备份”/“人工引导数据恢复”的时间成本;如果你的环境一切非常良好,且服务需要接收密集性的write操作,那么建议master采取snapshot,而slave采用AOF。
Redis主从复制可以根据是否是全量分为全量复制和增量复制:
1. 全量复制
Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:
l 从服务器连接主服务器,发送SYNC命令;
l 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
l 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
l 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
l 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
l 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
2. 增量复制
Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
3. Redis主从复制策略
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
Redis 集群实现了一个叫做备份迁移(replicamigration)的概念,以提高系统的可用性。在集群中有主节点-从节点的设定,如果主从节点间的映射关系是固定的,那么久而久之,当发生多个单一节点独立故障的时候,系统可用性会变得很有限。
例如有一个每个主节点都只有一个从节点的集群,当主节点或者从节点故障失效的时候集群能让操作继续执行下去,但如果主从节点都失效的话就没法让操作继续执行下去。然而这样长期会积累很多由硬件或软件问题引起的单一节点独立故障。例如:
l 主节点 A 有且只有一个从节点 A1。
l 主节点 A 失效了。A1 被提升为新的主节点。
l 三个小时后,A1 因为一个独立事件(跟节点 A 的失效无关)失效了。由于没有其他从节点可以提升为主节点(因为节点 A 仍未恢复正常),集群没法继续进行正常操作。
如果主从节点间的映射关系是固定的,那要让集群更有抵抗力地面对上面的情况的唯一方法就是为每个主节点添加从节点。然而这要付出的代价也更昂贵,因为要求 Redis 执行更多的实例、更多的内存等等。
一个候选方案就是在集群中创建不对称性,然后让集群布局时不时地自动变化。例如,假设集群有三个主节点A,B,C。节点 A 和 B 都各有一个从节点,A1 和 B1。节点 C 有两个从节点:C1 和 C2。
备份迁移是从节点自动重构的过程,为了迁移到一个没有可工作从节点的主节点上。在上面提到的例子中,备份迁移过程如下:
l 主节点 A 失效。A1 被提升为主节点。
l 节点 C2 迁移成为节点 A1 的从节点,要不然 A1 就没有任何从节点。
l 三个小时后节点 A1 也失效了。
l 节点 C2 被提升为取代 A1 的新主节点。
l 集群仍然能继续正常工作。
1. 异步复制:数据一致性
Redis 并不能保证数据的强一致性。 这意味这在实际中集群在特定的条件下可能会丢失写操作。
第一个原因是因为集群是用了异步复制。 写操作过程:
l 客户端向主节点B写入一条命令。
l 主节点B向客户端回复命令状态。
l 主节点将写操作复制给他得从节点 B1, B2 和 B3。
主节点对命令的复制工作发生在返回命令回复之后, 因为如果每次处理命令请求都需要等待复制操作完成的话, 那么主节点处理命令请求的速度将极大地降低 —— 我们必须在性能和一致性之间做出权衡。
2. 写入安全:数据一致性
1) 一个写入操作能到达一个主节点,但当主节点要回复客户端的时候,这个写入有可能没有通过主从节点间的异步冗余备份传播到从节点那里。 如果在某个写入操作没有到达从节点的时候主节点已经宕机了,那么该写入会永远地丢失掉,以防主节点长时间不可达而它的一个从节点已经被提升为主节点。
2) 另一个理论上可能会丢失写入操作的模式是:
l 因为分区使一个主节点变得不可达。
l 故障转移(fail over)到主节点的一个从节点。(即从节点被提升为主节点)
l 过一段时间之后主节点再次变得可达。
一个没有更新路由表(routingtable)的客户端或许会在集群把这个主节点变成一个从节点(新主节点的从节点)之前对它进行写入操作。
节点1 : master 155 slave 165 , 184 分配槽 0..4096
节点2 : master 156 slave 188 , 247 分配槽 4097..8193
节点3 : master 157 slave 248 分配槽 8194..12290
节点4 : master 158 slave 250 分配槽 12291..16383
批量写入脚本
#!/bin/bash
n=50000
for ((j=n;j>=1;j--))
do
sleep 3
echo$j
echo -en "xxx"| ./redis-cli -p 6381 -c -a XXX-h 192.168.1.155 -x set name$j
done
停止服务均为kill 进程
1. 一组master-slave:master失效
节点1和节点4进行测试 , 停止master 服务,slave被提升为master;提升的策略未研究。
结论:slave被提升为master
2. cluster-require-full-coverage参数设置为yes,一组master-slave宕机
停止所有服务,修改10台机器的redis。confconf文件,设置参数cluster-require-full-coverage=yes
将服务master、slave 主从配置初始化
节点4 master、slave 停止服务,然后在节点1 get 其它节点上的值,显示集群服务不可用。
结论:集群不可用
3. cluster-require-full-coverage参数设置为no,一组master-slave宕机
停止所有服务,修改10台机器的redis.conf文件,设置参数cluster-require-full-coverage=no
将服务master、slave 主从配置初始化
节点4 master、slave 停止服务,然后在节点1 get 其它节点上的值,没有在节点4 槽点上的值都可以得到, 节点4 槽点上的不可访问。
结论:集群可用,只是该server上slot数据找不到。
4. 一组master-slave:master失效,slave被提升为主后,master重启。
将服务master、slave 主从配置初始化
节点1和节点4进行测试 , 停止master 服务,slave被提升为master;
将停止的master服务启动,该master成为slave。
结论:slave被提升为master
5. 一组master-slave:master直接重启。
将服务master、slave 主从配置初始化
节点1和节点4进行测试 , 直接重启master 服务,master、slave关系不变。
结论:测试结果,不会改变master(cluster-node-timeout15000 //这是集群中的节点能够失联的最大时间,超过这个时间,该节点就会被认为故障)
6. 运行情况下修改备份机制,是否对集群有影响
config set appendonly no
使用命令关闭aof 数据备份策略(redis.conf中appendonly参数的值不会被改变),在进行set和get 操作正常;aof文件不会写入日志。
结论:对集群的正常使用影响。
7. 运行情况下,删除备份文件,是否对集群有影响
将服务master、slave 主从配置初始化
删除 节点1 master 的rdb 和 aof 文件,在其他节点get 节点1上的槽点,不影响数据访问
删除 节点1 master和slave 的rdb 和 aof 文件,在其他节点get节点1上的槽点,不影响数据访问
结论:不影响get set 数据
8. 宕机时node.config是否会少一部分数据,是否会影响集群启动
将服务master、slave 主从配置初始化
通过kill 节点1 的master 来模拟 宕机, 查看node.conf 文件数据不会少
结论: node信息不会丢失,但会更新状态
9. 最后一组master 无法启动时,如何手动更新slot管理?
无法分配slot
10. aof和rdb都存在,但aof出错时,怎么从rdb恢复?
关闭aof参数功能;(一般采用修复aof文件)
11. 写频繁时,master挂掉,且写aof文件,是否存在数据没有同步到slave导致slave升为master后查不到数据的情况?
理论分析:应该出现数据不一致
验证结果:未出现不一致
验证方法:使用循环写入脚本,不断set数据;在set数据过程中突然kill master节点,然后对比被kill的master 和 该master的slave的aof文件进行对比。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。