登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
广播
Follow
关于
导读
排行榜
发帖说明
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
写记录
写博客
小组
VIP申请
VIP网盘
网盘
联系我们
发帖说明
道具
勋章
任务
淘帖
动态
分享
留言板
导读
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
安全
›
线上遇到的redis和数据库数据未同步问题、redisson内部 ...
线上遇到的redis和数据库数据未同步问题、redisson内部实现问题
[ 复制链接 ]
柏雅云
7 天前
程序园永久vip申请,500美金$,无限下载程序园所有程序/软件/数据/等
背景
从离职同事手里接了一堆系统,其中一个系统,是对app提供服务的,虽说名义上这是一个系统,实际上,里面包含了五六个微服务,这其中有一个微服务,主要负责用户设备的上报和安全提醒,我们就叫设备管理服务:
1、老手机abc首次登录
如果用户首次用这个app,直接把当前这个设备(abc)设置为已信任设备,后台有个表device,会记录:
用户名设备id是否已被用户信任(trust)安全提醒消息id张三abc是null而且由于引入了redis缓存来存储信任设备列表,所以会同步设置缓存(如果没有缓存key存在,就会从数据库中查询并设置缓存):
key:用户名
value类型:redis set
value:[abc]
2、换新手机def后登录
等到用户换新手机(设备id:def)的时候,这次上报上来后,发现222这个设备不在用户已信任设备id的集合中(select 设备id from devie where trust = true),理论上,就需要触发一次安全提醒消息,消息是发给老设备abc.
总的来说,就是,当前这个设备管理服务,会去调用消息微服务,得到消息id后,会在数据库中,加一条记录,如下的第二条(未被用户信任,且发送了安全提醒消息)
用户名设备id是否已被用户信任(trust)安全提醒消息id张三abc是null张三def否1同时呢,消息服务那边,会记录一条消息:
消息id用户名可拉取该消息的设备id列表消息是否被拉取1张三abcfalse
3、老手机abc登录
老手机此时如果去登录,就会从消息服务拉取到上述的安全提醒消息,此时消息表的拉取状态变成true:
消息id用户名可拉取该消息的设备id列表消息是否被拉取1张三abctrue并发mq通知设备管理服务。设备管理服务这边,就会修改设备表,将设备def改成:已被用户信任。
用户名设备id是否已被用户信任(trust)安全提醒消息id张三abc是null张三def是1在这个步骤中,由于新增了用户信任设备,会将缓存过期,过期时间是1秒后。
4、新手机def再次登录
由于此时,def在数据库中,trust标志为true:已被用户信任,所以就不会再触发安全提醒的消息了。
线上问题
然而,接过来也没多久,产品就说线上有问题(好像没接手之前也有吧,忘了),偶尔会存在乱发短信的问题(就是不该发但发了),比如明明是用户自己的设备,但也会提醒你:你的账号在1台或者某几台(这里是占位符,设备型号,如iphone/小米/华为等)上登录,请注意安全,必要时联系客服或报警。
由于这个app和钱相关,而且是大量的钱,所以真就有不少用户去报警了。有的客户可能感觉是程序bug,但和钱相关后,就谨慎了,至少报警留个痕,对吧,免得后续扯皮时吃亏。
这些线上问题出了之后,我当前也是才接了这个系统没多久,出于一些原因和工作优先级的问题,也没花特别多时间来处理这个,产品说这个功能有开关,只能就是把这个安全提醒的功能给关闭了先。
等后续高优先级工作完成后,还是抽空看了下这块。
代码存在的一些问题
其实,大家看上面这个逻辑,是不是也不算复杂,如果纯粹的数据库操作的话,逻辑还是蛮简单;但我接手后,从代码和部分文档,来梳理出上述的逻辑,费了不少事。1个就是,代码里引入了缓存redis,来存储:已被用户信任的设备id集合,key是用户名,value就是redis的set类型,元素类型就是字符串,比如,最开始老手机登录,存的就是abc,等到上面的第三步后(老手机拉取了消息后),缓存里存的就应该是abc和def。
另外呢,引入了mq机制,说实话,mq也就是个用,我看也没有相关的确保消息不丢失的代码,不过这都还好,本次的问题也不是mq的问题。
再一个问题就是,这个设备id号,其实是app来生成的,但它也是可能变化的,同一台手机上,我如果把app完全卸载重装,设备id就会发生变化。其实后来讨论过,为啥不使用手机的硬件相关数据,如:IMEI;app同事好像是说,现在权限管得很严,不让获取IMEI字段,具体我也不清楚。
还有个麻烦的问题,用户app端是可以看到所有这些设备的,就是能查询如下表的记录,而且可以改,可以删:
用户名设备id是否已被用户信任(trust)安全提醒消息id张三abc是null可以删,还是他么的物理删除。
当时查问题的时候,一方面代码难看,没啥注释,代码也是面条式代码,再加上数据库里记录被物理删除,真的只能各种翻日志了,日志可能还是横跨好多天的。我这里也给大家放一下这个设备上报接口的逻辑图:
问题处理
思路
首先,这个问题不是必现的,是偶现。我在本地也没复现出来。
所以,我当时的思路是比较暴力的:
1、数据库物理删除改成逻辑删除;
2、代码简单重构,增加日志,规范变量命名,抽取函数等等;
3、讨论是否直接去掉redis缓存。
第三点,由于涉及架构变动,产品和测试认为动作有点大了,就先只改了前两点。
测试
测试时,没想到测试得同事偶然复现了这个问题,由于这次增加的日志多了不少,几乎就确认了,是缓存和数据库存在不同步的问题。
是这样的,前面背景中说到的,第三步是:老手机去拉取安全提醒的消息,然后此时,消息服务会调用设备管理服务,提示消息被消费了,可以将设备def改成常用了。我们从测试时的日志发现,数据库确实是改了。
用户名设备id是否已被用户信任(trust)安全提醒消息id张三abc是null张三def是1然后,缓存操作这块呢,代码是这样的:
然后,后续这个用户的新设备def再登录的话,按理来说,就会发现缓存过期了,就会从数据库中加载:
如果真是走了这段数据库加载的逻辑,基本可以说,上面那行日志是一定会打印的,但是,很遗憾啊,没打这行日志,看来,程序是发现从缓存中取到的set不为空。
但是,这怎么会呢,我第三步设置缓存1s后过期;后续def上报时,都过了好几十秒了,不可能缓存还在吧?
那就是这几十秒中间,出了什么事吧。
然后在这几十秒中间的日志里面找,发现:在第三步设置缓存1s过期后,马上几十毫秒内,又有一个该用户的设备上报请求(测试同事手里手机比较多,有4部,这一步我们命名为设备h吧),此时,那个本应该1s后过期的缓存,此时还存在于redis中。
设备h上报时,触发下面的代码:
我们进去看看:
上述这个红框代码,将缓存过期时间又给延长了啊。。。导致本应该1s后过期的缓存(内容:abc),生命周期又变得很长很长,此时,数据库中的已信任设备为:abc、def,而缓存中则是abc,这就产生了不一致。
问题根源
根源就是代码写得有问题。你改了数据库中def为常用设备了,缓存直接删除了不就行了,为啥要1s后过期呢,这不就1s内就是不一致的吗,直接删了也就不存在这个问题了。
尤其是,这个获取缓存的动作,还包含了设置过期时间的功能:
另外,由于这里混用了两个redis框架(spring redisTemplate和redisson),我一开始还怀疑偏了,以为是redisson内部有缓存之类的问题。
所以,对于一般的应用来说,不是严格要求数据库和缓存要一致的那种,一般:先修改数据库,再把缓存key删了,就够用了;对于互联网大厂那种,这种可能还是不够用,就会用什么binlog同步啥的,我就不操心那么多了,大家自己搜索吧。
redisson的问题
判空
在debug的时候,发现redisson原来是这样的。
就比如,我们上述的程序中,获取key:
RSet<String> ret = redissonClient.getSet(keyPrefix.prefix() + key);
复制代码
其中,Rset是redisson中的类型:
当我们在判断rset是否为空时(org.apache.commons.collections4.CollectionUtils#isEmpty):
最终,就会触发一个对redis的SCARD命令,也就是执行scard,获取集合中元素的数量:
contains
我们代码中还包括contains:
这个是触发如下命令:
获取集合中元素
我们还有如下代码:
这个触发的是:
相关抓包截图
总结
引入缓存,是为了解决问题,但是,如果不注意的话,就会发生:缓存数据库不同步问题;
引入redisson,是为了避免频繁操作数据库,但是,不了解内部的话,就会发现,简单的几个方法调用,就触发了一堆的网络调用,这是否真的高性能了呢?
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
问题
线上
遇到
redis
数据库
相关帖子
Oracle数据库物理备份与恢复实战指南
时序数据库 IoTDB 集成 SpringBoot Starter,实现时序数据库“零配置”接入
MySQL数据库全方位优化指南:从硬件到架构的深度调优
Milvus向量数据库:高性能、多特性,助力AI应用开发新潮流!
Oracle 19c数据库升级PSU版本及Patch安装操作指南
命令行创建与删除Oracle数据库:全流程实战指南
STM32F103ZET6开发板串口只发不收问题解决
工业智能时序数据库 IoTDB 荣获 2025 苏州・常熟全国创新创业大赛总决赛二等奖
一文了解时序数据库 IoTDB 分区、同步与备份
Obsidian的Bases数据库入门教程,使用数据库实现Todo待办管理系统
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
相关推荐
业界
Oracle数据库物理备份与恢复实战指南
0
146
纪晴丽
2025-11-25
安全
时序数据库 IoTDB 集成 SpringBoot Starter,实现时序数据库“零配置”接入
0
826
恙髡
2025-11-26
业界
MySQL数据库全方位优化指南:从硬件到架构的深度调优
2
983
姬宜欣
2025-11-26
安全
Milvus向量数据库:高性能、多特性,助力AI应用开发新潮流!
0
323
跑两獗
2025-11-29
业界
Oracle 19c数据库升级PSU版本及Patch安装操作指南
0
503
柏球侠
2025-11-30
业界
命令行创建与删除Oracle数据库:全流程实战指南
0
694
薛小春
2025-12-01
安全
STM32F103ZET6开发板串口只发不收问题解决
0
420
辜酗徇
2025-12-03
安全
工业智能时序数据库 IoTDB 荣获 2025 苏州・常熟全国创新创业大赛总决赛二等奖
0
698
兜蛇
2025-12-03
安全
一文了解时序数据库 IoTDB 分区、同步与备份
1
844
郏琼芳
2025-12-03
业界
Obsidian的Bases数据库入门教程,使用数据库实现Todo待办管理系统
0
384
焦尔蕾
2025-12-06
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
浏览过的版块
业界
签约作者
程序园优秀签约作者
发帖
柏雅云
7 天前
关注
0
粉丝关注
15
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
anyue1937
9994893
kk14977
6845355
3934307807
991122
4
xiangqian
638210
5
宋子
9987
6
闰咄阅
9991
7
刎唇
9993
8
俞瑛瑶
9998
9
蓬森莉
9952
10
匝抽
9986
查看更多