SpringCloud 源码剖析(五)Eureka源码之服务端接收注册信息

简介: SpringCloud 源码剖析(五)Eureka源码之服务端接收注册信息

原来一个 Map 就能搞定注册表了

Eureka 注册中心系列文章汇总:

领导让我研究 Eureka 源码 | 启动过程

领导“叕”让我研究 Eureka 源码:注册过程

值得收藏的 Eureka 控制台详解

大家好,我是悟空。

本篇从源码角度带你学习 Eureka 服务端接收注册的流程。另外我从源码中也发现了一些值得我们学习的地方,如 Eureka 存储注册表的数据结构、利用读写锁来控制更细粒度的并发性,提高程序的运行效率。

接下来,会从以下几个方面讲解:

  • 客户端发送注册请求。
  • Eureka 注册中心接收注册请求。
  • 服务端将客户端注册信息保存到一个 Map 里面。

关于源码的获取直接到官网下载就好了。 https://github.com/Netflix/eureka

本文已收录到我的 github:https://github.com/Jackson0714/PassJava-Learning

@[toc]

一、注册入口

上一讲我们知道了 Eureka Client 是通过发送 http 请求来注册的,那么肯定是有一个地方来接收这个 http 请求的,也就是注册入口。这是怎么玩的呢?

其实是用到了 jersey 框架,这个框架不用深究,我们只需要知道这个框架在哪引用以及做什么事情的就可以了。

可以把 jersey 类比 mvc 框架,jersey 有 servlet 专门处理 http 请求。引用 jersey 框架的地方:

\eureka\eureka-server\src\main\webapp\WEB-INF\web.xml

然后处理 HTTP 请求的 controller 在哪呢?

其实是在 eureka-core 项目的 resources 目录下,里面定义了很多的 Resource 结尾的类,它们就是用来处理 HTTP 请求的。

\eureka\eureka-core\src\main\java\com\netflix\eureka\resources

通过XxResource 类的英文注释我们也可以知道,这个 jersey resource 类是用来处理 HTTP 请求的。

A jersey resource that handles request

ApplicationsResource

最后找到了 ApplicationResource 类的 addInstance 方法就是我们要找的处理注册请求的方法。

二、接收注册请求

整体流程如下:

2.1 接收注册请求的方法

addInstance 方法里面的核心代码就是

registry.register(info, true);

registry 就是 PeerAwareInstanceRegistryImpl 的实例对象。它实现了 PeerAwareInstanceRegistry 接口。

调用它的 register() 方法后会调用抽象类 AbstractInstanceRegistry 的 register() 方法,核心代码就是在这个抽象类的 register() 方法。另外要说下的就是上面的抽象类和接口分别实现和继承了接口 InstanceRegistry。

接口和类的关系图如下:

那么注册信息会放到哪个里面呢?

三、存放注册信息的地方

我们看到源码里面定义了一个 gNewMap,是 ConcurrentHashMap,然后赋值给了 gMap 变量

ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap 

所以其实是用 gMap 变量来存注册信息的。我们来分析 gMap 的结构。

首先 gMap 是 ConcurrentHashMap 结构,所以就是 key-value 这种键值对的。

  • key 就是一个 唯一 id,String 类型。值类似这种:i-00000004
  • value 里面存的是 Lease。
  • Lease是一个类,里面持有一个 instanceInfo 的 holder。这个 instanceInfo 就是注册过来的服务实例信息,包含 ip 地址,端口号等。

把服务实例信息放到 gMap 中也很简单,调用 put 方法就可以了。

gMap.put(registrant.getId(), lease);

下面是我注册了两个服务实例的状态:

四、值得学习的地方

4.1 ConcurrentHashMap?

上面讲到 ConcurrentHashMap,为什么不是用 hashmap ?

ConcurrentHashMap<String, Lease<InstanceInfo>>()

原因

  1. 在并发编程中使用 HashMap 可能造成死循环 ( JDK 1.7 和 1.8 可能会造成数据丢失)
  2. HashTable 效率非常较低。

简单说下 ConcurrentHashMap 的底层原理是怎么样的?

ConcurrentHashMap 内部细分了若干个小的 HashMap,称之为段(Segment)。 默认情况下一个 ConcurrentHashMap 被进一步细分为 16 个段,既就是锁的并发度。如果需要在 ConcurrentHashMap 中添加一个新的表项,并不是将整个 HashMap 加锁,而是首先根据 hashcode 得到该表项应该存放在哪个段中,然后对该段加锁,并完成 put 操作。在多线程环境中,如果多个线程同时进行put操作,只要被加入的表项不存放在同一个段中,则线程间可以做到真正的并行

4.2 readWriteLock?

我们看到源码中有用到读锁 ReentrantReadWriteLock,如下所示

readWriteLock = new ReentrantReadWriteLock();
Lock read = readWriteLock.readLock();
read.lock();
...
read.unlock();

4.2.1 为什么分为读锁和写锁?

