环境:虚拟机3主3从

1、关闭slave是对读写都没有影响的

2、关键就是关闭master,读写都会失败

虽说可以设置lettuce的拓扑自动更新,但是redis的slave变成master是需要时间的
在这段时间内的读写都无法进行,异常-->【connection refused】
等到slave变成了master,读写才会恢复,但是依然会报警告,无法连接到xxx,哎...

找了半天发现有个方法可以避免读的失败,就是优先从slave读
    StatefulRedisClusterConnection对象之
    setReadFrom(ReadFrom.REPLICA_PREFERRED);
通过测试发现只有REPLICA_PREFERRED有效,其他无效
这个选项意思是优先从副本读取,master宕机或者slave宕机都不会对读造成任何影响
NICE啊。。。

3、使用lettuce操作cluster

|--工具类

/*** lettuce获取cluster连接*/
public class ClusterUtil {private static final List<RedisURI> redisURIList = new ArrayList<>();private static final String address ="192.168.8.131:6379," +"192.168.8.129:6379," +"192.168.8.130:6379," +"192.168.8.132:6379," +"192.168.8.134:6379," +"192.168.8.133:6379";private static final String auth = "******";private static RedisClusterClient client;private static ThreadLocal<StatefulRedisClusterConnection> box = new ThreadLocal<>();static {for (String x : address.split(",")) {StringBuilder sb = new StringBuilder();sb.append("redis://").append(auth).append("@").append(x);redisURIList.add(RedisURI.create(sb.toString()));}client = RedisClusterClient.create(redisURIList);//拓扑更新设置ClusterTopologyRefreshOptions.Builder topoBuilder = ClusterTopologyRefreshOptions.builder();topoBuilder.enableAllAdaptiveRefreshTriggers();topoBuilder.enablePeriodicRefresh(true);topoBuilder.dynamicRefreshSources(true);topoBuilder.closeStaleConnections(true);//client选项设置ClusterClientOptions.Builder clientOptionsBuilder = ClusterClientOptions.builder();clientOptionsBuilder.maxRedirects(5);clientOptionsBuilder.topologyRefreshOptions(topoBuilder.build());client.setOptions(clientOptionsBuilder.build());}//获取一个连接public static StatefulRedisClusterConnection getConnection() {if (box.get() == null) {StatefulRedisClusterConnection<String, String> connect = client.connect();//关键操作:优先从副本读取connect.setReadFrom(ReadFrom.REPLICA_PREFERRED);box.set(connect);}return box.get();}//关闭连接public static void close() {if (box.get() == null) return;StatefulRedisClusterConnection connect = box.get();connect.close();box.remove();}
}

|--操作类

/*** redis集群  添加与获取KEY*/
public class ClusterService {//添加public String set(String key, String value) {String result = null;try {StatefulRedisClusterConnection connection = ClusterUtil.getConnection();RedisAdvancedClusterCommands commands = connection.sync();result = commands.set(key, value);} catch (Exception e) {if (io.lettuce.core.RedisException.class == e.getClass()) {//master挂了}}finally {ClusterUtil.close();return result;}}//获取public String get(String key) {String value = null;try {StatefulRedisClusterConnection connection = ClusterUtil.getConnection();RedisAdvancedClusterCommands commands = connection.sync();value = (String) commands.get(key);} catch (Exception e) {if (io.lettuce.core.RedisException.class == e.getClass()) {//who knows}} finally {ClusterUtil.close();return value;}}
}

虽说lettuce这个【先从副本读】很牛逼,但是项目里也要与spring整合才行对么
不跟spring搞一起的框架不是好框架,况且spring可以方便的进行序列化

4、使用spring-data-redis操作cluster

|--配置类

@Configuration
@PropertySource(value = {"classpath:redis/redis.properties"},encoding = "UTF-8")
public class RedisConfig {@Beanpublic RedisClusterConfiguration getRedisClusterConfiguration(@Value("${redis.cluster.nodes}") String nodes,@Value("${redis.cluster.max-redirect}") int maxRedirect,@Value("${redis.cluster.auth}") String password){RedisClusterConfiguration redisConfiguration = new RedisClusterConfiguration();Set<RedisNode> redisNodes = new HashSet<>();for(String s : nodes.split(",")){if(s == null || s.equals("")) continue;String ip = s.split(":")[0];int port = Integer.parseInt(s.split(":")[1]);redisNodes.add(new RedisNode(ip,port));}redisConfiguration.setClusterNodes(redisNodes);redisConfiguration.setMaxRedirects(maxRedirect);redisConfiguration.setPassword(password);return redisConfiguration;}@Beanpublic GenericObjectPoolConfig getGenericObjectPoolConfig(@Value("${redis.pool.minIdle}") int minIdle,@Value("${redis.pool.maxIdle}") int maxIdle,@Value("${redis.pool.maxTotal}") int maxTotal,@Value("${redis.pool.maxWaitMills}") long maxWaitMillis,@Value("${redis.pool.testOnBorrow}") boolean testOnBorrow){GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();genericObjectPoolConfig.setMinIdle(minIdle);genericObjectPoolConfig.setMaxIdle(maxIdle);genericObjectPoolConfig.setMaxTotal(maxTotal);genericObjectPoolConfig.setMaxWaitMillis(maxWaitMillis);genericObjectPoolConfig.setTestOnBorrow(testOnBorrow);return genericObjectPoolConfig;}@Beanpublic LettucePoolingClientConfiguration getLettucePoolingClientConfiguration(@Autowired GenericObjectPoolConfig poolConfig){LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder configurationBuilder = LettucePoolingClientConfiguration.builder();configurationBuilder.poolConfig(poolConfig);//拓扑更新设置ClusterTopologyRefreshOptions.Builder topoBuilder = ClusterTopologyRefreshOptions.builder();topoBuilder.enableAllAdaptiveRefreshTriggers();topoBuilder.enablePeriodicRefresh(true);topoBuilder.dynamicRefreshSources(true);topoBuilder.closeStaleConnections(true);//client选项设置ClusterClientOptions.Builder clientOptionsBuilder = ClusterClientOptions.builder();clientOptionsBuilder.autoReconnect(false);clientOptionsBuilder.topologyRefreshOptions(topoBuilder.build());configurationBuilder.clientOptions(clientOptionsBuilder.build());return configurationBuilder.build();}@Beanpublic LettuceConnectionFactory getLettuceConnectionFactory(@Autowired RedisClusterConfiguration redisClusterConfiguration,@Autowired LettucePoolingClientConfiguration lettucePoolingClientConfiguration){return new LettuceConnectionFactory(redisClusterConfiguration,lettucePoolingClientConfiguration);}/*** JSON序列化  同步模式* @param redisConnectionFactory* @return*/@Bean(name = "jsonSyncRedisTemplate")public RedisTemplate<String,Object> getJsonSyncRedisTemplate(@Autowired RedisConnectionFactory redisConnectionFactory){RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);redisTemplate.setEnableTransactionSupport(true);redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setValueSerializer(RedisSerializer.json());redisTemplate.setHashKeySerializer(RedisSerializer.string());redisTemplate.setHashValueSerializer(RedisSerializer.json());return redisTemplate;}/*** JSON序列化  异步模式* @param redisConnectionFactory* @return*/@Bean(name = "jsonAsyncRedisTemplate")public RedisTemplate<String,Object> getJsonAsyncRedisTemplate(@Autowired RedisConnectionFactory redisConnectionFactory){RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setValueSerializer(RedisSerializer.json());redisTemplate.setHashKeySerializer(RedisSerializer.string());redisTemplate.setHashValueSerializer(RedisSerializer.json());return redisTemplate;}
}

|--操作类

@Service
public class ClusterService {@Autowired@Qualifier("jsonAsyncRedisTemplate")private RedisTemplate jsonAsyncRedisTemplate;//添加public void set(String key, Object value) {try {jsonAsyncRedisTemplate.opsForValue().set(key, value);} catch (Exception e) {//who knows}}//获取public Object get(String key) {Object value = null;try {value = jsonAsyncRedisTemplate.opsForValue().get(key);} catch (Exception e) {//who knows} finally {return value;}}
}

坑1)发现关闭master后,spring-data-redis一直在重连,导致方法阻塞
    slave变成了master依然阻塞
    把原来的master启动后还是阻塞
    设置拓扑刷新间隔为1秒还是阻塞
    心累。。。只好设置clientOptionsBuilder.autoReconnect(false);
    终于OK了,但是读写失败无法避免

坑2)想着lettuce的【先从副本读】能否在spring配置类里面也怼一个呢?
    看了半天,不行。。。只能配置LettucePoolingClientConfiguration里面的东西
    但是从副本读需要配置connection对象
    这个connection是springTemplate自己调用方法的时候,用connectionFactory生成的,咱们拿不到它
    算了。。。破罐破摔呗
    master挂掉,读写都会失败,只能捕获异常,自定义处理。
    或者把这些失败的记录怼到一个消息队列中?

