redis主从与哨兵集群的搭建

  • redis简介
  • redis常用命令
  • redis数据模型
  • redis数据结构
  • 关系型和非关系型数据库的优缺点
  • 关系型数据库
  • 非关系型数据库
  • redis存储
  • redis安装部署
  • 准备工作
  • 解压tar包
  • 编译安装
  • 配置环境变量
  • 启动redis
  • redis集群架构
  • 配置redis主从
  • 修改redis配置文件
  • 测试主从
  • 搭建redis哨兵集群
  • 搭建哨兵集群
  • 模拟主机故障,进行容灾切换


redis简介

redis6.2.6版本下载地址redis官网redis官方文档

  • Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、key-value数据库,并提供多种语言的API。(是一个非关系型的数据库)

既然提到非关系数据库,那么就有必要说一下关系型数据库和非关系型数据库的区别了。

  1. 数据存储结构的不同
    首先关系型数据库一般都有固定的表结构,并且需要通过DDL(数据定义语言)语句来修改表结构,不是很容易进行扩展。
    非关系型数据库的存储机制就有很多,比如咱们今天介绍的redis就是基于key/value俗称键值对,还有其他的比如基于文档的、基于图的等等,对于数据的格式十分灵活没有固定的表结构,方便扩展,因此如果业务的数据结构并不固定的或者经常变动比较大的,那么非关系型数据库是一个不错的选择
  2. 可扩展性的不同
    传统的关系型数据库给人一种横向扩展难,不好对数据进行分片等。

而一些非关系型数据库则原生就支持数据的水平扩展(就比如mongodb的sharding机制),并且这可能也是很多nosql的一大卖点,其实像mysql这种关系型数据库的水平扩展也并不是难,即使nosql水平扩展容易但对于向跨分片进行joins这种场景都没有什么太好的解决办法,不管是关系型还是非关系型数据库,解决水平扩展或者跨分片joins这种场景,在应用层和数据层中间加一层中间件来做数据处理也许是个好的办法

  1. 数据一致性的不同
    非关系型数据库一般强调的是数据最终一致性,而没有像ACID一样强调数据的强一致性,从非关系型数据库中读到的有可能还是处于一个中间态的数据,因此如果你的业务对于数据的一致性要求很高,那么非关系型数据库并不是一个很好的选择,非关系型数据库可能更多的偏向OLAP场景,而关系型数据库更多偏向于OLTP场景
  • Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系型数据库起到很好的补充作用。它提供了Java,c/c++,c#,PHP,JavaScript,Perl,object-C,python,ruby,erlang等客户端,使用很方便。
  • redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以关联其他从服务器的主服务器。这使得redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从服务器在任何地方同步树时,可以阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。

redis常用命令

redis时基于内存存储的,持久化的关键是这三条指令:save,bgsave,lastsave
当接收到save指令时,redis就会dump数据到一个文件里。
这里需要说一下的就是:redis的独特功能是存储列表和集合,这是它于mc之流相比更有竞争力的地方。
type key 用来获取某key的类型
keys pattern 匹配所有符合模式的key,比如keys* 就列出所有的key了
randomkey 返回随机的一个key
rename oldkeynewkey key改名用的

列表操作
rpush key string 将某个值加入到一个key列表末尾
lpush key string 将某个值加入到一个key列表头部
llen key 列表长度
lrange key start end 返回列表中某个范围的值,相当于mysql里面的分页查询那样
ltrim key start end 保留列表中某个范围的值
lindex key index 获取列表中特定索引号的值,要注意是O(n)复杂度
lset key index value 设置列表中某个位置的值
lpop key
prop key 和上面的lpop一样,就是类似栈或队列的那种取头取尾指令,可以当成消息队列来使用

集合操作
sadd key member 增加元素
srem key member 删除元素
scard key 返回集合大小
sismember key member 判断某个值是否在集合中
sinter key1 key2 … 获取多个集合的交集元素
smembers key 列出集合的所有元素
multiple DB 可以更换db,数据可以隔离开,默认是存放在DB 0。

redis数据模型

redis的外围由一个键、值映射的字典构成。与其他非关系型数据库主要不同在于:redis中值的类型不仅限于字符串,还支持如下抽象数据类型:

  • 字符串列表
  • 无序不重复的字符串集合
  • 有序不重复的字符串集合
  • 键、值都为字符串的哈希表
    值的类型决定了值本身支持的操作。Redis支持不同无序、有序的列表,无序、有序的集合间的交集、并集等高级服务器端原子操作。

redis数据结构

redis提供五种数据类型:string,hash,list,set及zset(sorted set)。

关系型和非关系型数据库的优缺点

关系型数据库

