Redis的四种工作模式实现

Redis:

Redis是一款优秀的结构数据存储系统,由于出色的并发性能广为关注,可用作:数据库、缓存、消息队列;同类型的还有memcached,但是由于memcache支持的结构类型较少,并且不能够将数据持久化,慢慢的被redis所取代。

Redis支持的数据结构:字符串、列表(数组)、hashes(关联数组)、集合、有序集合、bitmaps、hyperloglogs、空间索引;本篇博客简单介绍redis对于实现高可用和持久化的四种redis工作模式,进入正题:

[TOC]

进入正题简单介绍

单机模式

单机模式下,对于数据的落地,根据业务数据的重要程度选择是RDB还是AOF备份;

RDB:snapshotting, 二进制格式;按事先定制的策略,周期性地将数据从内存同步至磁盘;数据文件默认为dump.rdb;
                    客户端显式使用SAVE或BGSAVE命令来手动启动快照保存机制;
                            SAVE:同步,即在主线程中保存快照,此时会阻塞所有客户端请求;
                            BGSAVE:异步;backgroud

AOF:Append Only File, fsync 记录每次写操作至指定的文件尾部实现的持久化;当redis重启时,可通过重新执行文件中的命令在内存中重建出数据库;
                    BGREWRITEAOF:AOF文件重写;
                    不会读取正在使用AOF文件,而是通过将内存中的数据以命令的方式保存至临时文件中,完成之后替换原来的AOF文件; 
    注意:持久机制本身不能取代备份;应该制订备份策略,对redis库定期备份;

    RDB与AOF同时启用:
        (1) BGSAVE和BGREWRITEAOF不会同时进行;
        (2) Redis服务器启动时用持久化的数据文件恢复数据,会优先使用AOF;
RDB相关的配置:
    *save <seconds> <changes>

        save 900 1
        save 300 10
        save 60 10000
        save 5  200000

    表示:三个策略满足其中任意一个均会触发SNAPSHOTTING操作;900s内至少有一个key有变化,300s内至少有10个key有变化,60s内至少有1W个key发生变化;

        stop-writes-on-bgsave-error yes     ## dump操作出现错误时,是否禁止新的写入操作请求;
        rdbcompression yes              ##启用压缩
        rdbchecksum yes                 ##检测完整性

        dbfilename dump.rdb:指定rdb文件名
        *dir /var/lib/redis:rdb文件的存储路径

AOF相关的配置
        *appendonly no
        appendfilename "appendonly.aof"

        *appendfsync
            Redis supports three different modes:
                no:redis不执行主动同步操作,而是OS进行决定何时同步;
                everysec:每秒一次;  ##推荐
                always:每语句一次;

            no-appendfsync-on-rewrite no
                是否在后台执行aof重写期间不调用fsync,默认为no,表示调用;

            auto-aof-rewrite-percentage 100
            auto-aof-rewrite-min-size 64mb
                上述两个条件同时满足时,方会触发重写AOF;与上次aof文件大小相比,其增长量超过100%,且大小不少于64MB; 

            aof-load-truncated yes

主从复制模式

实现原理:主从模式实现比较简单,类似于MySQL的主从,选定一个主机当做master,在从节点配置指向master的地址端口及口令信息即可实现;master开启主从模式后,会对当前自身进行快照RDB,然后基于网络发送给slave节点,在此之前用户可以选择直接基于网络发送给slave快照还是先创建快照文件于磁盘中,而后将其发送给从节点;与此同时新接收的数据将放在repl-backlog-size中作为缓冲区,当slave接收RDB成功后,master将repl-backlog-size内容在陆续发送给slave

开始之前所有Redis首先进行基本安全加固:

vim /etc/redis.conf
    ...
    bind 192.168.2.128
    requirepass "ifan"
    ...

挑选一台Redis作为Master节点:

Slave:
    127.0.0.1:6379> SLAVEOF 192.168.2.128 6379
    127.0.0.1:6379> CONFIG SET masterauth "ifan"
    127.0.0.1:6379> CONFIG REWRITE

Master查看主从复制状态:

192.168.2.128:6379> INFO Replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.2.129,port=6379,state=online,offset=981,lag=1
master_repl_offset:981
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:980
192.168.2.128:6379> 
  1. Redis的主从复制支持多slave,同样支持链式复制,只需要各级slave指定自己的master即可
  2. Master以非阻塞方式同步数据至slave主机;

主从复制调优参数:repl(主从复制)

slave-serve-stale-data yes
    # 表明slave会继续应答来自client的请求,但这些数据可能已经过期(因为连接中断导致无法从master同步)。若配置为no,则slave除正常应答"INFO"和"SLAVEOF"命令外,其余来自客户端的请求命令均会得到"SYNC with master in progress"的应答,直到该slave与master的连接重建成功或该slave被提升为master。

slave-read-only yes
    # 从状态下,不可写
repl-diskless-sync no
    # no,则是Disk-backend主节点新创建快照文件于磁盘中,而后将其发送给从节点;
    # yes,主节点新创建快照后直接通过网络套接字文件发送给从节点;为了实现并行复制,通常需要在复制启动前延迟一个时间段;

repl-diskless-sync-delay 5
    # 配置当收到第一个请求时,等待多个5个slave一起来请求之间的间隔时间。
repl-ping-slave-period 10
    # 配置master与slave的心跳间隔10秒
repl-timeout 60
    # 主从复制的超时时间
repl-disable-tcp-nodelay no
    # 禁止Nagle算法,允许小包的发送,不等待一有变化就发送。对于延时敏感型,同时数据传输量比较小的应用,
repl-backlog-size 1mb
    # 设置备份的工作储备大小。工作储备是一个缓冲区,当从站断开一段时间的情况时,它替从站接收存储数据,因此当从站重连时,通常不需要完全备份,只需要一个部分同步就可以,即把从站断开时错过的一部分数据接收。工作储备越大,从站可以断开并稍后执行部分同步的断开时间就越长。

slave-priority 100
    # 复制集群中,主节点故障时,sentinel应用场景中的主节点选举时使用的优先级;数字越小优先级越高,但0表示不参与选举;
min-slaves-to-write 3
    # 主节点仅允许其能够通信的从节点数量大于等于此处的值时接受写操作;
min-slaves-max-lag 10
    # 从节点延迟时长超出此处指定的时长时,主节点会拒绝写入操作;

哨兵模式(3台)

原理实现:哨兵模式的实现是基于主从模式的一种补充,在主从模式下slave是不允许写入的,那么当master宕机后,整个业务将不能够继续写入,而哨兵则是为此做的了一个补充,当master出现故障后,每个redis服务都会工作一个sentinel(哨兵)时刻监控redis6379端口,一旦发生故障,基于quorum机制投票决定进而实现故障转移,重新选举master提供写操作,sentinel拥有调用外部脚本实现报警的能力

注意:配置哨兵之前清先配置主从复制

[root@node1 ~]#  vim /etc/redis-sentinel.conf
...
port 26379
bind 0.0.0.0            ##绑定端口,否则会被进入安全模式,仅允许127.0.0.1链接
sentinel monitor mymaster 192.168.2.129 6379 2      ##集群名,master地址,端口,投票2票及以上才进行故障转移
sentinel down-after-milliseconds mymaster 10000     ##监控到指定的集群的主节点异常状态持续多久方才将标记为“故障”;
sentinel failover-timeout mymaster 120000           ##sentinel必须在此指定的时长内完成故障转移操作,否则,将视为故障转移操作失败;
sentinel auth-pass mymaster ifan                   ##哨兵集群,配置链接6379端口密码
# sentinel notification-script <master-name> <script-path>  ##调用脚本报警功能
...

哨兵模式管理指令

redis-cli -h SENTINEL_HOST -p SENTINEL_PORT
redis-cli>
            SENTINEL masters                ##查看当前master信息
            SENTINEL slaves <MASTER_NAME>    ##查看master下的从节点信息
            SENTINEL failover <MASTER_NAME>  ##手动进行故障转移,需要指定集群名
            SENTINEL get-master-addr-by-name <MASTER_NAME>  ##查看当前master的ip信息

集群模式(6台)

