分布式系列教程(06) -分布式Redis缓存 (集群)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 分布式系列教程(06) -分布式Redis缓存 (集群)

代码已上传至Github,有兴趣的同学可以下载来看看:https://github.com/ylw-github/SpringBoot-Redis-Demo

本文目录结构:

l____引言

l____1. Redis-cluster

l________1.1 Redis-cluster 原理

l____2. Redis集群搭建

l________2.1 环境描述

l________2.2 各个Redis环境创建

l________2.3 安装Redis集群需要的环境

l________2.4 集群环境测试

l____3. SpringBoot整合Redis集群型

l____4.Redis集群的几个注意事项

l____总结

引言

Redis在3.0版本之前是不支持集群的,我们的redis如果想要集群的话,就需要一个中间件,然后这个中间件负责将我们需要存入redis中的数据的key通过一套算法计算得出一个值。然后根据这个值找到对应的redis节点,将这些数据存在这个redis的节点中。在取值的时候,同样先将key进行计算,得到对应的值,然后就去找对应的redis节点,从对应的节点中取出对应的值。

这样做有很多不好的地方,比如说我们的这些计算都需要在系统中去进行,所以会增加系统的负担。还有就是这种集群模式下,某个节点挂掉,其他的节点无法知道。而且也不容易对每个节点进行负载均衡。

常见的集群方案:

  1. 官方方案(redis-cluster搭建实战)
  2. (不推荐)客户端分片技术,扩容/缩容时,必须手动调整分片程序,出现故障不能自动转移
  3. (不推荐)可以使用主从复制方式
  4. 使用一些代理工具

下面将讲解Redis-Cluster搭建Redis集群。

1. Redis-cluster

1.1 Redis-cluster 原理

Redis 是一个开源的 key-value 存储系统,由于出众的性能,大部分互联网企业都用来做服务器端缓存。Redis 在3.0版本前只支持单实例模式,虽然支持主从模式、哨兵模式部署来解决单点故障,但是现在互联网企业动辄大几百G的数据,可完全是没法满足业务的需求,所以,Redis 在 3.0 版本以后就推出了集群模式。

Redis 集群采用了P2P的模式,完全去中心化。Redis 把所有的 Key 分成了 16384 个 slot(插槽),每个 Redis 实例负责其中一部分 slot 。集群中的所有信息(节点、端口、slot等),都通过节点之间定期的数据交换而更新。Redis 客户端可以在任意一个 Redis 实例发出请求,如果所需数据不在该实例中,通过重定向命令引导客户端访问所需的实例。

在这个图中,每一个蓝色的圈都代表着一个redis的服务器节点。它们任何两个节点之间都是相互连通的。客户端可以与任何一个节点相连接,然后就可以访问集群中的任何一个节点。对其进行存取和其他操作。

那么redis是怎么做到的呢?

首先,在redis的每一个节点上,都有这么两个东西,一个是插槽(slot)可以理解为是一个可以存储两个数值的一个变量,这个变量的取值范围是:0-16383,还有一个就是cluster我个人把这个cluster理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。

还有就是因为如果集群的话,是有好多个redis一起工作的,那么,就需要这个集群不是那么容易挂掉,所以呢,理论上就应该给集群中的每个节点至少一个备用的redis服务。这个备用的redis称为从节点(slave)。

那么这个集群是如何判断是否有某个节点挂掉了呢?

首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。如果某个节点和所有从节点全部挂掉,我们集群就进入fail状态。还有就是如果有一半以上的主节点宕机,那么我们集群同样进入发力状态。这就是我们的redis的投票机制,具体原理如下图所示:

这套架构的特点:

  • 分片算法:基于 slot hash桶;
  • 分片实例之间相互独立,每组 一个master 实例和多个slave;
  • 路由信息存放到第三方存储组件,如 zookeeper 或etcd
  • 旁路组件探活

2. Redis集群搭建

2.1 环境描述

安装部署任何一个应用其实都很简单,只要安装步骤一步一步来就行了,下面说一下 Redis 集群搭建规划。由于集群至少需要6个节点(3主3从模式),因为没有这么多机器,我本地也起不了那么多虚拟机,现在计划是在一台机器上模拟一个集群,当然,这和生产环境的集群搭建是没本质区别。

服务器 端口
9001主Redis服务器 192.168.162.131:9001
9002主Redis服务器 192.168.162.131:9002
9003主Redis服务器 192.168.162.131:9003
9004从Redis服务器 192.168.162.131:9004
9005从Redis服务器 192.168.162.131:9005
9006从Redis服务器 192.168.162.131:9006

2.2 各个Redis环境创建

1.创建文件夹:我们计划集群中 Redis 节点的端口号为 9001-9006 ,端口号即集群下各实例文件夹。数据存放在 端口号/data 文件夹中。