关系型数据库最经典的数据结构是表,由二维码及其之间的联系所组成的一个数据组织
优点:

  1. 易于维护:都是使用表结构,格式一致;
  2. 使用方便:sql语言通用,可用于复杂查询;
  3. 复杂操作:支持sql,可用于一个表及多个表之间非常复杂的查询。

缺点:

  1. 读写性能比较差,尤其是海量数据的高效率读写;
  2. 固定的表结构,灵活度较差;
  3. 高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。

非关系型数据库

非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。
优点:

  1. 格式灵活:存储数据的格式可以是key/value形式,文档形式,图片形式等,文档形式、图片形式等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
  2. nosql可以使用硬盘或者随机存储器作为载体,而关系数据库只能使用硬盘;
  3. 成本低:nosql数据库部署简单,基本都是开源软件

缺点:

  1. 不提供sql支持,学习和使用成本较高;
  2. 无事务处理;
  3. 数据结构相对复杂,复杂查询方面较差。

redis存储

redis使用两种文件格式:全量数据和增量请求。
全量数据格式是把内存中的数据写入磁盘,便于下次读取文件进行加载;

增量请求文件则是把内存中的数据序列化为操作请求,用于读取文件进行replay得到数据,序列化的操作包括set、rpush、sadd、zadd。

redis的存储分为内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置。
save seconds update,save配置,指出在多长时间内,有多少次更新操作,就将数据同步到数据文件。这个可以多个条件配合,比如默认配置文件中的设置,就设置了三个条件。

appendonly yes/no,appendonly配置,指出是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面的save条件来同步的,所以有的数据会在一段时间内只存在与内存中。

appendfsync no/always/everysec,appendfsync配置,no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示每秒同步一次。

redis安装部署

环境说明:
redis使用的是6.2.6版本

主机

IP

系统

master

192.168.182.137

redhat8.2

slave

192.168.182.143

redhat8.2

slave2

192.168.182.144

redhat8.2

准备工作

// 三台主机都要做
[root@master opt] wget https://download.redis.io/releases/redis-6.2.6.tar.gz

解压tar包

// 三台主机都做
[root@master opt]# tar -zxf redis-6.2.6.tar.gz

编译安装

[root@master redis-6.2.6]# pwd  //进入redis目录
/opt/redis-6.2.6

[root@master redis-6.2.6]# yum -y install gcc gcc-c++  //安装c语言编译器
[root@master redis-6.2.6]# yum -y install make  //安装make编译器

[root@master redis-6.2.6]# make MALLOC=libc

配置环境变量

// redis的二进制文件放在src目录下
[root@master redis-6.2.6]# cat /etc/profile.d/redis.sh   //为了能直接使用redis命令
export PATH=/opt/redis-6.2.6/src:$PATH

[root@master redis-6.2.6]# source /etc/profile.d/redis.sh  //使其生效

启动redis

在启动redis之前需要先做以下操作

启动方式有以下两种:
[root@master redis-6.2.6]# vim redis.conf
257 daemonize yes //把no改为yes

启动一:
[root@master src]# ./redis-server  //不建议用这种方式启动
[root@master redis-6.2.6]# redis-server /opt/redis-6.2.6/redis.conf  //推荐使用这种方式

启动二:
[root@master opt]# cat /usr/lib/systemd/system/redis.service 
[Unit]
Description=redis server daemon
After=network.target

[Service]
Type=forking
ExecStart=/opt/redis-6.2.6/src/redis-server /opt/redis-6.2.6/redis.conf
ExecStop=/bin/kill -s QUIT $MAINPID
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

[root@master opt]# systemctl daemon-reload
[root@master opt]# systemctl enable --now redis.service

[root@master opt]# ss -anlt | awk -F "  *|:" 'NR==2{print $5}'   //看到6379端口号说明成功
6379

进入客户端的命令
redis-cli -p 6379 
127.0.0.1:6379>

[root@master redis-6.2.6]# redis-cli -p 6379 shutdown  //关闭redis服务

以上操作三台主机都需要做

redis集群架构

现在所部署的哨兵集群是基于redis主从的基础上的,整体架构如下:
一个主节点(master)可拥有多个从节点(slave),从节点实现对主节点的复制,保证数据同步。而哨兵(sentinel)则对各节点进行监控,主要包括主节点存活检测、主从运行情况检测等,一旦主节点宕机,哨兵可自动进行故障转移 (failover)、主从切换。

配置redis主从

修改redis配置文件

建议在修改配置文件之前写备份

// 在master要做的事
[root@master redis-6.2.6]# mkdir logs
75 bind 192.168.182.137  //本机IP地址
94 protected-mode no  
302 logfile "/opt/redis-6.2.6/logs/redis.log"