实现原理:redis cluster是一种无中心的分布式服务,最小由3台即可实现集群(但不能保证高可用的能力)3台为master节点,3台为slave节点(master正常时不提供服务),当客户端的存请求到达redis集群时会将数据进行hash取模,根据redis集群建立划分的slot进行存储,取的时候根据取模的slot进行取值,cluster模式下无论客户端请求到达集群的任何节点都能够被提供服务,但是要求客户端是智能客户端,因为客户端到达节点存取数据进行取模得到数据可存放和读取的服务器位置,由客户端自行发起第二次访问

关于集群实现其他方案:Codis / cerberus.

地址 服务1 服务2 系统版本
192.168.2.128(node1) 6379(master) 6380(slave) CentOS7.2
192.168.2.129(node2) 6379(master) 6380(slave) CentOS7.2
192.168.2.130(node3) 6379(master) 6380(slave) CentOS7.2

三台机器分别安装redis:

[root@node1 ~]# ntpdate -u ntp.aliyun.com
[root@node1 ~]# yum install redis -y
[root@node1 ~]# cp /etc/redis.conf /etc/redis_6379.conf
[root@node1 ~]# cp /etc/redis.conf /etc/redis_6380.conf
[root@node1 ~]# egrep -v "^#|^$" /etc/redis_6379.conf
    ...
    bind 0.0.0.0
    port 6379
    pidfile /var/run/redis_6379.pid
    logfile /var/log/redis/redis_6379.log
    cluster-enabled yes
    cluster-config-file nodes-6379.conf
    cluster-node-timeout 15000
    cluster-slave-validity-factor 10
    cluster-migration-barrier 1
    ...

注:为了完成多实例,请将/etc/redis_6380.conf和6379配置保持一致,端口除外

优化内存相关选项:

echo "vm.overcommit_memory=1" >> /etc/sysctl.conf ; sysctl -p
echo "511" > /proc/sys/net/core/somaxconn
echo never > /sys/kernel/mm/transparent_hugepage/enabled 

启动服务:

[root@node1 ~]# redis-server /etc/redis_6379.conf &
[root@node1 ~]# redis-server /etc/redis_6380.conf &

检查日志是否有异常信息:

[root@node1 ~]# tail -f /var/log/redis/redis_6379.log
[root@node1 ~]# tail -f /var/log/redis/redis_6380.log

添加机器到集群:

redis-cli -h 192.168.2.128 -p 6379 -c
192.168.2.128:6379> CLUSTER MEET 192.168.2.129 6379
192.168.2.128:6379> CLUSTER MEET 192.168.2.130 6379

查看集群状态:

192.168.2.128:6379> CLUSTER INFO            ##查看集群状态
    cluster_state:fail                     ##集群状态,之所以会失败是因为我们还没有对集群进行槽位的划分
    cluster_slots_assigned:0 #分配的slot数
    cluster_slots_ok:0       #正确的slot数
    cluster_slots_pfail:0
    cluster_slots_fail:0
    cluster_known_nodes:3    #当前的节点数
    cluster_size:0
    cluster_current_epoch:2
    cluster_my_epoch:0
    cluster_stats_messages_sent:171
    cluster_stats_messages_received:171

192.168.2.128:6379> CLUSTER NODES
    2a9f356a7362c535056f4311057d78269c7aa6d4 192.168.2.129:6379 master - 0 1551782791382 1 connected 5462-10922
    af69cb43def99109d4e9a2e15b0fa41b1998bb02 192.168.2.130:6379 master - 0 1551782790373 0 connected 10923-16383
    32db6806120a01ce90fa8641bd15abd3c6a55408 192.168.2.128:6379 myself,master - 0 0 2 connected 0-5461

划分槽位(根据master的数量进行划分,一共16384个槽位):

[root@node1 ~]# for k in {0..5461};do redis-cli -h 192.168.2.128 -p 6379 CLUSTER ADDSLOTS $k;done
[root@node1 ~]# for k in {5462..10922};do redis-cli -h 192.168.2.129 -p 6379 CLUSTER ADDSLOTS $k;done
[root@node1 ~]# for k in {10923..16383};do redis-cli -h 192.168.2.130 -p 6379 CLUSTER ADDSLOTS $k;done

