1.背景
线上部署的应用,偶尔会出现,数据读取出来为空的情况,但是通过打印日志,发现数据确实是存在的。
日志文件:
对应代码:
2.系统架构梳理
tagId2NameMap 是通过一个定时任务去更新的,即:updateTagIdMapping 函数,
本来 tagId2NameMap 是HashMap
3.问题定位排查
(1)以为是不安全的原因导致的,改为ConcurrentHashMap,改为ConcurrentHashMap,还是会出现一样的问题
(2)增加日志,发现是在发生updateTagIdMapping 更新时间和 getTagName 函数时间非常接近的时候,在几毫秒的差异时候,会出现上述问题。
怀疑是tagId2NameMap 在clear 之后,数据还没有完全addAll进去。
4.解决思路
解决方案一:
通过加锁的方式来进行处理,上述业务场景,非常明显,适合读写锁,读的QPS 是较高的,而写的QPS非常低,是通过定时任务来定时进行配置。
private final ReentrantReadWriteLock updateLock = new ReentrantReadWriteLock();
在更新的地方加写锁
在读取的地方加读锁
最终没有出现上述问题。
解决方案二:
用将数据添加到tmp 临时变量中,再进行赋值替换
问题定位难点:本地较难复现,刚好更新时间和读取时间一致。本地很难出现和线上一样的QPS,线上流量高峰期QPS有接近6000
读写锁原理和使用参考: