【分布式】Redis分布式缓存

一、什么是Redis分布式缓存

  • Redis分布式缓存是指使用Redis作为缓存系统来存储和管理数据的分布式方案。在分布式系统中,多台服务器共同对外提供服务,为了提高系统的性能和可扩展性,通常会引入缓存来减轻数据库的压力。Redis作为一种高性能的内存数据库,具备快速读写和高并发处理能力,非常适合用作分布式缓存。

二、Redis分布式缓存的特点

特点 描述
分布式架构 使用主从复制和集群模式实现数据的分布式存储和管理
内存存储 数据存储在内存中,提供快速读写和高并发处理能力
支持多种数据结构 提供字符串、哈希、列表、集合和有序集合等多种数据结构
缓存淘汰策略 支持多种缓存淘汰策略,如LRU、LFU和随机等
缓存穿透防止 使用布隆过滤器等技术,防止缓存穿透
高并发处理能力 使用单线程和非阻塞IO等机制,处理大量并发请求
高可用性 支持主从复制和集群模式,保证数据的高可用性和可扩展性
灵活的缓存策略 可根据业务需求选择合适的缓存策略
提升系统性能和可扩展性 减轻数据库负载压力,提升系统的性能和可扩展性
支持丰富的数据处理功能 提供丰富的数据结构和数据操作命令,支持灵活的数据处理需求
提供缓存监控和管理功能 提供监控和管理工具,方便管理和维护分布式缓存系统
安全稳定 Redis具备持久化机制,支持数据备份和恢复,保证数据的安全稳定性
易于使用和部署 Redis具有简单的配置和易于使用的接口,方便部署和集成到系统中
社区活跃 Redis拥有庞大的开源社区,持续不断地发布新版本和解决问题

三、Redis分布式缓存的多种实现方式及区别

实现方式 描述 主要区别
主从复制 通过配置主节点(Master)和从节点(Slave)实现数据复制 - 主节点负责写入操作,从节点用于读取操作和备份 - 可以通过配置多个从节点实现负载均衡与高可用性
哨兵模式 使用哨兵节点(Sentinel)监控主节点状态并进行故障转移 - 哨兵节点负责监控主节点的状态 - 当主节点失效时,自动选举从节点为新的主节点 - 支持高可用性
Redis Cluster 使用多个Redis实例以集群的方式共同管理一个数据集 - 数据被分割为多个哈希槽,存储在不同节点上 - 自动进行数据复制与故障转移 - 支持负载均衡与高可用性

四、主从复制模式

1. 什么是主从复制模式

  • 主从复制模式是指在分布式系统中,通过设置一个主节点(Master)和多个从节点(Slave)来实现数据的复制和同步。主节点负责接收和处理所有的写操作,而从节点则负责复制主节点的数据,并用于读取操作和备份。

2. 主要实现步骤

  1. 配置主节点:

    首先选择一个节点作为主节点,在主节点的配置文件中,开启主从复制功能,设置好监听端口和网络地址,并开启对外提供服务。

  2. 配置从节点:

    选择服务器作为从节点,在从节点的配置文件中,设置好主节点的网络地址和端口,并开启对主节点的连接。

  3. 启动主节点:

    在主节点上启动数据库服务,并确保数据库服务正常运行。

  4. 启动从节点:

    在从节点上启动数据库服务,并确保数据库服务正常运行。

  5. 主节点授权:

    在主节点上设置一个授权密码,并将密码配置到从节点中,以实现从节点对主节点的连接。

  6. 从节点连接主节点:

    从节点会通过向主节点发送SYNC命令来建立与主节点的连接,并发送复制命令。

  7. 主节点接受从节点:

    主节点接受从节点的连接请求,并验证从节点的身份。

  8. 数据同步:

    主节点将自己的数据同步到从节点。初始同步可以通过全量复制,即将主节点的全部数据复制到从节点;增量同步则是主节点将新写入的数据实时传输给从节点。

  9. 数据更新和读取:

    所有写入操作都要在主节点上进行,主节点会将更新的数据同步到所有从节点。读取操作可以在主节点或从节点上进行,从节点可以提供读取服务以减轻主节点的负载。

  10. 监控和故障切换:

    监控主节点的状态和性能,当主节点发生故障时,可以通过手动或自动的方式将一个从节点提升为新的主节点,以保证服务的可用性和连续性。

3. 重要机制

重要机制 描述
1. 全量复制 主节点接收到SYNC命令后,会开启一个后台线程,将自己的整个数据集发送给从节点。
2. 增量复制 主节点会将新的写命令发送给从节点,并通过每秒发送一个心跳包来保持与从节点的连接。从节点接收到新的写命令后,会对数据进行更新。
3. 心跳检测 主节点会通过发送心跳包来检测与从节点的连接是否正常。如果连接断开,主节点会尝试重新连接。
4. 断线重连 从节点如果与主节点的连接断开,会尝试重新连接。主节点会检测到从节点的重新连接,并继续发送增量复制的命令。
5. 故障转移 当主节点发生故障时,Redis集群会从从节点中选举一个新的主节点,然后将其他从节点切换到新的主节点上。
6. 同步延迟 由于网络原因或主节点负载过高,从节点可能会出现同步延迟的情况。这会导致从节点的数据不是实时更新。

