缓存-redis 三种模式搭建和运行原理

标签: redis 缓存 主从 哨兵 集群


本文简单的介绍redis三种模式在linux的安装部署和数据存储的总结,希望可以相互交流相互提升。

一. redis安装

1、安装单机版redis

对于Centos7在安装redis之前需要进行一些常用工具的安装:

sudo yum install net-tools 网络工具,比如ifconfig
sudo yum -y install lrzsz 文件的上传下载

关闭防火墙

systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动
firewall-cmd --state #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)

正式安装redis

使用命令的模式进行redis的安装(文件down到/usr/local/sftp/
安装前需要进行tcl的安装,否则在make的时候报错
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
tar -zxvf tcl8.6.1-src.tar.gz
cd /usr/local/tcl8.6.1/unix/
./configure
make && make install

使用redis-3.2.8.tar.gz(截止2017年4月的最新稳定版)
tar -zxvf redis-3.2.8.tar.gz
cd redis-3.2.8
make && make test && make install

2. redis 的make test出现异常解决

在redis进行maketest时候会出现一系列的异常,有如下解决方案:

  • You need tcl 8.5 or newer in order to run the Redis test
    解决方案:前面已经安装了tcl;
  • [exception]: Executing test client: NOREPLICAS Not enough good slaves to write..
    NOREPLICAS Not enough good slaves to write.
    解决方案:vim tests/integration/replication-2.tcl
    将其中的第一个if里面的after 1000修改成after 10000,延长测试时间
  • [err]: Slave should be able to synchronize with the master in tests/integration/replication-psync.tcl
    Replication not started.
    解决方案:重新make test一次就好了;
  • [err]: Test replication partial resync: ok psync (diskless: yes, reconnect: 1) in tests/integration/replication-psync.tcl
    解决方案:vim tests/integration/replication-psync.tcl
    将其中的after 100修改成after 1000就好了。

3. redis的生产环境启动方案

用redis-server启动一下redis,做一些实验没什么意义。

要把redis作为一个系统的daemon进程去运行的,每次系统启动,redis进程一起启动,操作不走如下:

  1. redis utils目录下,有个redis_init_script脚本
  1. 将redis_init_script脚本拷贝到linux的/etc/init.d目录中,将redis_init_script重命名为redis_6379,6379是我们希望这个redis实例监听的端口号
  2. 修改redis_6379脚本的第6行的REDISPORT,设置为相同的端口号(默认就是6379)
  3. 创建两个目录:/etc/redis(存放redis的配置文件),/var/redis/6379(存放redis的持久化文件)
  4. 修改redis配置文件(默认在根目录下,redis.conf),拷贝到/etc/redis目录中,修改名称为6379.conf
  5. 修改redis.conf中的部分配置为生产环境
    daemonize yes        让redis以daemon进程运行
    pidfile /var/run/redis_6379.pid 设置redis的pid文件位置
    port 6379          设置redis的监听端口号
    dir /var/redis/6379     设置持久化文件的存储位置
  6. 启动redis,执行cd /etc/init.d, chmod 777 redis_6379,./redis_6379 start
  7. 确认redis进程是否启动,ps -ef | grep redis
    9.让redis跟随系统启动自动启动 sudo update-rc.d reds_6379 defaults(7 无法执行 可以使用下面的方式)
    在redis_6379脚本中,最上面,加入两行注释
      # chkconfig: 2345 90 10
      # description: Redis is a persistent key-value database
    chkconfig redis_6379 on

4. redis cli的使用

redis-cli SHUTDOWN,连接本机的6379端口停止redis进程
redis-cli -h 127.0.0.1 -p 6379 SHUTDOWN,制定要连接的ip和端口号
redis-cli PING,ping redis的端口,看是否正常
redis-cli,进入交互式命令行

二. redis 之 RDB 和 AOF

RDB和AOF是redis的一种数据持久化的机制。持久化是为了避免系统在发生灾难性的系统故障时导致的系统数据丢失。我们一般会将数据存放在本地磁盘,还会定期的将数据上传到云服务器。
  RDB 是redis的snapshotting,通过redis.conf中的save配置进行设置,如 save 60 1000:

表示每隔60s,如果有超过1000个key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快照,这个操作也被称之为snapshotting,也可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成

AOF 是以appendonly方式进行数据的储存的,开启AOF模式后,所有存进redis内存的数据都会进入os cache中,然后默认1秒执行一次fsync写入追加到appendonly.aof文件中。一般我们配置redis.conf中的一下指令:

appendonly yes 可以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的;
appendfsync everysec 每秒将os cache中的数据fsync到磁盘,这个最常用的,生产环境一般都这么配置,性能很高,QPS可以上万;还有另外两种参数always和no,前者持续写入,性能低,数据保存完整,后者os cache自己控制写入时间,那样可能丢失数据很多;
rewrite策略
  auto-aof-rewrite-percentage 100
  auto-aof-rewrite-min-size 64mb
  表示在第一次将缓存中的数据追加到aof文件中后记录次文件的大小,比如128MB,在追加数据到文件大小是上次文件的100%,也就是2倍,此时需要判断文件是否大于64mb,大于min-size则进行rewrite。

AOF和RDB模式我们一般在生产环境都会打开,一般而言,redis服务挂掉后进行重启会优先家在aof中的文件。

三. redis 之 主从配置

1. 主从架构的核心原理

当启动一个slave node的时候,它会发送一个PSYNC命令给master node,如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据;否则如果是slave node第一次连接master node,那么会触发一次full resynchronization;
  开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。
  slave node如果跟master node有网络故障,断开了连接,会自动重连。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。

2. 主从复制的断点续传

从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。

master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制,但是如果没有找到对应的offset,那么就会执行一次resynchronization。

3. 无磁盘化复制

master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了,可以有如下配置:

repl-diskless-sync
repl-diskless-sync-delay 等待一定时长再开始复制,因为要等更多slave重新连接过来

4. 过期key处理

slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。

5. 主从架构redis配置

  1. 打开slaveof参数
      在slave node上配置:slaveof masterip masterport
  1. redis slave node只读,默认开启,slave-read-only
  2. master上启用安全认证,requirepass (master 配置)
    slave连接master口令,masterauth(slave node 配置)

四. redis 之哨兵模式

1. 哨兵主要功能

  • 集群监控,负责监控redis master和slave进程是否正常工作
  • 消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
  • 故障转移,如果master node挂掉了,会自动转移到slave node上
  • 配置中心,如果故障转移发生了,通知client客户端新的master地址

2. reids 对于异步复制和脑裂数据丢失问题解决

min-slaves-to-write 3
min-slaves-max-lag 10

在redis.conf配置文件中,上面的参数代表至少需要3个slaves节点与master节点进行连接,并且master和每个slave的数据同步延迟不能超过10秒。一旦上面的设定没有匹配上,则master不在提供相应的服务。

3. 哨兵模式的核心机制

  • 3.1 sdown和odown转换机制

sdown和odown两种失败状态:

  • sdown是主观宕机,就一个哨兵如果自己觉得一个master宕机了,那么就是主观宕机;
  • odown是客观宕机,如果quorum数量的哨兵都觉得一个master宕机了,那么就是客观宕机;

sdown达成的条件很简单,如果一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数之后,就主观认为master宕机
  sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了quorum指定数量的其他哨兵也认为那个master是sdown了,那么就认为是odown了,客观认为master宕机

  • 3.2 哨兵集群的自动发现机制

哨兵互相之间的发现,是通过redis的pub/sub系统实现的,每个哨兵都会往sentinel:hello这个channel里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在。
  每隔两秒钟,每个哨兵都会往自己监控的某个master+slaves对应的sentinel:hello channel里发送一个消息,内容是自己的host、ip和runid还有对这个master的监控配置。
  每个哨兵也会去监听自己监控的每个master+slaves对应的sentinel:hello channel,然后去感知到同样在监听这个master+slaves的其他哨兵的存在。
  每个哨兵还会跟其他哨兵交换对master的监控配置,互相进行监控配置的同步。

  • 3.3 slave配置的自动纠正
      哨兵会负责自动纠正slave的一些配置,比如slave如果要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据;如果slave连接到了一个错误的master上,比如故障转移之后,那么哨兵会确保它们连接到正确的master上。

  • 3.4 slave->master选举算法
      如果一个master被认为odown了,而且majority哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个slave来作为新的master。

选举会考虑slave的一些信息

  1. 跟master断开连接的时长
  2. slave优先级
  3. 复制offset
  4. run id

如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master
  
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

接下来会对slave进行排序

  1. 按照slave优先级进行排序,slave priority越低,优先级就越高
  2. 如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高
  3. 如果上面两个条件都相同,那么选择一个run id比较小的那个slave
  • 3.5 quorum和majority

每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个slave来做切换,这个slave还得得到majority哨兵的授权,才能正式执行切换;

如果quorum < majority,比如5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵授权就可以执行切换;
  但是如果quorum >= majority,那么必须quorum数量的哨兵都授权,比如5个哨兵,quorum是5,那么必须5个哨兵都同意授权,才能执行切换

  • 3.6 configuration epoch

哨兵会对一套redis master+slave进行监控,有相应的监控的配置,执行切换的那个哨兵,会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的.
  如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch,作为新的version号。

  • 3.7 configuraiton传播

哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub消息机制
  这里之前的version号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的,其他的哨兵都是根据版本号的大小来更新自己的master配置的。

4. 经典的三哨兵集群搭建

  • 4.1 修改sentinel.conf配置文件如下参数:
  1. 创建如下文件夹
    mkdir /etc/sentinal
    mkdir -p /var/sentinal/5000
  1. 移动配置文件位置
    /etc/sentinel/5000.conf
  2. 修改相关配置信息

    绑定端口

    port 5000

    绑定本级ip

    bind 192.168.xxx.xxx
    dir /var/sentinal/5000

    设定哨兵masterip

    sentinel monitor mymaster 192.168.xxx.xxx 6379 2
    sentinel down-after-milliseconds mymaster 30000
    sentinel failover-timeout mymaster 60000
    sentinel parallel-syncs mymaster 1
  3. 生产环境额外部署

    后台启动

    daemonize yes

    日志保存路径

    logfile /var/log/sentinal/5000/sentinel.log
    mkdir -p /var/log/sentinal/5000
  • 4.2 启动哨兵集群,并查看相关信息
  1. 启动哨兵client端
    redis-cli -h 192.168.xxx.xxx -p 5000
  1. 查看相关信息
    sentinel master mymaster
    SENTINEL slaves mymaster
    SENTINEL sentinels mymaster
    SENTINEL get-master-addr-by-name mymaster
  • 4.3 哨兵的增加删除和slave永久下线
    4.3.1 哨兵节点的增加和删除

增加sentinal,会自动发现;
删除sentinal的步骤:
(1)停止sentinal进程

(2)SENTINEL RESET *,在所有sentinal上执行,清理所有的master状态
(3)SENTINEL MASTER mastername,在所有sentinal上执行,查看所有sentinal对数量是否达成了一致

4.3.2 slave的永久下线

让master摘除某个已经下线的slave:SENTINEL RESET mastername,在所有的哨兵上面执行.

五. redis 之集群模式

redis的集群模式为了解决系统的横向扩展以及海量数据的存储问题,如果你的数据量很大,那么就可以用redis cluster。
  redis cluster可以支撑N个redis master,一个master上面可以挂载多个slave,一般情况我门挂载一个到两个slave,master在挂掉以后会主动切换到slave上面,或者当一个master上面的slave都挂掉后,集群会从其他master上面找到冗余的slave挂载到这个master上面,达到了系统的高可用性。

1. redis cluster 的hash slot 算法

redis cluster有固定的16384个hash slot,对每个key计算CRC16值,然后对16384取模,可以获取key对应的hash slot;
  redis cluster中每个master都会持有部分slot,比如有3个master,那么可能每个master持有5000多个hash slot;
  hash slot让node的增加和移除很简单,增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去,移动hash slot的成本非常低;

2. redis cluster 简单配置

2.1 redis cluster的重要配置

  • cluster-enabled

  • cluster-config-file :这是指定一个文件,供cluster模式下的redis实例将集群状态保存在那里,包括集群中其他机器的信息,比如节点的上线和下限,故障转移,不是我们去维护的,给它指定一个文件,让redis自己去维护.

  • cluster-node-timeout :节点存活超时时长,超过一定时长,认为节点宕机,master宕机的话就会触发主备切换,slave宕机就不会提供服务.

2.2 在三台机器上启动6个redis实例

  1. 修改redis.conf配置文件

    mkdir -p /etc/redis-cluster
    mkdir -p /var/log/redis
    mkdir -p /var/redis/7001

    port 7001
    cluster-enabled yes
    cluster-config-file /etc/redis-cluster/node-7001.conf
    cluster-node-timeout 15000
    daemonize yes
    pidfile /var/run/redis_7001.pid
    dir /var/redis/7001
    logfile /var/log/redis/7001.log
    bind 192.168.xxx.xxx
    appendonly yes

将上面的配置文件,在/etc/redis下放6个,分别为: 7001.conf,7002.conf,7003.conf,7004.conf,7005.conf,7006.conf

  1. 准备生产环境的启动脚本

在/etc/init.d下,放6个启动脚本,分别为: redis_7001, redis_7002, redis_7003, redis_7004, redis_7005, redis_7006

每个启动脚本内,都修改对应的端口号

  1. 分别在3台机器上,启动6个redis实例

将每个配置文件中的slaveof给删除(不要开启从节点配置)

2.3 创建集群

  • 使用如下命令时报错

    yum install -y ruby
    yum install -y rubygems
    gem install redis

redis requires Ruby version >= 2.2.2的报错,查了资料发现是Centos默认支持ruby到2.0.0,可gem 安装redis需要最低是2.2.2

解决办法是 先安装rvm,再把ruby版本提升至2.3.3

  1. 安装curl(centos7 已经安装不用重新安装)

sudo yum install curl

  1. 安装RVM

gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
curl -L get.rvm.io | bash -s stable

  1. 查询rvm文件所在位置,并加载rvm配置

find / -name rvm -print
source /usr/local/rvm/scripts/rvm

  1. 查看rvm库中已知的ruby版本,并安装一个ruby版本

rvm list known
rvm install 2.3.4

  1. 使用一个ruby版本是指为默认,移除旧版本

rvm use 2.3.4 --default
rvm remove 2.0.0
ruby --version

  1. 安装redis

gem install redis

使用redis-trib.rb命令创建集群

cp /usr/local/sftp/redis-3.2.8/src/redis-trib.rb /usr/local/bin

redis-trib.rb create --replicas 1 192.168.199.141:7001 192.168.199.141:7002 192.168.199.142:7003 192.168.199.142:7004 192.168.199.143:7005 192.168.199.143:7006

--replicas: 表示每个master有几个slave

redis-trib.rb check 192.168.31.187:7001 查看状体

3. 集群模式master扩容和节点移除

3.1 加入新master

mkdir -p /var/redis/7007

port 7007
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7007.conf
cluster-node-timeout 15000
daemonize yes
pidfile /var/run/redis_7007.pid
dir /var/redis/7007
logfile /var/log/redis/7007.log
bind 192.168.199.144
appendonly yes

以上相同配置完成后,设置启动脚本进行启动;然后用如下命令进行node节点添加:

redis-trib.rb add-node 192.168.199.144:7007 192.168.199.141:7001
redis-trib.rb check 192.168.199.141:7001

3.2 reshard一些数据过去

resharding的意思就是把一部分hash slot从一些node上迁移到另外一些node上
redis-trib.rb reshard 192.168.199.141:7001

3.3 添加node作为slave

进行上面的相同配置后,设定启动脚本,执行如下命令(其中masterid可以通过check命令进行查看):
redis-trib.rb add-node --slave --master-id 28927912ea0d59f6b790a50cf606602a5ee48108 192.168.199.144:7008 192.168.199.141:7001

3.4 删除node

先用resharding将数据都移除到其他节点,确保node为空之后,才能执行remove操作
redis-trib.rb del-node 192.168.199.141:7001 bd5a40a6ddccbd46a0f4a2208eb25d2453c2a8db

你可能感兴趣的:(缓存-redis 三种模式搭建和运行原理)