再次查看集群状态:

192.168.2.128:6379> CLUSTER INFO            ##查看集群状态
    cluster_state:ok
    cluster_slots_assigned:16384            ##划分的总槽位
    cluster_slots_ok:16384                  ##成功划分的槽位
    cluster_slots_pfail:0
    cluster_slots_fail:0
    cluster_known_nodes:3
    cluster_size:3
    cluster_current_epoch:2
    cluster_my_epoch:0
    cluster_stats_messages_sent:3495
    cluster_stats_messages_received:3495

添加从节点

redis-cli -h 192.168.2.128 -p 6379 -c
192.168.2.128:6379> CLUSTER MEET 192.168.2.128 6380
192.168.2.128:6379> CLUSTER MEET 192.168.2.129 6380
192.168.2.128:6379> CLUSTER MEET 192.168.2.130 6380

划分槽位(根据master的数量进行划分,一共16384个槽位):

[root@node1 ~]# for k in {0..5461};do redis-cli -h 192.168.2.128 -p 6380 CLUSTER ADDSLOTS $k;done
[root@node1 ~]# for k in {5462..10922};do redis-cli -h 192.168.2.129 -p 6380 CLUSTER ADDSLOTS $k;done
[root@node1 ~]# for k in {10923..16383};do redis-cli -h 192.168.2.130 -p 6380 CLUSTER ADDSLOTS $k;done

查看集群节点数:

192.168.2.128:6379> CLUSTER INFO            ##查看集群状态
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6    ##所有节点数6个
cluster_size:3          ##主节点数3个
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:4388
cluster_stats_messages_received:4388

查看状态:

192.168.2.128:6379> CLUSTER NODES
2a9f356a7362c535056f4311057d78269c7aa6d4 192.168.2.129:6379 master - 0 1551782791382 1 connected 5462-10922
af69cb43def99109d4e9a2e15b0fa41b1998bb02 192.168.2.130:6379 master - 0 1551782790373 0 connected 10923-16383
30744bd131bb249850d0f1ff5a91fae751b86fe3 192.168.2.130:6380 master - 0 1551782788357 5 connected
65d1453da3e1e3dc2a1e4bdefac375c4890e8555 192.168.2.128:6380 master - 0 1551782789362 3 connected
85461b05a18125b2301a615d217af4dacf35879c 192.168.2.129:6380 master - 0 1551782792388 4 connected
32db6806120a01ce90fa8641bd15abd3c6a55408 192.168.2.128:6379 myself,master - 0 0 2 connected 0-5461

注意:此时的六个节点全部是以master的身份,我们需要将后需添加的3个变更为从节点,并基于master进行复制

修改从节点状态:

128(6380) -- 复制 --> 129 (6379)
129(6380) -- 复制 --> 130 (6379)
130(6380) -- 复制 --> 128 (6379)

# redis-cli -h 192.168.2.128 -p 6380 -c CLUSTER REPLICATE 2a9f356a7362c535056f4311057d78269c7aa6d4
# redis-cli -h 192.168.2.129 -p 6380 -c CLUSTER REPLICATE af69cb43def99109d4e9a2e15b0fa41b1998bb02
# redis-cli -h 192.168.2.130 -p 6380 -c CLUSTER REPLICATE 32db6806120a01ce90fa8641bd15abd3c6a55408

再次查看节点状态(此时的主从关系已经形成):

192.168.2.128:6379> CLUSTER NODES
2a9f356a7362c535056f4311057d78269c7aa6d4 192.168.2.129:6379 master - 0 1551786306436 1 connected 5462-10922
af69cb43def99109d4e9a2e15b0fa41b1998bb02 192.168.2.130:6379 master - 0 1551786305391 0 connected 10923-16383
30744bd131bb249850d0f1ff5a91fae751b86fe3 192.168.2.130:6380 slave 32db6806120a01ce90fa8641bd15abd3c6a55408 0 1551786308514 5 connected
65d1453da3e1e3dc2a1e4bdefac375c4890e8555 192.168.2.128:6380 slave 2a9f356a7362c535056f4311057d78269c7aa6d4 0 1551786307471 3 connected
85461b05a18125b2301a615d217af4dacf35879c 192.168.2.129:6380 slave af69cb43def99109d4e9a2e15b0fa41b1998bb02 0 1551786303303 4 connected
32db6806120a01ce90fa8641bd15abd3c6a55408 192.168.2.128:6379 myself,master - 0 0 2 connected 0-5461

