0%

Elasticsearch 分片:分布式存储与查询的核心

分片(Shard)是 Elasticsearch 实现分布式存储和并行查询的基础,将一个索引的数据拆分为多个片段,分布在不同节点上。理解分片的工作原理和配置策略,对优化集群性能和可靠性至关重要。

分片的基本概念

主分片与副本分片

  • 主分片(Primary Shard)
    • 索引数据的原始存储单元,负责处理写入请求(索引、更新、删除)。
    • 数量在索引创建时指定(number_of_shards),创建后不可修改(因路由依赖主分片数量)。
    • 默认值:5 个(6.8.x 版本)。
  • 副本分片(Replica Shard)
    • 主分片的副本,用于冗余备份和分担查询压力(只读,不处理写入)。
    • 数量可动态调整(number_of_replicas),默认 1 个。
    • 副本分片不能与对应的主分片位于同一节点(避免单点故障)。

分片的核心作用

  • 分布式存储:突破单节点存储上限,支持海量数据(如 10 个主分片可存储 10 倍于单节点的数据)。
  • 并行处理:查询请求可同时在多个分片(主或副本)上执行,提升查询效率。
  • 高可用性:主分片故障时,副本分片可自动升级为主分片(需集群有足够节点)。

分片路由机制

当文档写入或查询时,Elasticsearch 需要确定文档属于哪个主分片,这一过程通过路由算法实现:

路由公式

阅读全文 »

Elasticsearch 集群:分布式架构与管理详解

Elasticsearch 集群是由多个节点(Node)组成的分布式系统,通过协同工作实现高可用、高扩展的数据存储与查询。集群的核心是节点角色分工、分片(Shard)分布式管理及动态配置,以下从架构、监控、配置等方面详细解析。

集群核心组件

节点(Node):集群的基本单元

节点是 Elasticsearch 的运行实例,每个节点通过 cluster.name 标识所属集群。根据功能分工,节点分为以下类型:

节点类型 作用 核心配置(elasticsearch.yml
主节点(Master) 管理集群元数据(索引创建 / 删除、分片分配),不处理数据读写。 node.master: true node.data: false node.ingest: false
数据节点(Data) 存储索引数据,处理索引 / 查询请求,对 CPU、内存、IO 要求高。 node.master: false node.data: true node.ingest: false
客户端节点(Client) 作为协调节点(路由请求、合并结果),不存储数据也不参与主节点选举。 node.master: false node.data: false node.ingest: true
预处理节点(Ingest) 处理文档预处理(如添加字段、转换格式),可与其他角色叠加。 node.ingest: true(默认开启)

分片(Shard):数据分布式存储的核心

分片是索引数据的最小存储单元,分为主分片和副本分片,实现数据分布式存储与高可用:

  • 主分片(Primary Shard)
    • 负责数据写入,数量在索引创建时指定(number_of_shards),不可动态修改
    • 作用:通过横向扩展(增加主分片)提升存储容量。
  • 副本分片(Replica Shard)
    • 主分片的冗余副本,负责分担查询压力,数量可动态调整(number_of_replicas)。
    • 作用:提高查询吞吐量,保障数据可用性(主分片故障时自动升级为新主分片)。

集群监控与管理 API

Elasticsearch 提供丰富的 API 监控集群状态、节点信息及分片分布,核心接口如下:

集群状态监控

(1)查看集群健康状态
阅读全文 »

Spring Boot 使用 JSP 详解:从依赖配置到视图渲染全流程

虽然 Spring Boot 推荐使用 Thymeleaf、Freemarker 等模板引擎,但在迁移传统 SSH/SSM 项目时,仍需支持 JSP 视图。由于 Spring Boot 对 JSP 的支持并非默认集成,需手动配置依赖、资源路径和视图解析器。从 “依赖配置→目录结构→视图解析→常见问题” 四个维度,详细讲解 Spring Boot 集成 JSP 的完整流程,帮你顺利实现 JSP 页面渲染。

核心背景:为什么 Spring Boot 不默认支持 JSP?

Spring Boot 推荐使用 嵌入式容器(如 Tomcat)和 可执行 JAR 打包,而 JSP 存在两个关键限制,导致其未被默认支持:

  1. JSP 编译依赖 Servlet 容器:JSP 需要 Tomcat 的 jasper 引擎编译为 Servlet 类,而嵌入式 Tomcat 默认不包含 jasper 依赖;
  2. JAR 包无法直接包含 JSP:JSP 文件需放在 WEB-INF 目录下,而 Spring Boot 默认的 JAR 打包结构中没有 WEB-INF,需手动配置资源路径映射。

因此,集成 JSP 的核心是 “添加 JSP 编译依赖” 和 “配置 JSP 资源目录”。

Spring Boot 集成 JSP 的完整步骤

步骤 1:添加 JSP 相关依赖

需引入两个核心依赖:tomcat-embed-jasper(JSP 编译引擎)和 jstl(JSP 标准标签库,可选但推荐)。

Maven 依赖配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<dependencies>
<!-- 1. Spring Boot Web 依赖(包含嵌入式 Tomcat) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 2. JSP 编译引擎(嵌入式 Tomcat 需手动引入) -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!-- scope 无需设置为 provided,嵌入式 Tomcat 需要加载该依赖 -->
</dependency>

<!-- 3. JSTL 标签库(可选,使用 JSP 标签时需引入,如 c:forEach) -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
<exclusions>
<!-- 排除旧的 servlet-api 依赖,避免冲突 -->
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
依赖说明:
阅读全文 »

Spring BeanDefinition 详解:Bean 的 “元数据蓝图”

BeanDefinition 是 Spring 中描述 Bean 的核心元数据接口,它像一份 “蓝图”,定义了 Bean 的创建规则、属性配置、依赖关系等关键信息。Spring 容器正是基于这些元数据完成 Bean 的实例化、属性注入和生命周期管理。本文将从接口定义、核心属性、实现类体系三个维度,全面解析 BeanDefinition 的设计与作用。

BeanDefinition 核心接口:定义 Bean 的元数据规范

BeanDefinition 接口继承了 AttributeAccessor(属性访问)和 BeanMetadataElement(元数据元素)接口,为 Bean 定义了一套完整的元数据规范。其核心作用是 “描述 Bean 的所有特征,让 Spring 容器知道如何创建和管理这个 Bean”。

核心属性分类

BeanDefinition 的属性可分为基础配置依赖关系生命周期角色标识四大类,对应 XML 配置中的<bean>标签属性或注解配置的元信息:

类别 核心属性 对应 XML 配置示例
基础配置 类名(beanClassName)、作用域(scope)、是否抽象(abstract) <bean class="com.User" scope="singleton" abstract="false"/>
依赖关系 父 Bean(parentName)、依赖 Bean(dependsOn)、工厂 Bean(factoryBeanName) <bean parent="baseBean" depends-on="dataSource" factory-bean="userFactory"/>
生命周期 懒加载(lazyInit)、初始化方法(initMethodName)、销毁方法(destroyMethodName) <bean lazy-init="true" init-method="init" destroy-method="close"/>
装配规则 自动装配候选(autowireCandidate)、首选 Bean(primary) <bean autowire-candidate="true" primary="true"/>
角色标识 角色(role):区分用户定义 Bean 和 Spring 内部 Bean -

关键方法解析

(1)作用域相关
1
2
3
4
5
6
7
8
// 设置作用域(singleton/prototype等)
void setScope(String scope);
// 获取作用域
String getScope();
// 判断是否为单例(简化方法,等价于 scope == SCOPE_SINGLETON)
boolean isSingleton();
// 判断是否为原型(简化方法,等价于 scope == SCOPE_PROTOTYPE)
boolean isPrototype();
  • 单例(SCOPE_SINGLETON):容器中仅存在一个实例,默认值;
  • 原型(SCOPE_PROTOTYPE):每次getBean()都创建新实例。
(2)依赖与继承相关
1
2
3
4
5
6
7
// 设置父Bean名称(实现Bean配置继承)
void setParentName(String parentName);
String getParentName();

// 设置依赖的Bean(被依赖Bean优先初始化)
void setDependsOn(String... dependsOn);
String[] getDependsOn();
阅读全文 »

网络通信的分层封装与解析过程

在计算机网络中,数据的传输并非直接发送原始信息,而是通过分层封装的方式,在每一层为数据添加必要的控制信息(首部),确保数据能跨越复杂网络准确到达目标。接收方则通过逆向解析,逐层剥离首部,最终获取原始数据。以下是完整的通信流程解析:

数据发送:分层封装的全过程

数据从应用层产生到通过物理介质发送,需经过应用层、传输层、网络层、数据链路层的逐层处理,每一层都会在数据前添加该层的首部信息。

1. 应用层:数据的生成与编码

  • 操作:用户通过应用程序(如浏览器、邮件客户端)生成原始数据(如网页请求、邮件内容),并按照应用层协议(如 HTTP、SMTP)进行编码和格式化。
  • 示例:浏览器生成一个 HTTP 请求报文,包含请求方法(GET)、目标 URL、协议版本等信息。
  • 输出:应用层数据(无首部,仅原始内容)。

2. 传输层:添加端口与可靠性控制

  • 操作:传输层(TCP 或 UDP)接收应用层数据,在其前端添加传输层首部,核心信息包括:
    • 源端口号:标识发送方的应用程序(如浏览器用随机端口);
    • 目标端口号:标识接收方的应用程序(如 HTTP 服务用 80 端口);
    • 序号与确认号(TCP 特有):确保数据按序传输和可靠确认;
    • 校验和:用于检测数据传输过程中的损坏。
  • 示例:TCP 为 HTTP 请求添加首部,源端口为 12345,目标端口为 80,序号为 1000。
  • 输出:传输层报文(= 传输层首部 + 应用层数据)。

3. 网络层:添加 IP 地址与路由信息

  • 操作:网络层(IP 协议)接收传输层报文,将其作为自身数据,在前端添加IP 首部,核心信息包括:
    • 源 IP 地址:发送方设备的逻辑地址(如 192.168.1.100);
    • 目标 IP 地址:接收方设备的逻辑地址(如 203.0.113.5);
    • 协议字段:标识上层协议(如 TCP=6,UDP=17);
    • 生存时间(TTL):限制数据包的传输跳数,防止环路。
  • 示例:IP 首部中源 IP 为 192.168.1.100,目标 IP 为 203.0.113.5,协议字段为 6(表示上层是 TCP)。
  • 输出:IP 数据报(= IP 首部 + 传输层报文)。

4. 数据链路层:添加 MAC 地址与链路控制信息

阅读全文 »