五、Redis Cluster模式

1. 什么是Redis Cluster模式

  • Redis Cluster模式是Redis官方提供的一种分布式数据存储解决方案,用于支持在多个节点上分片和复制数据。它的设计目标是提供高可用性、可扩展性和数据一致性。

  • 在Redis Cluster模式中,数据被分布在多个节点上,并且每个节点都负责处理一部分数据。为了实现数据的均匀分布和高可用性,Redis Cluster使用了一致性哈希算法,将数据映射到一个固定数量的槽位上。每个节点负责管理一些槽位和相应的数据。

  • 除了数据的分片,Redis Cluster还提供了数据的复制功能,通过将数据复制到其他节点上来保证数据的冗余和故障恢复。每个节点可以有多个副本节点,其中一个节点是主节点,负责处理写操作,其他是从节点,负责复制主节点的数据。

  • Redis Cluster通过使用Gossip协议来实现节点之间的通信和故障检测。每个节点会周期性地与其他节点进行通信,交换关于自己和其他节点的信息,从而达到故障检测、故障转移和数据迁移的目的。

总体来说,Redis Cluster模式是一种可扩展、高可用的分布式数据存储方案,适用于需要处理大量数据和高并发的场景。

2. 主要实现步骤

  1. 配置文件:

    为每个节点创建一个配置文件。配置文件中需要指定节点的IP地址、端口号、节点类型(主节点/从节点)等信息。

  2. 启动节点:

    启动每个节点的Redis服务器,可以通过命令行启动或者使用配置文件来启动。启动时需要指定节点的配置文件。

  3. 创建集群:

    选择一个节点作为初始节点,通过命令行工具redis-cli或者Redis提供的脚本redis-trib.rb来创建集群。使用命令行工具时,可以执行命令redis-cli --cluster create <node1> <node2> ... <nodeN> --cluster-replicas <replicas>,其中<node1> <node2> ... <nodeN>是所有节点的IP地址和端口号,<replicas>是每个主节点对应的从节点数量。

  4. 添加节点:

    在集群创建完成后,可以通过命令行工具或者脚本来添加新的节点到集群中。使用命令行工具时,可以执行命令redis-cli --cluster add-node <new_node> <existing_node>,其中<new_node>是要添加的节点IP地址和端口号,<existing_node>是已存在的节点IP地址和端口号。

  5. 扩容:

    如果需要扩容集群,可以在已经添加的节点上执行命令redis-cli --cluster reshard <node>,其中<node>是一个已存在的节点。该命令会引导你完成数据迁移和槽位重分配的操作。

  6. 故障转移:

    如果某个节点发生故障或者下线,Redis Cluster会自动进行故障转移操作,选择一个从节点提升为主节点,保证数据的可用性。

需要注意的是,在Redis Cluster中,每个节点都需要运行一个Redis服务器实例,而且每个节点都需要使用相同的配置文件(或者至少具有相同的集群配置)。另外,Redis Cluster节点之间通过Gossip协议进行通信和故障检测,所以确保网络正常运行是很重要的。

3. 重要机制

重要机制 描述
1. 集群槽分配 集群将整个数据集分成16384个槽,每个槽可以存储一个键值对。每个节点负责管理一部分槽的数据。
2. 节点互连 节点通过互相发送PING和PONG命令来建立互连关系。节点会维护一个集群状态,包含其他节点的信息。
3. 槽迁移 当节点加入或离开集群时,槽的分配会发生变化。集群会通过将槽从一个节点迁移到另一个节点来完成槽的重新分配。
4. 数据传播 当一个主节点接收到一个写命令时,它会将该命令发送给对应的从节点,并等待从节点确认。如果从节点没有确认,主节点会将命令发送给其他从节点。
5. 故障转移 当一个主节点不可用时,集群会通过选举过程将一个从节点升级为新的主节点。其他从节点会重新分配槽,并将数据从旧的主节点复制到新的主节点。
6. 客户端请求路由 客户端发送一个命令到任意一个节点,节点会根据命令的键值计算槽,并将请求路由到负责该槽的节点。
7. 节点状态监控 集群会定期检测节点的健康状态,包括节点是否可达、是否正常工作等。如果节点不可达或出现异常,集群会进行相应的处理。

Redis Cluster模式实现了数据的分布存储、故障转移和负载均衡的功能。集群中的每个节点都是平等的,可以接收客户端的读写请求,提高了系统的可用性和扩展性。

六、主从复制模式与Redis cluster的区别