到此Redis3.2版本的集群已经搭建完成,redis-cluster需要智能客户端,在写入时需要智能判断

# for k in {1..10};do redis-cli -h 192.168.2.128 -p 6379 SET key$k val$k;done   ##我们先不以集群模式来寸数据,由于redis的分片机制,会提醒你本次数据要交给xx主机存
(error) MOVED 9189 192.168.2.129:6379
OK
OK
(error) MOVED 13120 192.168.2.130:6379
(error) MOVED 9057 192.168.2.129:6379
OK
OK
(error) MOVED 13004 192.168.2.130:6379
(error) MOVED 8941 192.168.2.129:6379
(error) MOVED 5850 192.168.2.129:6379

# for k in {11..20};do redis-cli -c -h 192.168.2.128 -p 6379 SET key$k val$k;done  ##我们以集群模式去存,则全部存成功
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK

# for k in {11..20};do redis-cli -h 192.168.2.128 -p 6379 GET key$k;done   ##不以集群模式读取
"val11"
(error) MOVED 13976 192.168.2.130:6379
(error) MOVED 9913 192.168.2.129:6379
(error) MOVED 5726 192.168.2.129:6379
"val15"
(error) MOVED 13852 192.168.2.130:6379
(error) MOVED 9789 192.168.2.129:6379
(error) MOVED 6098 192.168.2.129:6379
"val19"
"val20"

# redis-cli -h 192.168.2.130 -p 6379 GET key12  ##根据上面提示的数据存储位置去读取,则读取成功
"val12"

模拟故障:

# ps -ef|grep redis
root       2805      1  0 18:31 ?        00:00:09 redis-server 0.0.0.0:6379 [cluster]
root       2809      1  0 18:31 ?        00:00:06 redis-server 0.0.0.0:6380 [cluster]
# kill -9 2805
杀掉进程后先是先是集群状态fail稍后slave上线对外提供服务

192.168.2.128:6380> cluster nodes
2a9f356a7362c535056f4311057d78269c7aa6d4 192.168.2.129:6379 master - 0 1551787432472 1 connected 5462-10922
32db6806120a01ce90fa8641bd15abd3c6a55408 192.168.2.128:6379 master,fail - 1551787261748 1551787257954 2 disconnected
85461b05a18125b2301a615d217af4dacf35879c 192.168.2.129:6380 slave af69cb43def99109d4e9a2e15b0fa41b1998bb02 0 1551787433495 4 connected
30744bd131bb249850d0f1ff5a91fae751b86fe3 192.168.2.130:6380 master - 0 1551787431446 7 connected 0-5461
65d1453da3e1e3dc2a1e4bdefac375c4890e8555 192.168.2.128:6380 myself,slave 2a9f356a7362c535056f4311057d78269c7aa6d4 0 0 3 connected
af69cb43def99109d4e9a2e15b0fa41b1998bb02 192.168.2.130:6379 master - 0 1551787427638 0 connected 10923-16383

注:当集群中master出现宕机时,slave才会对外提供服务,否则slave接收请求时会提示该数据能够提供服务的位置,当6台机器的master的全部宕机,slave上线,除非宕机超过一半,集群不再成立,机器下线后,重新上线以slave的身份工作

宕机前:
# redis-cli -h 192.168.2.128 -p 6380 GET key13      ##宕机前129的备节128(6380)点不提供服务,提示该数据能提供服务的服务器位置
(error) MOVED 9913 192.168.2.129:6379
# redis-cli -h 192.168.2.129 -p 6379 GET key13      ##根据提示,129的6379能够提供服务
"val13"

模拟宕机后:
# redis-cli -h 192.168.2.129 -p 6379 GET key13      ##129的6379不能够提供服务
Could not connect to Redis at 192.168.2.129:6379: Connection refused

# redis-cli -h 192.168.2.128 -p 6380 GET key13      ##129的备节点128(6380)提供服务
"val13"

