Redis分布式

本文解析了集群和分布式系统的概念及区别,介绍了从单机结构到集群再到分布式结构的演进过程,并深入探讨了Redis分布式环境配置及算法原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

集群和分布式的区别

生动形象地讲解了集群和分布式的区别

单机结构

当系统业务量很小的时候,我们可以将所有的代码放在一个项目,之后将这个项目部署在一台服务器上就好。整个项目的所有服务都又这台服务器提供,这就是单机结构。

集群

当单机结构到达性能瓶颈时,我们将"单机"复制几分,这样就构成了一个集群。集群中每台服务器就叫做这个集群中的一个"节点",所有节点构成了一个集群,每个节点都提供相同的服务。那么这样系统的处理能力就相当于提升了好多倍(有几个节点就相当于提升了这么多倍)

集群中涉及到用户的请求转发问题,当客户端对服务器进行请求时,应该选择集群下哪个节点处理较合适?理论上选择此刻负载较小的节点来处理,这样使得每个节点的压力都比较平均。我们在所有节点前增加一个"调度者"的角色,用户的所有请求都先交给它,然后它根据当前集群中节点的负载情况,决定将请求派发给谁。这个"调度者"便是负载均衡处理器,通常由Nginx实现。

分布式

从单机结构到集群结构,代码基本不需要改动,只需要多部署几台服务器即可,每台服务器上运行相同的代码。但是当集群结构演进至分布式结构,代码就需要发生较大的改动,升级成微服务架构。
==分布式结构就是将一个完整的系统,按照业务功能,拆分成独立的子系统。在分布式结构中,每个子系统被称为"服务"==这些子系统能够独立运行在Web容器中,它们之间通过RPC方式通信。

举个例子,假设需要开发一个在线商城。按照微服务的思想,我们需要按照功能模块拆分成多个独立的服务,如:用户服务、产品服务、订单服务、后台管理服务、数据分析服务等等。这一个个服务都是一个个独立的项目,可以独立运行。如果服务之间有依赖关系,那么通过RPC方式调用。
优点:

  1. 系统之间的耦合度大大降低,可以独立开发、独立部署、独立测试,系统与系统之间的边界非常明确,排错也变得相当容易,开发效率大大提升
  2. 系统之间的耦合度降低,从而系统更易于扩展。我们可以针对性地扩展某些服务。假设这个商城要搞一次大促,下单量可能会大大提升,因此我们可以针对性地提升订单系统、产品系统的节点数量,而对于后台管理系统、数据分析系统而言,节点数量维持原有水平即可
  3. 服务的复用性更高。比如,当我们将用户系统作为单独的服务后,该公司所有的产品都可以使用该系统作为用户系统,无需重复开发

在这里插入图片描述

Redis分布式算法原理

用图片的方式生动详细地讲解了Redis分布式算法原理

在这里插入图片描述

Redis分布式环境配置

修改两个Redis的配置文件redis.conf,将其中一个端口修改为6380。

启动Redis服务端
通过配置文件启动redis-server

。/redis.sercer ../redis.conf

启动Redis客户端
启动客户端需要指定端口

./redis.cli -p 6379|6380
Jedis下分布式Redis
public class RedisShardedPool {
    private static ShardedJedisPool pool;//sharded jedis连接池
    private static Integer maxTotal = Integer.parseInt(PropertiesUtil.getProperty("redis.max.total","20")); //最大连接数
    private static Integer maxIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.max.idle","20"));//在jedispool中最大的idle状态(空闲的)的jedis实例的个数
    private static Integer minIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.min.idle","20"));//在jedispool中最小的idle状态(空闲的)的jedis实例的个数

    private static Boolean testOnBorrow = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.borrow","true"));//在borrow一个jedis实例的时候,是否要进行验证操作,如果赋值true。则得到的jedis实例肯定是可以用的。
    private static Boolean testOnReturn = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.return","true"));//在return一个jedis实例的时候,是否要进行验证操作,如果赋值true。则放回jedispool的jedis实例肯定是可以用的。

//    private static String redisIp = PropertiesUtil.getProperty("redis.ip");
//    private static Integer redisPort = Integer.parseInt(PropertiesUtil.getProperty("redis.port"));

    
    private static String redis2Ip = PropertiesUtil.getProperty("redis2.ip");
    private static Integer redis2Port = Integer.parseInt(PropertiesUtil.getProperty("redis2.port"));
    private static String redis1Ip = PropertiesUtil.getProperty("redis1.ip");
    private static Integer redis1Port = Integer.parseInt(PropertiesUtil.getProperty("redis1.port"));



    private static void initPool(){
        JedisPoolConfig config = new JedisPoolConfig();

        config.setMaxTotal(maxTotal);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);

        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);

        config.setBlockWhenExhausted(true);//连接耗尽的时候,是否阻塞,false会抛出异常,true阻塞直到超时。默认为true。

//        JedisShardInfo info = new JedisShardInfo(redisIp,redisPort,1000*2);

        JedisShardInfo info2 = new JedisShardInfo(redis2Ip,redis2Port,1000*2);

        JedisShardInfo info1 = new JedisShardInfo(redis1Ip,redis1Port,1000*2);

        List<JedisShardInfo> jedisShardInfoList = new ArrayList<JedisShardInfo>(2);

//        jedisShardInfoList.add(info);
        jedisShardInfoList.add(info2);
        jedisShardInfoList.add(info1);

        pool = new ShardedJedisPool(config,jedisShardInfoList, Hashing.MURMUR_HASH, Sharded.DEFAULT_KEY_TAG_PATTERN);
    }

    static{
        initPool();
    }

    public static ShardedJedis getJedis(){
        return pool.getResource();
    }


    public static void returnBrokenResource(ShardedJedis jedis){
        pool.returnBrokenResource(jedis);
    }



    public static void returnResource(ShardedJedis jedis){
        pool.returnResource(jedis);
    }


    public static void main(String[] args) {
        ShardedJedis jedis = pool.getResource();
		
		//添加key,Redis根据一致性哈希算法存入对应的Cache
		//获取Key时,Redis通过同样的哈希算法得出对应的Key先前存在哪个Cache,去那个Cache下找key
        for(int i =0;i<10;i++){
            jedis.set("key"+i,"value"+i);
        }
        returnResource(jedis);

//        pool.destroy();//临时调用,销毁连接池中的所有连接
        System.out.println("program is end");


    }
}
@Slf4j
public class RedisShardedPoolUtil {

    /**
     * 设置key的有效期,单位是秒
     * @param key
     * @param exTime
     * @return
     */
    public static Long expire(String key,int exTime){
        ShardedJedis jedis = null;
        Long result = null;
        try {
            jedis = RedisShardedPool.getJedis();
            result = jedis.expire(key,exTime);
        } catch (Exception e) {
            log.error("expire key:{} error",key,e);
            RedisShardedPool.returnBrokenResource(jedis);
            return result;
        }
        RedisShardedPool.returnResource(jedis);
        return result;
    }

    //exTime的单位是秒
    public static String setEx(String key,String value,int exTime){
        ShardedJedis jedis = null;
        String result = null;
        try {
            jedis = RedisShardedPool.getJedis();
            result = jedis.setex(key,exTime,value);
        } catch (Exception e) {
            log.error("setex key:{} value:{} error",key,value,e);
            RedisShardedPool.returnBrokenResource(jedis);
            return result;
        }
        RedisShardedPool.returnResource(jedis);
        return result;
    }

    public static String set(String key,String value){
        ShardedJedis jedis = null;
        String result = null;

        try {
            jedis = RedisShardedPool.getJedis();
            result = jedis.set(key,value);
        } catch (Exception e) {
            log.error("set key:{} value:{} error",key,value,e);
            RedisShardedPool.returnBrokenResource(jedis);
            return result;
        }
        RedisShardedPool.returnResource(jedis);
        return result;
    }

    public static String getSet(String key,String value){
        ShardedJedis jedis = null;
        String result = null;

        try {
            jedis = RedisShardedPool.getJedis();
            result = jedis.getSet(key,value);
        } catch (Exception e) {
            log.error("getset key:{} value:{} error",key,value,e);
            RedisShardedPool.returnBrokenResource(jedis);
            return result;
        }
        RedisShardedPool.returnResource(jedis);
        return result;
    }

    public static String get(String key){
        ShardedJedis jedis = null;
        String result = null;
        try {
            jedis = RedisShardedPool.getJedis();
            result = jedis.get(key);
        } catch (Exception e) {
            log.error("get key:{} error",key,e);
            RedisShardedPool.returnBrokenResource(jedis);
            return result;
        }
        RedisShardedPool.returnResource(jedis);
        return result;
    }

    public static Long del(String key){
        ShardedJedis jedis = null;
        Long result = null;
        try {
            jedis = RedisShardedPool.getJedis();
            result = jedis.del(key);
        } catch (Exception e) {
            log.error("del key:{} error",key,e);
            RedisShardedPool.returnBrokenResource(jedis);
            return result;
        }
        RedisShardedPool.returnResource(jedis);
        return result;
    }

    public static Long setnx(String key,String value){
        ShardedJedis jedis = null;
        Long result = null;

        try {
            jedis = RedisShardedPool.getJedis();
            result = jedis.setnx(key,value);
        } catch (Exception e) {
            log.error("setnx key:{} value:{} error",key,value,e);
            RedisShardedPool.returnBrokenResource(jedis);
            return result;
        }
        RedisShardedPool.returnResource(jedis);
        return result;
    }

}
<think>好的,用户想了解Redis分布式环境下的应用或配置,特别是分布式部署与实现。首先,我需要回顾一下Redis分布式方案,尤其是Redis Cluster,因为这是官方推荐的。记得引用[1]和[3]提到Redis Cluster是官方3.0版本推出的,支持自动分片和故障转移。 接下来,用户可能需要知道不同的分布式方案之间的区别。比如主从复制、哨兵模式和Cluster模式的区别。主从复制主要是数据备份和读写分离,但需要手动故障转移。而哨兵模式可以自动处理故障转移,但分片还是得自己处理。Cluster模式则解决了分片和自动故障转移的问题,适合大规模应用。 然后,Redis Cluster的核心机制是什么?根据引用[4],数据分区是通过哈希槽(hash slot)实现的,总共有16384个槽。每个主节点负责一部分槽,数据根据key的CRC16值分配到对应的槽。这需要详细说明一下,包括节点间的通信和故障检测机制,比如Gossip协议。 另外,分布式部署的具体步骤可能也是用户关心的。比如如何配置集群,需要多少个节点,以及如何分配槽。可能需要提到使用redis-cli工具创建集群,以及节点添加和删除的过程。还有,从节点的作用,作为备份和故障转移的支持,引用[4]提到从节点复制主节点数据和状态。 应用场景方面,用户可能想知道什么时候该用Redis Cluster。比如高并发、大数据量需要水平扩展,或者需要高可用性的场景。引用[1]和[3]提到适合大规模分布式系统,所以可以强调这些情况下的优势。 还需要考虑一些注意事项,比如客户端需要支持集群协议,避免跨槽操作,以及批量操作可能受到限制。此外,网络稳定性很重要,节点间的延迟会影响性能。可能还要提到Redisson框架(引用[2])如何帮助实现分布式锁,作为分布式环境中的一个应用例子。 最后,用户可能需要相关的问题,比如如何选择不同的分布式方案,Cluster的扩容步骤,或者与代理分片的区别。这可以帮助他们进一步探索。</think>### Redis 分布式部署与实现 Redis分布式环境下的核心方案是 **Redis Cluster**,其通过数据分片和主从复制实现高可用与横向扩展。以下是关键实现细节与应用场景: --- #### 一、Redis 分布式方案对比 1. **主从复制** - **作用**:数据冗余与读写分离(主节点写,从节点读)。 - **局限**:需手动处理主节点故障,无自动分片能力。 2. **哨兵模式(Sentinel)** - **作用**:监控主节点状态,自动选举新主节点实现故障转移[^3]。 - **局限**:数据分片仍需客户端或代理层实现。 3. **Redis Cluster(官方推荐)** - **核心能力**: - **自动分片**:数据按哈希槽(16384 个槽)分布到多个主节点[^4]。 - **故障转移**:主节点宕机时,从节点自动升级为主节点[^1]。 - **适用场景**:大规模数据、高并发读写需求[^3]。 --- #### 二、Redis Cluster 实现机制 1. **数据分片** - 每个键通过公式 `CRC16(key) % 16384` 映射到哈希槽。 - 节点启动时声明负责的槽范围,例如: ```bash redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 ... --cluster-replicas 1 ``` 2. **节点通信** - 节点间通过 **Gossip 协议**交换状态信息(如槽分配、节点存活)。 - 客户端可连接任意节点,若请求的键不属于当前节点,返回 `MOVED` 重定向指令。 3. **故障转移** - 主节点宕机后,从节点发起选举,获得多数主节点投票后接替主节点角色。 --- #### 三、配置示例 ```bash # 启动 6 个节点(3 主 + 3 从) redis-server /path/to/redis_7000.conf --port 7000 --cluster-enabled yes redis-server /path/to/redis_7001.conf --port 7001 --cluster-enabled yes # ...其他节点同理 # 创建集群(1 个从节点对应 1 个主节点) redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \ 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1 ``` --- #### 四、应用场景 1. **高并发读写**:如电商秒杀系统,分片降低单节点压力。 2. **高可用需求**:金融交易系统,故障转移保障服务连续性。 3. **海量数据存储**:日志分析场景,横向扩展突破单机内存限制。 --- #### 五、注意事项 1. **客户端兼容性**:需支持集群协议(如 JedisCluster、Redisson[^2])。 2. **跨槽操作限制**:事务、Lua 脚本中的键需在同一节点。 3. **网络要求**:节点间延迟过高可能导致集群状态异常。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值