This commit is contained in:
chenyan 2023-01-08 19:08:24 +08:00
parent 97ff76f97f
commit 9f31a3f918
2 changed files with 6 additions and 6 deletions

View File

@ -137,7 +137,7 @@ ORM 框架是动不了了,在用的低版本的没法处理这个问题, 又
已经是相对较优的实现了再追求更强的一致性就得去权衡代价和收益了。最终这个bug是被切了无法复现手动清下缓存改小了缓存有效期 就算结了。
咱们从理论上猜一下可能有哪些场景会导致数据不一致。
咱们从理论上猜一下可能有哪些场景会导致数据不一致(先认为所有的远程调用都是可靠的)
1. 数据库主从延迟。写接口更新了主库,删除了缓存。读接口从从库里取出来的还是旧数据,并把旧数据又放进了缓存。
2. 读接口 发现缓存里没数据, 走到数据库里去取,取完卡了一下,还没来得及放进缓存。写接口 更新完数据,删完缓存。读接口 从卡住的状态恢复过来,把旧数据放进了缓存。
@ -152,11 +152,11 @@ ORM 框架是动不了了,在用的低版本的没法处理这个问题, 又
所以就只好增加信息量,
1. 写接口可以多说点假设数据中有version字段表示数据的版本。写接口 数据更新时删除缓存的主体内容但保留最新的version值。读接口就能根据版本号判断要放进缓存的是不是旧数据。
2. (读接口,也要有主观能动性)。时不时的抽查下数据质量,不能说缓存里有数据就 100% 认为是合格的数据。那检查抽取样本的标准呢...比如,可以按时间,越新的缓存越不可信。还可以做个本地计数器,按频率或次数,阈值到了就去数据库里取新的。
1. 写接口可以一次多说点。假设数据中有version字段表示数据的版本。写接口 数据更新时删除缓存的主体内容但保留最新的version值。读接口就能根据版本号判断要放进缓存的是不是旧数据。这又引入了一个新的要注意的问题多说多错远程调用真的可靠吗要保证缓存中的version字段和数据库中的一致, 又要进一步考虑增加两步提交的逻辑,代价太大了。完全删除的动作,不止是传递了数据更新的信息,在缓存的场景下还具有强大的容错力。)
2. 写接口,可以多说几次。延迟一会儿再删一次缓存。从技术上虽然不解决根本问题,但从业务功能效果上可太香了。
3. 读接口,也要有主观能动性。时不时的抽查下数据质量,不能说缓存里有数据就 100% 认为是合格的数据。那检查抽取样本的标准呢...
## 穿透

View File

@ -39,7 +39,7 @@ tags: [jvm, lock]
总结一下,做个名词解析。我们把实现一把锁,拆成了两个部分。“锁的执行流程” 和 “蛋的问题”。
“锁的执行流程” 的不同,对应的是文章第一段占茅坑中提到的 “占坑花样” 的不同, 也对应第三段中用 C++/Java 实现的 “主要逻辑” 的不同。
“锁的执行流程” 的不同,对应的是文章第一段占茅坑中提到的 “占坑花样” 的不同。
“蛋的问题” 如何解决,可以寻求他人的帮助。比如 操作系统内核就提供了一些系统调用。比如 cpu 支持 `cmpxchg` 指令来比较并交换数据,多核的时候这个指令前面还可以加个 `lock`。再比如 redis 的 setNx() 命令。
@ -248,7 +248,7 @@ AtomicInteger 就强依赖 cpu 指令提供的 CAS 操作。核心代码长这
--
第一个线程来申请锁的时候,查看 markWord 状态是空白的。使用一次 CAS 操作,把自己的线程标识填入 markWord。之后自己再来申请锁看到 markWord 状态没变,就无须任何同步操作了。
第一个线程来申请锁的时候,查看 markWord 状态是空白的。使用一次 CAS 操作,把自己的线程标识填入 markWord。之后自己再来申请锁看到 markWord 状态没变,就无须任何同步操作了。这种情况,就可以用 偏向 来形容。
第二个线程来的时候,查看 markWord 状态显示已经有人占用,就开始把锁升级成轻量级锁了,就是乐观锁,就是自旋锁。