主从复制 数据分片
部署方式 一主多从 多节点
写操作 主节点处理 分布在多节点
读操作 主节点和从节点都可处理 分布在多节点
可用性 主节点故障时,需要手动进行故障切换 单节点故障不影响整体可用性
扩展性 读操作可以扩展到多个从节点 数据分布在多个节点,可以横向扩展
数据一致性 主节点会将数据同步到从节点,有一定的延迟 数据分散在多个节点,可能会出现一致性问题
数据备份 从节点可用作数据备份 数据存储在多个节点,提供数据冗余
部署规模 适合小规模集群 适合大规模集群
场景适用 读写分离的场景,读多写少 数据规模大,需要横向扩展的场景

七、Redis分布式缓存的Java使用示例

java 复制代码
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisCache {
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;
    private static JedisPool jedisPool;

    static {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(100); // 设置最大连接数
        jedisPoolConfig.setMaxIdle(10); // 设置最大空闲连接数

        // 创建连接池
        jedisPool = new JedisPool(jedisPoolConfig, REDIS_HOST, REDIS_PORT);
    }

    public static void put(String key, String value) {
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.set(key, value);
        }
    }

    public static String get(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.get(key);
        }
    }

    public static void remove(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.del(key);
        }
    }
}

在上面的示例中,首先创建了一个JedisPool对象,用于连接Redis服务器。然后,在put方法中使用try-with-resources语句获取Jedis实例,并使用set方法将键值对存储到Redis中。在get方法中同样使用try-with-resources语句获取Jedis实例,并使用get方法从Redis中获取值。在remove方法中使用try-with-resources语句获取Jedis实例,并使用del方法删除键值对。

这只是一个简单的示例,可以根据自己的需求进行扩展和优化,例如添加缓存过期时间、添加对象序列化和反序列化等。

八、Redis分布式缓存的SpringBoot实现示例

  1. 首先,在pom.xml文件中添加Redis和Spring Boot的相关依赖:
xml 复制代码
<dependencies>
    <!-- Redis依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- Spring Boot依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
  1. 在application.properties文件中配置Redis连接信息:
properties 复制代码
# Redis连接信息
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
  1. 创建一个缓存工具类RedisCacheUtil.java,用于操作Redis缓存:
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedisCacheUtil {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 存储缓存数据
    public void setCacheObject(String key, Object value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    // 获取缓存数据
    public Object getCacheObject(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    // 删除缓存数据
    public boolean deleteCacheObject(String key) {
        return redisTemplate.delete(key);
    }
}
  1. 创建一个Controller类,用于测试缓存的读写操作:
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/cache")
public class CacheController {

    @Autowired
    private RedisCacheUtil redisCacheUtil;

    @GetMapping("/get/{key}")
    public Object getCache(@PathVariable String key) {
        // 从缓存中获取数据
        Object value = redisCacheUtil.getCacheObject(key);
        if (value != null) {
            return value;
        }
        // 如果缓存中不存在,则从数据库中获取数据,并存入缓存
        value = fetchDataFromDatabase(key);
        redisCacheUtil.setCacheObject(key, value, 5, TimeUnit.MINUTES);
        return value;
    }

    @GetMapping("/delete/{key}")
    public boolean deleteCache(@PathVariable String key) {
        // 删除缓存数据
        return redisCacheUtil.deleteCacheObject(key);
    }

    // 模拟从数据库中获取数据的方法
    private Object fetchDataFromDatabase(String key) {
        // ...
        return "Data from database for key: " + key;
    }
}

通过访问/cache/get/{key}可以从缓存中获取数据,如果缓存中不存在,则从数据库中获取数据并存入缓存;通过访问/cache/delete/{key}可以删除缓存数据。

相关推荐
java技术小馆1 小时前
Zookeeper中的Zxid是如何设计的
java·分布式·zookeeper·云原生
DemonAvenger1 小时前
深入剖析 sync.Once:实现原理、应用场景与实战经验
分布式·架构·go
Vic23342 小时前
Kafka简要介绍与快速入门示例
分布式·kafka
敲上瘾3 小时前
高并发内存池(二):Central Cache的实现
linux·服务器·c++·缓存·哈希算法
Lethehong4 小时前
崖山YashanDB:下一代国产分布式数据库的架构革新与行业实践
数据库·分布式·架构
遇码13 小时前
单机快速部署开源、免费的分布式任务调度系统——DolphinScheduler
大数据·运维·分布式·开源·定时任务·dolphin·scheduler
csjane107914 小时前
Redis原理:rename命令
java·redis
Feng.Lee14 小时前
聊一聊缓存如何进行测试
功能测试·测试工具·缓存
纪元A梦15 小时前
分布式锁算法——基于ZooKeeper的分布式锁全面解析
java·分布式·算法·zookeeper
小样vvv15 小时前
【分布式】Hystrix 的核心概念与工作原理
分布式·hystrix