原文地址:https://blog.51cto.com/swiki/2358726

时间: 2024-10-19 07:31:48

Redis的四种工作模式实现的相关文章

交换机的四种工作模式

Cisco 交换机的命令行模式 用户模式只能用来查看一些统计信息 Switch> 特权模式可以查看或修改Cisco设备的配置 Switch>enable Switch# 全局配置模式可以修改交换机的全局配置 Switch#configure terminal Switch(config)# 接口模式针对于接口的配置 Switch(config)#interface fastEthernet 0/1 Switch(config-if)# 可以使用end命令来快速退出当前模式 Switch(con

LVS四种工作模式搭建与十种调度算法

LVS概念 lvs集群类型中的术语: VS:Virtual Server,Director Server(DS) Dispatcher(调度器),Load BalancerRS:Real Server(lvs), upstream server(nginx) backend server(haproxy)CIP:Client IPVIP: Virtual serve IP VS外网的IPDIP: Director IP VS内网的IPRIP: Real server IP 访问流程:CIP <-

31、activity 四种工作模式

Activity中的四种启动模式

在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. Android总Activity的启动模式分为四种: [html] view plaincopy Activity启动模式设置: <activity android:name=".MainActivity" android:launchMode="standard" 

Android Activity:四种启动模式,Intent Flags和任务栈(转自他人博客)

在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.那各个页面跳转关系如何决定呢?如果启动了顺序启动了ABCD的Activiy,如何从D调回到B呢?下面讲述一下Acitivity的四种启动模式.讲解启动模式之前,有必要先讲解一下“任务栈”的概念; 任务栈 每个应用都有至少一个任务栈,是用来存放Activity的,功能类似于函数调用的栈,先后顺序代表了Activity的出现顺序:比如Activity1-->Activity2-->Act

知识总结: Activity的四种启动模式

通常情况下,一个应用有一个Task,这个Task就是为了完成某个工作的一系列Activity的集合.而这些Activity又被组织成了堆栈的形式.当一个Activity启动时,就会把它压入该Task的堆栈,而当用户在该Activity中按返回键,或者代码中finish掉时,就会将它从该Task的堆栈中弹出.然而,事实上我们的需求远没有我们想的那么简单.有时候,你可能希望在开启一个Activity时,重新开启一个Task:有时你可能希望将已经存在的一个Activity放到栈顶,而不是重新创建一个等

LVS 三种工作模式基本配置(不含HA)

类别:原创 服务器 本文参考 LVS三种工作模式简介及案例参考http://www.sxt.cn/u/324/blog/3188 LVS DR模式基本配置参考http://www.21ops.com/ops/26717.html LVS TUN模式配置参考(其它的文档全都少了内容) http://outofmemory.cn/wr/?u=http%3A%2F%2Fwww.jizhuomi.com%2Fsoftware%2F365.html ipvsadm 命令详细参数参考 http://blog

嵌入式中 ARM的几种工作模式 以及异常模式的优先级

一.Arm工作模式: Arm微处理器支持7种工作模式,分别为: 1. 用户模式(Usr)            用于正常执行程序 2. 快速中断模式(FIQ)    用于高速数据传输 3. 外部中断模式(IRQ)   用于通常的中断处理 4. 管理模式(SVC)          操作系统使用的保护模式(高权限),复位和软件中断进入 5. 数据访问终止模式(abt)   当数据或指令预取终止时进入该模式,可用于虚拟内存及存储保护 6. 系统模式(sys)            运行均有特权的操作

LVS的几种工作模式

LVS简单介绍 LVS (Linux Virtual Server)的缩写,其实就是Linux虚拟服务器.在1实际的生产场景,提供一个web服务应用的一般不会是一台web服务器,为了保证业务的可靠性,一般会为业务布置多台服务器来支撑业务,及时有其中的一台或者部分服务器挂掉也不至于导致整个业务无法访问.那么既然存在那么多台web服务器用来提供服务,难道需要用户记下来所有的地址么?当然不是,此时就需要一个前端的调度器,用户只需要记住这个前端的调度器的地址,每回访问的时候去访问调度器就可以了,调度器接