14.Redis分布式、分片式集群基本使用

目录


Redis专栏目录(点击进入…)



Redis分布式、分片式集群基本使用

提高Redis的读写能力

客户端集群(分片式)

1.redis.properties配置文件

redis.maxTotal=200
redis.node1.ip=127.0.0.1
redis.node1.port=6379
redis.node2.ip=localhost
redis.node2.port=6379

2.配置applicationContext-redis.xml

<!-- Spring和Jedis整合 -->
<!-- 配置连接池 -->
<bean class="redis.clients.jedis.JedisPoolConfig" id="jedisPoolConfig">
	<!-- 最大连接数 -->
	<property name="maxTotal" value="${redis.maxTotal}" />
</bean>

<!-- 配置分片式集群 -->
<bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool">
	<constructor-arg index="0" ref="jedisPoolConfig" />
	<constructor-arg index="1">
		<list>
		<bean class="redis.clients.jedis.JedisShardInfo">
			<constructor-arg index="0" value="${redis.node1.ip}" />
			<constructor-arg index="1" value="${redis.node1.port}" />
		</bean>
		<bean class="redis.clients.jedis.JedisShardInfo">
			<constructor-arg index="0" value="${redis.node2.ip}"/>
			<constructor-arg index="1" value="${redis.node2.port}"/>
		</bean>
		</list>
	</constructor-arg>
</bean>

3.封装ShardedJedisPool使用

@Service
public class RedisService {
	// 注入的分片集群的连接池
	@Autowired(required = false)
	private ShardedJedisPool shardedJedisPool;

	// 抽取一个方法
	public <T> T execute(RedisFunction<T, ShardedJedis> fun) {
		ShardedJedis jedis = null;
		try {
			jedis = shardedJedisPool.getResource();
			return fun.callback(jedis);// 执行具体的方法,具体的方法知道吗?
		} finally {
			if (null != jedis) {
				// 关闭资源,把连接放回我们的连接池中
				jedis.close();
			}
		}
	}

	/**
	 * 在redis中添加数据
	 * 
	 * @param key   键
	 * @param value 值
	 * @return
	 */
	public String set(String key, String value) {
		return execute(new RedisFunction<String, ShardedJedis>() {
			@Override
			public String callback(ShardedJedis e) {
				return e.set(key, value);
			}
		});
	}

	/**
	 * 
	 * 在redis中添加数据并且设置生命周期 --> 秒
	 * 
	 * @param key     键
	 * @param value   值
	 * @param seconds 生命周期(秒)
	 * @return
	 */
	public String set(String key, String value, Integer seconds) {
		return execute(new RedisFunction<String, ShardedJedis>() {
			@Override
			public String callback(ShardedJedis e) {
				String str = e.set(key, value);
				e.expire(key, seconds);
				return str;
			}
		});
	}

	/**
	 * 在redis获取数据
	 * 
	 * @param key 键
	 * @return
	 */
	public String get(String key) {
		return execute(new RedisFunction<String, ShardedJedis>() {
			@Override
			public String callback(ShardedJedis e) {
				return e.get(key);
			}
		});
	}

	/**
	 * 在redis中删除
	 * 
	 * @param key 键
	 * @return
	 */
	public Long del(String key) {
		return execute(new RedisFunction<Long, ShardedJedis>() {
			@Override
			public Long callback(ShardedJedis e) {
				return e.del(key);
			}
		});
	}

	/**
	 * 在redis中设置时间
	 * 
	 * @param key     键
	 * @param seconds 生命周期
	 * @return
	 */
	public Long expire(String key, Integer seconds) {
		return execute(new RedisFunction<Long, ShardedJedis>() {
			@Override
			public Long callback(ShardedJedis e) {
				return e.expire(key, seconds);
			}
		});
	}
}

分片式集群
在redis中的集群有两种
(1)一种是分片式集群
(2)一种是官方正式提出的集群

无法动态增加减少服务节点
ps: redis在3.0之前是没有集群的

为什么无法动态增加减少服务节点?
因为服务节点的数量,涉及到了hash值的计算,如果现在有两台服务器,hash值是要根据这两台服务器去查找;如果有三台,那么hash值的计算就会发生变化,;同理如果4台,5台同样也会发生变化,减少服务器节点也是一样的

那么分片就不用了?
当然不是,如果架构中存在两台redis服务器,足以支撑服务,就不会遇到上面说的问题

早期的时候就只有分片
在这里插入图片描述

分片式集群使用:需要两台电脑

// 1.构建一个连接池的信息
JedisPoolConfig config = new JedisPoolConfig();
// 2.设置最大的连接数
config.setMaxTotal(30);
// 定义集群信息
List<JedisShardInfo> list = new ArrayList<JedisShardInfo>();
list.add(new JedisShardInfo("127.0.0.1", 6379));
list.add(new JedisShardInfo("localhost", 6379));
// 定义集群连接池
ShardedJedisPool pool = new ShardedJedisPool(config, list);
// 定于jedis分片对象
ShardedJedis shardedJedis = null;
// 从连接池中获取jedis分片对象
shardedJedis = pool.getResource();
// 设置多个数据,通过从连接池中获取的Jedis分片对象设置10个key
for (int x = 0; x < 10; x++) {
	shardedJedis.set("key_" + x, "value_" + x);
}

// 随便从10个key中获取数据
System.out.println(shardedJedis.get("key_0"));
System.out.println(shardedJedis.get("key_3"));
// 把连接放入到连接池中
if (null != shardedJedis) {
	// 关闭
	shardedJedis.close();
}
// 关闭连接池
pool.close();

服务端集群(分布式)

1.导入依赖

<!-- Jedis,Redis的Java客户端 -->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.9.0</version>
</dependency>

2.redis.properties配置文件

redis.maxActive=1000
redis.maxIdle=10
redis.maxWaitMillis=30000
redis.testOnBorrow=true

3.配置文件(applicationContext.xml)

<!-- 加载Jedis配置文件 -->
<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:redis.properties</value>
        </list>
    </property>
</bean>

<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
    <constructor-arg name="jedisClusterNode">
        <set>
            <ref bean="nodes1"/>
            <ref bean="nodes2"/>
            <ref bean="nodes3"/>
            <ref bean="nodes4"/>
            <ref bean="nodes5"/>
            <ref bean="nodes6"/>
        </set>
    </constructor-arg>
    <constructor-arg name="connectionTimeout" value="300"/>
    <constructor-arg name="soTimeout" value="300"/>
    <constructor-arg name="maxAttempts" value="10"/>
    <constructor-arg name="password" value="123456"/>
    <constructor-arg name="poolConfig" ref="genericObjectPoolConfig"></constructor-arg>
</bean>

<!-- 连接池配置,这个bean是下面jedisCluster的一个属性 -->
<bean id="genericObjectPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="${redis.maxActive}"/>
    <property name="maxIdle" value="${redis.maxIdle}"/>
    <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
    <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
</bean>

<!-- 集群配置,使用构造方法注入的方式(其他方式略) -->
<bean id="nodes1" class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="127.0.0.1"/>
    <constructor-arg name="port" value="7001"/>
</bean>
<bean id="nodes2" class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="127.0.0.1"/>
    <constructor-arg name="port" value="7002"/>
</bean>
<bean id="nodes3" class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="127.0.0.1"/>
    <constructor-arg name="port" value="7003"/>
</bean>
<bean id="nodes4" class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="127.0.0.1"/>
    <constructor-arg name="port" value="7004"/>
</bean>
<bean id="nodes5" class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="127.0.0.1"/>
    <constructor-arg name="port" value="7005"/>
</bean>
<bean id="nodes6" class="redis.clients.jedis.HostAndPort">
    <constructor-arg name="host" value="127.0.0.1"/>
    <constructor-arg name="port" value="7006"/>
</bean>

4.Service自动注入RedisService使用

package ink.nzh.infinite.common.redis.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * spring redis 工具类
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2022/1/19 19:52
 */
@Component
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public class RedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key   缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param timeout  时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @param unit    时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 获取有效时间
     *
     * @param key Redis键
     * @return 有效时间
     */
    public long getExpire(final String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 判断 key是否存在
     *
     * @param key 键
     * @return true存在 false不存在
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

    /**
     * 删除单个对象
     *
     * @param key
     */
    public boolean deleteObject(final String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     */
    public long deleteObject(final Collection collection) {
        return redisTemplate.delete(collection);
    }

    /**
     * 缓存List数据
     *
     * @param key      缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final String key, final List<T> dataList) {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }

    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(final String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * 缓存Set
     *
     * @param key     缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        for (T t : dataSet) {
            setOperation.add(t);
        }
        return setOperation;
    }

    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 删除缓存Map
     */
    public <T> void deleteMap(final String key, final String hashKey) {
        redisTemplate.opsForHash().delete(key, hashKey);
    }

    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }

    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    public Long getCacheMapSize(final String key) {
        return redisTemplate.opsForHash().size(key);
    }


    /**
     * 往Hash中存入数据
     *
     * @param key   Redis键
     * @param hKey  Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        redisTemplate.opsForHash().put(key, hKey, value);
    }

    /**
     * 获取Hash中的数据
     *
     * @param key  Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final String key, final String hKey) {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }

    /**
     * 获取多个Hash中的数据
     *
     * @param key   Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final String pattern) {
        return redisTemplate.keys(pattern);
    }
}

Spring Boot使用Redis集群

redis cluster集群在以下情况下判断集群宕机:
a.当超过半数的主节点宕机
b.某个主节点和下面的从节点全部宕机

spring.redis.database=0
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.timeout=10000
spring.redis.cluster.nodes=127.0.0.1:8001,127.0.0.1:8002,127.0.0.1:8003,127.0.0.1:8004, 127.0.0.1:8005, 127.0.0.1:8006

Service自动注入RedisService使用

package ink.nzh.infinite.common.redis.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * spring redis 工具类
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2022/1/19 19:52
 */
@Component
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public class RedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key   缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param timeout  时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @param unit    时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 获取有效时间
     *
     * @param key Redis键
     * @return 有效时间
     */
    public long getExpire(final String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 判断 key是否存在
     *
     * @param key 键
     * @return true存在 false不存在
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

    /**
     * 删除单个对象
     *
     * @param key
     */
    public boolean deleteObject(final String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     */
    public long deleteObject(final Collection collection) {
        return redisTemplate.delete(collection);
    }

    /**
     * 缓存List数据
     *
     * @param key      缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final String key, final List<T> dataList) {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }

    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(final String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * 缓存Set
     *
     * @param key     缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        for (T t : dataSet) {
            setOperation.add(t);
        }
        return setOperation;
    }

    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 删除缓存Map
     */
    public <T> void deleteMap(final String key, final String hashKey) {
        redisTemplate.opsForHash().delete(key, hashKey);
    }

    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }

    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    public Long getCacheMapSize(final String key) {
        return redisTemplate.opsForHash().size(key);
    }


    /**
     * 往Hash中存入数据
     *
     * @param key   Redis键
     * @param hKey  Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        redisTemplate.opsForHash().put(key, hKey, value);
    }

    /**
     * 获取Hash中的数据
     *
     * @param key  Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final String key, final String hKey) {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }

    /**
     * 获取多个Hash中的数据
     *
     * @param key   Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final String pattern) {
        return redisTemplate.keys(pattern);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值