注意replicaof指定master的IP地址和端口号,在老版本上事slaveof

// 在salve上要做的事
[root@slave redis-6.2.6]# vim redis.conf
75 bind 192.168.182.143  // 为本机IP
477   replicaof 192.168.182.137 6379  master的IP和端口号
// 在slave2上要做的事
[root@slave2 redis-6.2.6]# vim redis.conf
75 bind 192.168.182.143  //本机IP
477   replicaof 192.168.182.137 6379  master的IP和端口号

注意修改完配置文件之后需要重启redis服务才能生效

测试主从

[root@master redis-6.2.6]# redis-cli -h 192.168.182.137 -p 6379
192.168.182.137:6379> set name tom  // 设置一个value值
OK

[root@slave ~]# redis-cli -h 192.168.182.143  //这里也可以不指定端口号,因为redis默认使用的事6379端口号
192.168.182.143:6379> get name
"tom"

[root@slave2 redis-6.2.6]# redis-cli -h 192.168.182.144
192.168.182.144:6379> get name
"tom"

// 主从同步成功

搭建redis哨兵集群

  • 哨兵集群详解:
  • Redis Sentinel是Redis 的高可用性解决方案由一个或多个Sentinel(哨兵)实例组成。它可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,它的主要功能如下:
  • 监控: Sentinel会不断地检查你的主服务器和从服务器是否运作正常。
  • 通知:当被监控的某个 Redis 服务器出现问题时, Sentinel可以通过API向管理员或者其他应用程序发送通知。
  • 故障迁移:当主服务器不能正常工作时,Sentinel会自动进行故障迁移,也就是主从切换。
  • 统一的配置管理:连接者询问sentinel取得主从的地址。
  • 哨兵集群原理
    Sentinel 使用的算法核心是 Raft 算法,主要用途就是用于分布式系统,系统容错,以及Leader选举,每个Sentinel都需要定期的执行以下任务:
  • 每个 Sentinel 会自动发现其他 Sentinel 和从服务器,它以每秒钟一次的频率向它所知的主服务器、从服务器以及其他 Sentinel 实例发送一个 PING 命令。
  • 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 那么这个实例会被 Sentinel 标记为主观下线。 有效回复可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
  • 如果一个主服务器被标记为主观下线, 那么正在监视这个主服务器的所有Sentinel要以每秒一次的频率确认主服务器的确进入了主观下线状态。
  • 如果一个主服务器被标记为主观下线, 并且有足够数量的Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断, 那么这个主服务器被标记为客观下线。
  • 在一般情况下, 每个Sentinel会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令。 当一个主服务器被Sentinel标记为客观下线时,Sentinel向下线主服务器的所有从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
  • 当没有足够数量的Sentinel同意主服务器已经下线, 主服务器的客观下线状态就会被移除。 当主服务器重新向Sentinel的 PING 命令返回有效回复时, 主服务器的主管下线状态就会被移除。

搭建哨兵集群

// 三台主机做同样的操作
[root@master redis-6.2.6]# vim sentinel.conf
26 daemonize yes
36 logfile "/opt/redis-6.2.6/logs/sentinel.conf"
84 sentinel monitor mymaster 192.168.182.137 6379 2
[root@master ~]# redis-sentinel /opt/redis-6.2.6/sentinel.conf //启动哨兵
// 查看哨兵信息
[root@master ~]# redis-cli -h 192.168.182.137 -p 26379
192.168.182.137:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.182.137:6379,slaves=2,sentinels=3

[root@slave ~]# redis-cli -h 192.168.182.143 -p 26379
192.168.182.143:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.182.137:6379,slaves=2,sentinels=3


[root@slave2 ~]# redis-cli -h 192.168.182.144 -p 26379
192.168.182.144:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.182.137:6379,slaves=2,sentinels=3

模拟主机故障,进行容灾切换

[root@master ~]# systemctl stop redis.service  //关闭redis服务
[root@master redis-6.2.6]# ps -ef | grep redis  //使用此命令找到sentinel进程,然后再kill掉sentinel的进程
// 因为主机切换到了144主机,因此原来主机的配置文件也会随之更改,所以在137启动前需要更改配置文件,将其配置成144的从机:
[root@master redis-6.2.6]# vim redis.conf
477   replicaof 192.168.182.144 6379

[root@master redis-6.2.6]# redis-server /opt/redis-6.2.6/redis.conf //启动redis服务
[root@master redis-6.2.6]# systemctl restart redis.service  //也可以使用此命令启动redis服务

[root@master redis-6.2.6]# redis-sentinel /opt/redis-6.2.6/sentinel.conf  //启动sentinel服务

//至此哨兵集群搭建完毕