0%

Eureka 简介:Spring Cloud 生态的经典服务注册中心

Eureka 是 Netflix 开源的服务发现组件,作为 Spring Cloud 早期推荐的注册中心,凭借高可用性设计和与 Spring 生态的无缝集成,成为微服务架构中服务治理的经典方案。它通过Eureka Server(注册中心)和Eureka Client(服务端 / 客户端)的角色分工,实现服务的注册、发现和健康管理。

Eureka 的核心架构

Eureka 的设计遵循AP 原则(可用性优先,兼顾最终一致性),核心组件包括:

Eureka Server(注册中心)

  • 提供服务注册接口,存储所有可用服务的元数据(IP、端口、状态等);
  • 支持集群部署,通过节点间数据复制实现高可用;
  • 提供 Web 控制台(默认地址 http://localhost:8761),直观展示服务状态。

Eureka Client(服务端 / 客户端)

  • 服务提供者:启动时向 Eureka Server 注册自身信息,定期发送心跳证明可用性;

  • 服务消费者:从 Eureka Server 拉取服务列表并缓存到本地,通过服务名调用接口;

    这种方式可以使得微服务不需要每次请求都查询Eureka Server,从而降低了Eureka Server的压力,如果Eureka Server所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者完成调用

  • 内置轮询负载均衡算法,简化服务调用流程。

Eureka 的核心特性

阅读全文 »

Eureka 服务下线机制:确保注册中心实例准确性

在 Eureka 架构中,服务下线是维持注册中心注册表准确性的关键环节。默认情况下,Eureka 通过心跳检测机制自动剔除失效服务,但在某些场景(如服务异常崩溃)下可能出现延迟,导致无效实例残留。本文详细介绍 Eureka 服务下线的实现方式及手动干预手段。

Eureka 服务下线的默认机制

Eureka 通过心跳检测自动剔除实现服务下线管理:

  1. 心跳续约
    服务提供者(Eureka Client)启动后,会定期向 Eureka Server 发送心跳(默认每 30 秒一次),证明自身可用。心跳请求格式为:

    1
    PUT /eureka/apps/{服务名}/{实例ID}?status=UP
  2. 自动剔除

    • 若 Eureka Server 在90 秒内未收到心跳(可通过lease-expiration-duration-in-seconds配置),会将该实例标记为DOWN
    • 标记后,Eureka Server 不会立即删除实例,而是等待一段时间(受自我保护机制影响)后从注册表中移除。
  3. 自我保护机制的影响
    当 Eureka Server 触发自我保护(如网络分区导致心跳骤减),会暂停自动剔除功能,此时即使服务已下线,仍可能保留在注册表中,避免误删健康服务。

服务下线不及时的问题与原因

常见问题

  • 服务已手动停止,但 Eureka Server 仍显示为UP状态,导致消费者调用失效实例报错;
  • 服务异常崩溃(如进程被 kill),未执行正常下线流程,Eureka Server 无法及时感知。

原因分析

阅读全文 »

Spring Bean 实例化完整流程解析:从配置加载到 Bean 就绪

Spring Bean 的实例化是 IOC 容器的核心能力,并非简单的 “new 对象”,而是一套包含 “配置元信息解析→BeanDefinition 注册→容器增强→实例化→属性注入→初始化” 的完整链路。本文结合 BeanDefinitionReaderBeanDefinitionRegistryBeanFactoryPostProcessor 等核心组件,从 “阶段拆解→组件作用→实战细节” 三个维度,彻底讲透 Bean 实例化的每一步。

Bean 实例化的整体链路(宏观视角)

Bean 实例化的本质是 “将配置元信息(XML / 注解)转化为可使用的 Bean 实例”,整体流程可分为 4 大阶段,每个阶段对应特定组件和职责:

graph TD
    A[阶段1:配置元信息加载] --> B[阶段2:BeanDefinition生成与注册]
    B --> C[阶段3:BeanFactoryPostProcessor增强]
    C --> D[阶段4:Bean实例化与初始化]
    D --> E["Bean就绪:可通过getBean()获取"]

每个阶段的核心目标:

  • 阶段 1:读取外部配置(XML / 注解 / JavaConfig),转化为 Spring 可识别的 “元信息”;
  • 阶段 2:将元信息封装为 BeanDefinition(Bean 的 “蓝图”),并注册到容器;
  • 阶段 3:修改 / 增强 BeanDefinition(如替换占位符、动态注册新 Bean);
  • 阶段 4:基于 BeanDefinition 创建实例、注入属性、执行初始化,最终生成可用 Bean。

阶段 1:配置元信息加载 —— 告诉 Spring “要创建哪些 Bean”

Spring 无法主动感知需要创建的 Bean,必须通过配置元信息明确告知。配置方式分为 “XML 配置”“注解配置”“JavaConfig 配置”,对应不同的 BeanDefinitionReader 来加载。

1. 核心组件:BeanDefinitionReader(元信息读取器)

BeanDefinitionReader 是加载配置元信息的顶层接口,不同配置方式对应不同实现类:

阅读全文 »

hive Map 字段查询全解析:从建表到复杂查询

Hive 支持 MAP 类型字段存储键值对数据(如用户成绩单、商品属性等),配合内置集合函数可高效查询和分析 Map 中的数据。本文以成绩单场景为例,详细讲解 Map 字段的建表、数据插入、常用查询及集合函数的使用,帮助开发者灵活处理键值对数据。

Map 类型表的创建与数据准备

建表语句解析

创建包含 MAP 字段的表需指定分隔符,确保 Hive 正确解析键值对结构。

建表示例
1
2
3
4
5
6
7
8
CREATE TABLE test_map (  
name STRING COMMENT '学生姓名',
score MAP<STRING, INT> COMMENT '科目-分数的键值对'
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t' -- 列分隔符(姓名与 score 之间用制表符分隔)
COLLECTION ITEMS TERMINATED BY ',' -- Map 内部键值对之间的分隔符
MAP KEYS TERMINATED BY ':'; -- Map 中键与值的分隔符(如 "数学:90" 中的 ":")
分隔符说明
  • FIELDS TERMINATED BY '\t':表中列之间的分隔符(如 张三\t数学:90,英语:85 中,张三score 字段用 \t 分隔);
  • COLLECTION ITEMS TERMINATED BY ',':Map 中多个键值对的分隔符(如 数学:90,英语:85 中用 , 分隔);
  • MAP KEYS TERMINATED BY ':':Map 中键(Key)和值(Value)的分隔符(如 数学:90 中用 : 分隔)。

插入测试数据

向 Map 类型表插入数据需遵循上述分隔符规则,示例数据格式:

1
2
3
张三	数学:90,英语:85,语文:95  
李四 数学:88,英语:92
王五 语文:80,物理:75,数学:90
插入数据语句
阅读全文 »

Scala 偏函数:精准处理集合的筛选与转换

偏函数(Partial Function)是 Scala 中一种特殊的函数,它只对满足特定条件的输入值进行处理,相当于 filter(筛选)和 map(转换)的结合体。偏函数特别适合处理包含多种类型元素的集合,能简洁地实现 “先筛选、后操作” 的逻辑。本文将详细解析偏函数的定义、使用及简化写法。

偏函数的基本概念

偏函数是仅对部分输入值有定义的函数,与普通函数(对所有输入值都有定义)形成对比。在 Scala 中,偏函数通过 PartialFunction[A, B] 特质实现,其中:

  • A 是输入参数类型
  • B 是返回值类型

PartialFunction 特质包含两个核心方法:

  1. isDefinedAt(x: A): Boolean:判断输入 x 是否符合处理条件(是否在偏函数的定义域内)。
  2. apply(x: A): B:对符合条件的输入 x 执行具体操作并返回结果。

偏函数的定义与使用

完整定义(实现特质方法)

通过实现 PartialFunction 特质的两个方法,定义一个偏函数:

1
2
3
4
5
6
7
8
// 定义偏函数:只处理 Int 类型,将其翻倍
val doubleInt: PartialFunction[Any, Int] = new PartialFunction[Any, Int] {
// 筛选条件:仅 Int 类型符合要求
override def isDefinedAt(x: Any): Boolean = x.isInstanceOf[Int]

// 处理逻辑:将 Int 类型的值翻倍
override def apply(x: Any): Int = x.asInstanceOf[Int] * 2
}

使用偏函数(通过 collect 方法)

集合的 collect 方法专门用于接收偏函数,它会先通过 isDefinedAt 筛选元素,再对符合条件的元素应用 apply 方法:

1
2
3
4
5
6
// 包含多种类型的集合
val mixedList: List[Any] = List(1, "scala", 3, 4.5, 'a', 5)

// 使用偏函数处理集合
val result: List[Int] = mixedList.collect(doubleInt)
println(result) // 输出:List(2, 6, 10)
阅读全文 »