原因

在没有读写锁之前,假设使用普通的 ReentrantLock,那么虽然保证了线程安全,但是也浪费了一定的资源,因为如果多个读操作同时进行,其实并没有线程安全问题,可以允许让多个读操作并行,以便提高程序效率。

但是写操作不是线程安全的,如果多个线程同时写,或者在写的同时进行读操作,便会造成线程安全问题。

读写锁就解决了这样的问题,它设定了一套规则,既可以保证多个线程同时读的效率,同时又可以保证有写入操作时的线程安全。

读锁: 允许多个线程获取读锁,同时访问同一个资源。

读锁

写锁: 只允许一个线程获取写锁,不允许同时访问同一个资源。

写锁

整体思路

是它有两把锁,第 1 把锁是写锁,获得写锁之后,既可以读数据又可以修改数据,而第 2 把锁是读锁,获得读锁之后,只能查看数据,不能修改数据。读锁可以被多个线程同时持有,所以多个线程可以同时查看数据。

在读的地方合理使用读锁,在写的地方合理使用写锁,灵活控制,可以提高程序的执行效率。

4.2.2 读写锁的获取规则

在使用读写锁时遵守下面的获取规则:

  • 如果有一个线程已经占用了读锁,则此时其他线程如果要申请读锁,可以申请成功。
  • 如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁,因为读写不能同时操作。
  • 如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,都必须等待之前的线程释放写锁,同样也因为读写不能同时,并且两个线程不应该同时写。

读写锁互斥总结

  • 读读共享。
  • 写写互斥、读写互斥、写读互斥。

五、总结

本篇从源码的角度,分析了 Eureka 服务端接收注册信息的流程,核心逻辑就是将服务实例的注册信息放到 ConcurrentHashMap 里面,同时利用读锁来控制细粒度的并发注册。另外介绍了下我们不太熟悉的 Jersey 框架,它是用来处理 HTTP 请求的,比如用来处理客户端注册的 HTTP 请求。

从源码分析中,我学到了 Eureka 存储注册表用到的数据结构 ConcurrentHashMap<String, Lease>(),大家可以借鉴下用到项目中。然后又复习了一遍 ConcurrentHashMap原理、可重入读写锁的原理,学习就是不断记忆,不断遗忘的过程,学习源码正好可以复习一波~

参考资料

http://www.passjava.cn

https://www.cnblogs.com/zz-ksw/p/12774151.html

相关文章
|
5月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
931 3
|
3月前
|
负载均衡 Java API
《深入理解Spring》Spring Cloud 构建分布式系统的微服务全家桶
Spring Cloud为微服务架构提供一站式解决方案,涵盖服务注册、配置管理、负载均衡、熔断限流等核心功能,助力开发者构建高可用、易扩展的分布式系统,并持续向云原生演进。
|
10月前
|
负载均衡 Dubbo Java
Spring Cloud Alibaba与Spring Cloud区别和联系?
Spring Cloud Alibaba与Spring Cloud区别和联系?
|
11月前
|
消息中间件 Java Kafka
【Azure Kafka】使用Spring Cloud Stream Binder Kafka 发送并接收 Event Hub 消息及解决并发报错
reactor.core.publisher.Sinks$EmissionException: Spec. Rule 1.3 - onSubscribe, onNext, onError and onComplete signaled to a Subscriber MUST be signaled serially.
209 5
|
11月前
|
前端开发 Java Nacos
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
本文介绍了如何使用Spring Cloud Alibaba 2023.0.0.0技术栈构建微服务网关,以应对微服务架构中流量治理与安全管控的复杂性。通过一个包含鉴权服务、文件服务和主服务的项目,详细讲解了网关的整合与功能开发。首先,通过统一路由配置,将所有请求集中到网关进行管理;其次,实现了限流防刷功能,防止恶意刷接口;最后,添加了登录鉴权机制,确保用户身份验证。整个过程结合Nacos注册中心,确保服务注册与配置管理的高效性。通过这些实践,帮助开发者更好地理解和应用微服务网关。
1942 0
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
|
10月前
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
266 0
|
12月前
|
人工智能 安全 Java
AI 时代:从 Spring Cloud Alibaba 到 Spring AI Alibaba
本次分享由阿里云智能集团云原生微服务技术负责人李艳林主讲,主题为“AI时代:从Spring Cloud Alibaba到Spring AI Alibaba”。内容涵盖应用架构演进、AI agent框架发展趋势及Spring AI Alibaba的重磅发布。分享介绍了AI原生架构与传统架构的融合,强调了API优先、事件驱动和AI运维的重要性。同时,详细解析了Spring AI Alibaba的三层抽象设计,包括模型支持、工作流智能体编排及生产可用性构建能力,确保安全合规、高效部署与可观测性。最后,结合实际案例展示了如何利用私域数据优化AI应用,提升业务价值。
1174 4
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
475 7
|
负载均衡 Java 开发者
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
769 5

热门文章

最新文章