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 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
小羊没烦恼!2 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
俊昭喜喜里2 天前
java中的继承和多态的区别
java
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
譕痕2 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码2 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖2 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时2 天前
01-06-A-JVM排查实战详解
java·jvm