mkdir /usr/local/redis-cluster
cd redis-cluster/
mkdir -p 9001/data 9002/data 9003/data 9004/data 9005/data 9006/data

2.安装Redis(先不要配置):参考之前写的文章《Linux下安装Redis》,安装到第4步即可。

3.复制脚本:在/usr/local/redis-cluster下创建 bin 文件夹,用来存放集群运行脚本,并把安装好的 Redis 的 src 路径下的运行脚本拷贝过来:

cd /usr/local/redis-cluster
mkdir bin
cd /usr/local/redis-3.2.9/src
cp mkreleasehdr.sh redis-benchmark redis-check-aof  redis-cli redis-server redis-trib.rb /usr/local/redis-cluster/bin

4.复制一个新 Redis 实例:我们现在从已安装好的 Redis 中复制一个新的实例到 9001 文件夹,并修改 redis.conf 配置。

---- 复制redis实例:

cp -r /usr/local/redis  /usr/local/redis-cluster/9001

---- 修改redis.conf,搜索去修改:

port 9001(每个节点的端口号)
daemonize yes
bind 192.168.162.131(绑定当前机器 IP)
dir /usr/local/redis-cluster/9001/data/(数据文件存放位置)
pidfile /var/run/redis_9001.pid(pid 9001和port要对应)
cluster-enabled yes(启动集群模式)
cluster-config-file nodes9001.conf(9001和port要对应)
cluster-node-timeout 15000
appendonly yes

5.复制五个新 Redis 实例:我们已经完成了一个节点了,其实接下来就是机械化的再完成另外五个节点,其实可以这么做:把 9001 实例 复制到另外五个文件夹中,唯一要修改的就是 redis.conf 中的所有和端口的相关的信息即可,其实就那么四个位置,开始操作:

---- 复制五个redis实例:

\cp -rf /usr/local/redis-cluster/9001/*   /usr/local/redis-cluster/9002
\cp -rf /usr/local/redis-cluster/9001/*   /usr/local/redis-cluster/9003
\cp -rf /usr/local/redis-cluster/9001/*   /usr/local/redis-cluster/9004
\cp -rf /usr/local/redis-cluster/9001/*   /usr/local/redis-cluster/9005
\cp -rf /usr/local/redis-cluster/9001/*   /usr/local/redis-cluster/9006

\cp -rf 命令是不使用别名来复制,因为 cp 其实是别名 cp -i,操作时会有交互式确认,比较烦人。

---- 修改redis.conf,搜索9001去修改,修改4个部分:

port 900?(每个节点的端口号)
dir /usr/local/redis-cluster/900?/data/(数据文件存放位置)
pidfile /var/run/redis_9001.pid(pid 900?和port要对应)
cluster-config-file nodes9001.conf(900?和port要对应)
vi /usr/local/redis-cluster/9002/redis/etc/redis.conf
vi /usr/local/redis-cluster/9003/redis/etc/redis.conf
vi /usr/local/redis-cluster/9004/redis/etc/redis.conf
vi /usr/local/redis-cluster/9005/redis/etc/redis.conf
vi /usr/local/redis-cluster/9006/redis/etc/redis.conf

6.启动9001~9006六个节点:

/usr/local/redis/bin/redis-server  /usr/local/redis-cluster/9001/redis/etc/redis.conf
/usr/local/redis/bin/redis-server  /usr/local/redis-cluster/9002/redis/etc/redis.conf
/usr/local/redis/bin/redis-server  /usr/local/redis-cluster/9003/redis/etc/redis.conf
/usr/local/redis/bin/redis-server  /usr/local/redis-cluster/9004/redis/etc/redis.conf
/usr/local/redis/bin/redis-server  /usr/local/redis-cluster/9005/redis/etc/redis.conf
/usr/local/redis/bin/redis-server  /usr/local/redis-cluster/9006/redis/etc/redis.conf

7.使用9001测试:

/usr/local/redis-cluster/9001/redis/bin/redis-cli -h 192.168.162.131 -p 9001
set name "ylw"

发现报错 :(error) CLUSTERDOWN Hash slot not served

原因这是因为虽然我们配置并启动了 Redis 集群服务,但是他们暂时还并不在一个集群中,互相直接发现不了,而且还没有可存储的位置,就是所谓的slot(槽)

2.3 安装Redis集群需要的环境

由于 Redis 集群需要使用 ruby 命令,所以我们需要安装 ruby 和相关接口。

yum install ruby
yum install rubygems
gem install redis   #使用本地上传方式

当执行:gem install redis时,会发现一只卡着,不能下载,所以只能本地安装(已上传到百度网盘,链接:https://pan.baidu.com/s/1cPKa2X55SPVh5XR3iVAD9g 密码:z21e

使用ssh工具上传到/usr/local目录

安装:

gem install -l /usr/local/redis-3.2.1.gem

2.4 集群环境测试

1.启动集群,输入yes:

/usr/local/redis-cluster/bin/redis-trib.rb create --replicas 1 192.168.162.131:9001 192.168.162.131:9002 192.168.162.131:9003 192.168.162.131:9004 192.168.162.131:9005 192.168.162.131:9006

简单解释一下这个命令:调用 ruby 命令来进行创建集群,–replicas 1 表示主从复制比例为 1:1,即一个主节点对应一个从节点;然后,默认给我们分配好了每个主节点和对应从节点服务,以及 solt 的大小,因为在 Redis 集群中有且仅有 16383 个 solt ,默认情况会给我们平均分配,当然你可以指定,后续的增减节点也可以重新分配。

2.验证

在9001设置name:启动命令(记得加-c)不然会抱error:

/usr/local/redis-cluster/9001/redis/bin/redis-cli -h 192.168.162.131 -c -p 9001

在9003获取name:

可以看到在9003依然可以获取到name。

Redis 集群成功!

3. SpringBoot整合Redis集群

代码已提交到Github,版本号:b1dab796317110116e7b2b14b22e10b6f1033b1f

修改的地方不多,直接修改application.yml即可

spring:
  redis:
    database: 0
#    host: 132.232.44.194
#    port: 6379
#    password: 123456
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 8
        min-idle: 0
    timeout: 10000
    cluster:
      nodes:
        - 192.168.162.131:9001
        - 192.168.162.131:9002
        - 192.168.162.131:9003
        - 192.168.162.131:9004
        - 192.168.162.131:9005
        - 192.168.162.131:9006

设置age:浏览器输入:http://localhost:8080/setString?key=sex&value=male

在浏览器获取sex:

4.Redis集群的几个注意事项

  • Redis集群使用CRC16对key进行hash:集群固定使用16384对hash出来的值取模。因为取模结果一定在16384之内,所以集群中的sharding(分片)实际就是如何将16384个值在n个主节点间分配,如何分配取决于你的配置。
  • Redis生产级集群需要容灾:因此,一般部署为n个主+n*m个从。n大小主要取决于单机性能,m大小主要取决于机器稳定性。
  • Redis集群是弱一致性的:此处的一致,主要指主从之间的数据一致性。主要是因为redis在做数据更新时,不要求主从数据同步复制一定要成功。
    集群最小的主数量为3,主数量应为奇数,以便做选举判决。

总结

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
18天前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
26天前
|
缓存 NoSQL Java
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
45 3
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
|
7天前
|
存储 分布式计算 负载均衡
分布式计算模型和集群计算模型的区别
【10月更文挑战第18天】分布式计算模型和集群计算模型各有特点和优势,在实际应用中需要根据具体的需求和条件选择合适的计算架构模式,以达到最佳的计算效果和性能。
24 2
|
19天前
|
NoSQL Redis 数据库
计数器 分布式锁 redis实现
【10月更文挑战第5天】
39 1
|
23天前
|
NoSQL 算法 关系型数据库
Redis分布式锁
【10月更文挑战第1天】分布式锁用于在多进程环境中保护共享资源,防止并发冲突。通常借助外部系统如Redis或Zookeeper实现。通过`SETNX`命令加锁,并设置过期时间防止死锁。为避免误删他人锁,加锁时附带唯一标识,解锁前验证。面对锁提前过期的问题,可使用守护线程自动续期。在Redis集群中,需考虑主从同步延迟导致的锁丢失问题,Redlock算法可提高锁的可靠性。
63 4
|
3天前
|
存储 监控 大数据
构建高可用性ClickHouse集群:从单节点到分布式
【10月更文挑战第26天】随着业务的不断增长,单一的数据存储解决方案可能无法满足日益增加的数据处理需求。在大数据时代,数据库的性能、可扩展性和稳定性成为企业关注的重点。ClickHouse 是一个用于联机分析处理(OLAP)的列式数据库管理系统(DBMS),以其卓越的查询性能和高吞吐量而闻名。本文将从我的个人角度出发,分享如何将单节点 ClickHouse 扩展为高可用性的分布式集群,以提升系统的稳定性和可靠性。
15 0
|
17天前
|
SQL NoSQL MongoDB
一款基于分布式文件存储的数据库MongoDB的介绍及基本使用教程
一款基于分布式文件存储的数据库MongoDB的介绍及基本使用教程
32 0
|
23天前
|
缓存 NoSQL 算法
面试题:Redis如何实现分布式锁!
面试题:Redis如何实现分布式锁!
|
3月前
|
NoSQL Redis
基于Redis的高可用分布式锁——RedLock
这篇文章介绍了基于Redis的高可用分布式锁RedLock的概念、工作流程、获取和释放锁的方法,以及RedLock相比单机锁在高可用性上的优势,同时指出了其在某些特殊场景下的不足,并提到了ZooKeeper作为另一种实现分布式锁的方案。
102 2
基于Redis的高可用分布式锁——RedLock
|
3月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】