内容简介:注册中心 Eureka 源码解析 —— Eureka源码解析 —— 应用实例注册发现 (九)之岁月是把萌萌的读写锁
摘要: 原创出处 http://www.iocoder.cn/Eureka/instance-registry-read-write-lock/ 「芋道源码」欢迎转载,保留摘要,谢谢!
关注 微信公众号:【芋道源码】 有福利:
- RocketMQ / MyCAT / Sharding-JDBC 所有 源码分析文章列表
- RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
- 您对于源码的疑问每条留言 都 将得到 认真 回复。 甚至不知道如何读源码也可以请教噢 。
- 新的 源码解析文章 实时 收到通知。 每周更新一篇左右 。
- 认真的 源码交流微信群。
1. 概述
本文主要分享 Eureka 注册中心的那把读写锁 ,让我瘙痒难耐,却不得其解。在某次意外的抠脚的一刻( 笔者不抽烟,如果抽烟的话,此处应该就不是抠脚了 ),突然顿悟,爽,这好比… 比喻有点猥琐,笔者就省略 100 字。
不瞎比比,上代码:
public abstract class AbstractInstanceRegistry implements InstanceRegistry{ private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final Lock read = readWriteLock.readLock(); private final Lock write = readWriteLock.writeLock(); // ... 省略其他代码 }
推荐 Spring Cloud 书籍:
- 请支持正版。下载盗版, 等于主动编写低级 BUG 。
- 程序猿DD —— 《Spring Cloud微服务实战》
- 周立 —— 《Spring Cloud与 Docker 微服务架构实战》
- 两书齐买,京东包邮。
2. 读写锁
我们把设计到读写锁的方法整理如下:
方法 | 读锁 | 写锁 | 不使用 |
---|---|---|---|
#register(...) |
√ | ||
#cancel(...) |
√ | ||
#evict(...) |
√ | ||
#renew(...) |
√ | ||
#statusUpdate(...) |
√ | ||
#deleteStatusOverride(...) |
√ | ||
#getApplicationDeltasFromMultipleRegions(...) |
√ | ||
#getApplicationsFromMultipleRegions(...) |
√ |
是否看到这读写感到几丝诡异的味道?OK,我们把问题梳理如下:
- A. 为什么
#register(...)
/#cancel(...)
/#evict(...)
/#statusUpdate(...)
/#deleteStatusOverride(...)
等 写操作 使用 读锁 - B. 为什么
#renew(...)
写操作 不使用 锁 - C. 为什么
#getApplicationDeltasFromMultipleRegions(...)
读操作 使用 写锁 - D. 为什么
getApplicationsFromMultipleRegions(...)
读操作 不使用 锁
先解释 A + C :
我们来回想下,在 Eureka 应用集合一致性哈希码的公式: appsHashCode = ${status}_${count}_
。( 不了解的同学可以加载下 《Eureka 源码解析 —— 应用实例注册发现(七)之增量获取》「 2. 应用集合一致性哈希码 」 )
#renew(...)
方法 )方法的调用都会影响哈希码。
我们把目光移向唯一使用 写锁 的 #getApplicationDeltasFromMultipleRegions(...)
方法,该方法执行过程中,需要保证 recentlyChangedQueue
和 registry
共享变量的 应用实例的状态一致 ,不然返回的增量应用实例集合的状态是不准确的。此时能够达到该效果,必须让 #getApplicationDeltasFromMultipleRegions(...)
和前六个方法 互斥 。方案如下:
- a. 全部
synchronized
- b.
#getApplicationDeltasFromMultipleRegions(...)
使用 读锁 ,前六个方法使用 写锁 - c.
#getApplicationDeltasFromMultipleRegions(...)
使用 写锁 ,前六个方法使用 读锁
Eureka 选择了 方案c ,原因如下:
- a. 性能太差
- b. 前六个方法使用 写锁 ,势必冲突太大,虽然读肯定比写多。
- c.
#getApplicationDeltasFromMultipleRegions(...)
使用 写锁 ,配合 ResponseCache ,即减少了 写锁 使用的频率,每次缓存过期才使用,又避免了前六个方法因为 方案b 中的 写锁 导致互斥。( 不了解 ResponseCache 的同学可以加载下 《Eureka 源码解析 —— 应用实例注册发现(六)之全量获取》「 3.2 响应缓存 ResponseCache 」 )
再解释 D
#getApplicationsFromMultipleRegions(...)
方法的逻辑,只依赖 registry
共享变量,不存在应用实例的状态一致的困扰,所以不使用锁。
最后解释 B
#renew(...)
方法的逻辑,虽然会影响应用实例的状态,但是是极小概率,考虑到它调用的比较频繁,比起因为锁给这个方法带来的性能降低,不如返回的结果暂时不够准确。( 想了解极小概率发生原因的同学可以加载 《Eureka 源码解析 —— 应用实例注册发现(八)之覆盖状态》「 4.3 续租场景 」 )
TODO [0029] 读写锁
笔者路上突然又想了问题,可能不是上述原因,可能和 ResponseCache 有关系,参见 #invalidateCache(...)
方法的每次调用。也就是说,这个读写锁是针对 ResponseCache 的读写锁。
666. 彩蛋
开森 !
本来以为需要跟 Eureka 官方提交 issue 提问,并且做好了获得不到答案的准备,结果无意中的抠脚( 请允许我热爱抠脚给我带来的灵感 )解答了自己的疑惑。
岁月是把纠结而又萌萌哒的锁,你不知道你的困扰,哪天不经意的被打开。
愿大喜大悲,不枉仅知的这一生。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- ReactNative源码解析-初识源码
- Spring源码系列:BeanDefinition源码解析
- Spring源码分析:AOP源码解析(下篇)
- Spring源码分析:AOP源码解析(上篇)
- 注册中心 Eureka 源码解析 —— EndPoint 与 解析器
- 新一代Json解析库Moshi源码解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。