3)开始测试
    100个线程,每个线程200ms进行一次读写,连续读写100次
    于是总共10000次读和10000次写,master挂掉后读写失败率差不多13%
    虚拟机性能差,用云服务器大概0.00000013%

使用lettuce和redisTemplate操作redis cluster踩坑日记相关推荐

  1. Lettuce替换Jedis操作Redis缓存

    Redis介绍及Mencached对比 Redis全称是远程字典服务,是一个Key-Value的存储系统,相比于很早之前一直使用的mencached,不单单提供了更多的类型支持. 数据类型上:menc ...

  2. springboot中使用RedisTemplate操作redis遇到的问题

    首先说说问题, 在springboot中使用RedisTemplate操作redis时候,通过redis工具发现存入redis的数据的键为空 ,如下图: 点击空的键,弹出错误提示:不能打开值的标签,不 ...

  3. RedisTemplate操作redis时,key值出现\xac\xed\x00\x05t\x00前缀

    现象: 使用redistemplate操作redis,随后在客户端keys * 查询,发现key值多了前缀,但是不影响程序读写 经查阅资料,是RedisTemplate默认序列化方式用的是JdkSer ...

  4. Python脚本之操作Redis Cluster

    本文为博主原创,未经授权,严禁转载及使用. 本文链接:https://blog.csdn.net/zyooooxie/article/details/123760358 之前曾经分享过2篇 关于Red ...

  5. 原生Javascript 操作 css类名 - 踩坑篇

    文章目录 原生Javascript 操作 css类名 效果图示下: 案例 · 代码如下: 重要代码提示: 其他无关参考: 官方参考: 原生Javascript 操作 css类名 不建议用 .class ...

  6. c++字符串操作之std::ostringstream踩坑日记

    c++字符串操作之std::ostringstream踩坑日记 在开发过程中经常会遇到字符串操作,而std::string又没有format操作,这就很难受了. 于是我找到了std::ostrings ...

  7. Win11 + Ubuntu18.04 双系统踩坑日记

    Win11 + Ubuntu18.04 双系统踩坑日记 前言 准备工作 硬件配置 镜像下载 Win11镜像下载 Ubuntu镜像下载 启动盘准备 Win11启动盘 Ubuntu启动盘 Win11安装 ...

  8. Antd Pro V4 protable详解(ps:踩坑日记)

    Antd Pro V4 protable详解(ps:踩坑日记) 写在前面: 在这篇文章中,你会了解到: protable 中的cloumns属性详解 protable数据加载和处理(两种方法,直接使用 ...

  9. 关于我使用vant组件的踩坑日记

    啦啦啦~~~又是晴朗的一天~今天用vue+vant组件写h5移动端项目需要使用的到一个Actionsheet 弹窗,就是想实现一个这shai的效果: 当我悠哉悠哉的翻阅文档,哎~找到了我想要的 然后我 ...

  10. 全志哪吒D1-H Tina Linux Ubuntu 22.04入门踩坑日记

    哪吒D1-H Tina Linux入门踩坑日记 系统环境 源码编译 mklibs-readelf的C++标准问题 m4的SIGSTKSZ问题 libfakeroot的_STAT_VER问题 read_ ...

最新文章

  1. 关于matlab中的梯度使用
  2. 【转】闲聊Kernel engineer的境界(全)
  3. MySQL高级 - 锁 - MySQL对锁的支持
  4. 计算机基础知识学前自测,2011计算机二级C语言学前自测题:DOS的基本操作
  5. vim选中字符复制/剪切/粘贴
  6. 我最大的乐趣是不厌其烦地收集人生的各种经历和体验。我喜欢享受人生的各种经历和体验所带给我的难以言表的乐趣...
  7. 如何用管程实现生产者消费者问题?
  8. Java经典设计模式 总览
  9. Converter使用及其原理
  10. Ping命令进行网络检测
  11. Java字符串(超超超详细)
  12. 机器学习老中医:利用学习曲线诊断模型的偏差和方差
  13. python矩阵内积乘_numpy矩阵向量乘法
  14. 以太坊 solidity在线实时编译器
  15. Java笔试的各种输入总结
  16. C语言程序设计--19春 形考任务1,南开19春学期(1709、1803、1809、1903)《C语言程序设计》在线作业-1辅导资料.docx...
  17. 零基础学习python数据分析,需要掌握哪些技能?
  18. 阿里:不清除35岁以上的P8员工!
  19. 如何在不停机的情况下在Django中创建索引
  20. NSSCTF刷题wp——常用编码

热门文章

  1. java 目录遍历漏洞_路径遍历 漏洞修复
  2. 第一周总结 汉得日记
  3. 在Flutter中创建有意思的滚动效果 - Sliver系列
  4. mysql delete in死锁_delete where in导致的死锁问题
  5. 陆面生态水文模拟与多源遥感数据同化与Noah-MP模型
  6. vue项目中通过cdn引入资源并配置
  7. 什么样的企业要使用360评估?
  8. DLang 编译实验
  9. 数字孪生|成熟度评价
  10. Monero GUI Wallet发送交易源码分析