Redis实现简易哨兵模式

故事背景

在一个月黑风高的夜晚,突然收到公司微信群的一条消息,一台生产服务器挂了,里面有部署到redis,让我们查查看服务有没有用到这个redis。经调查发现一个旧的支付服务有用到,接着我们快马加鞭登上服务器看看有没有报错信息,结果发现一切正常,才松了一口气。

后面发现redis挂了之后也没影响业务的原因是因为旧的框架使用了简易哨兵模式:开启一个线程检测redis心跳,如果连接不上就把状态设为不可用,调用redis方法就会直接返回,这样就不会报错或者卡住业务,如果redis连接正常则正常使用。

简易哨兵实现

1.初始化读取配置文件,加载redis配置,里面有一个activeServers和downServers分别代表可用和失效的缓存服务器

checkActive的实现

2.在获取jedis实例的时候会扫描activeServers

3.有一个心跳定时任务会定期检测activeServers是否可用,代码设置了10秒检测一次。

代码重构

由于这是很旧的框架,修改起来很困难,后面打算弃用了,用网上封装的redisCache去实现redis操作,但是网上封装的没有做到这种检测心跳的模式,如果redis服务器挂了,就意味着服务会尝试连接,然后抛出异常变得不可用。由于我们系统的并发不算太高,去掉redis也不会出现缓存穿透打爆数据库的情况,所以我把旧框架的简易哨兵模式搬过来使用,保证redis挂掉也不会影响服务使用。

1、redis工具类添加active状态,启用线程定时检查redis心跳。

springbean初始化方法可以通过构造器实现、@PostConstruct注解、InitializingBean接口、@Bean的initMethod属性,我这里选择用@PostConstruct注解实现线程定时检测redis心跳。

2、写一个切面判断redis的active状态,如果不可用则直接返回

注入失败

在redisCache创建active参数设置为true,然后在其他地方读取active参数的时候发现active无法读取

研究了很久,也问了几个大哥,发现应该是代理类的属性没有注入,需要获取原对象才能正确获取属性。 为什么生成代理类呢,那是因为做了aop增强,如果有做切面,就要通过get方法获取属性。测试了一下生成代理对象是因为有aop切面,或者对象方法里面有@Transactional注解。

要怎么才能正确读取代理对象中的active属性呢?调用get方法,就会走代理方法正确获取属性,直接调用代理对象属性就为空。但是因为我在@Around切面获取get方法会进入死循环,所以需要把active属性改成static全局变量,如果类.static获取即可解决。

AOP的原理可以简单这么认为,代理对象持有被代理对象(因为代理对象的字段并不会被赋值,都是null,所以需要用到被代理对象字段的值),通过在调用被代理对象方法前后做一些事情。

为什么不会赋值? 参考www.zhihu.com/question/37...

总结

1、心跳检测在很多地方都会用到,比如nacos注册中心、服务检测、nginx等。可通过定时发送心跳检测服务是否正常运行,如果检测失败则剔除出集群。

2、spring bean注入也是面试和工作中其中一个考点。对于属性依赖注入需要@Autowired注解修饰,调用类需要用@Component等注解修饰,交给spring管理。因为上面的redisCache是经过切面,生成了代理对象,如果想调用属性只能设置static。

相关推荐
吾日三省吾码2 小时前
JVM 性能调优
java
Estar.Lee2 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
弗拉唐3 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi774 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
2401_857610034 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
少说多做3434 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀4 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20204 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深4 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++