0%

Elasticsearch 索引变为只读问题:原因与解决方案

当 Elasticsearch 集群磁盘空间不足时,可能会触发内置的磁盘保护机制,将索引强制设置为只读状态,导致无法写入或修改数据。本文详细解析这一问题的成因、解决步骤及预防措施。

问题根源:磁盘水位线(Watermark)保护机制

Elasticsearch 为防止磁盘空间耗尽,通过磁盘水位线机制监控节点磁盘使用率,并在达到阈值时采取保护措施:

水位线参数 默认值 触发行为
cluster.routing.allocation.disk.watermark.low 85% 磁盘使用率超过 85% 时,不再向该节点分配新分片。
cluster.routing.allocation.disk.watermark.high 90% 磁盘使用率超过 90% 时,将该节点上的分片迁移到其他节点。
cluster.routing.allocation.disk.watermark.flood_stage 95% 磁盘使用率超过 95% 时,将节点上所有索引设置为只读read_only_allow_delete),仅允许删除操作。

触发只读的典型日志

当达到 flood_stage 水位线时,日志会显示类似以下内容:

1
2
flood stage disk watermark [95%] exceeded on [node-id][node-name][/path/to/data] 
free: 1.9gb[4%], all indices on this node will be marked read-only

此时,所有写入、更新操作会失败,仅查询和删除操作可用。

解决步骤:恢复读写能力

紧急处理:释放磁盘空间

首先需释放足够的磁盘空间(建议至少保留 10% 以上空闲空间):

  • 删除无用的索引、日志文件或临时文件。
  • 迁移部分数据到其他存储(如冷数据归档)。

关闭磁盘水位线检查(临时)

若无法立即扩容,可临时关闭磁盘阈值检查,允许 Elasticsearch 忽略水位线限制:

阅读全文 »

Tomcat 类加载器:打破双亲委派的隔离机制

Java 类加载器的双亲委派模型通过层级委派确保类加载的安全性和唯一性,但 Tomcat 作为多 Web 应用容器,需要实现应用间类库隔离(避免不同应用的同名类冲突)和类热部署,因此自定义了一套类加载器体系。本文将详细解析 Tomcat 类加载器的结构、加载机制及与双亲委派的差异。

Tomcat 类加载器的结构

Tomcat 打破了 Java 原生的双亲委派模型,设计了多层次的类加载器,实现不同范围类的隔离与共享。其核心类加载器结构如下(从顶层到应用层):

tomcat类加载器

核心类加载器及职责

类加载器 父加载器 配置参数 职责范围
Common 类加载器 System 类加载器 common.loader 加载 Tomcat 内部和所有 Web 应用共享的类(如 Servlet 规范 API、通用工具类)。
Catalina 类加载器 Common 类加载器 server.loader 加载仅 Tomcat 内部可见的类(对 Web 应用隐藏),默认与 Common 共享。
Shared 类加载器 Common 类加载器 shared.loader 加载所有 Web 应用共享但对 Tomcat 不可见的类,默认与 Common 共享。
Web 应用类加载器 Shared 类加载器 无(自动生成) 加载当前 Web 应用私有类(/WEB-INF/classes/WEB-INF/lib 下的类),仅当前应用可见。
Jasper 类加载器 Web 应用类加载器 无(JSP 专用) 加载 JSP 编译后的类,支持 JSP 热部署(修改后重新编译加载)。

配置文件:catalina.properties

Tomcat 通过 conf/catalina.properties 配置类加载器的资源路径:

阅读全文 »

POI 读取 Excel 合并单元格内容:完整解决方案

在处理包含合并单元格的 Excel 时,直接读取非左上角的单元格会返回空值(因为合并单元格仅左上角单元格保存数据)。本文将详细讲解如何识别合并单元格、读取合并区域的内容,并提供通用工具类,确保在各种合并场景下准确获取数据。

合并单元格的特性与读取难点

合并单元格的存储规则

Excel 中合并单元格(如 CellRangeAddress 定义的区域)仅在左上角第一个单元格中存储数据,其他被合并的单元格均为空。例如:

  • 合并 A1:A3(3 行 1 列)后,仅 A1 有值,A2A3 为空;
  • 合并 B2:D4(3 行 3 列)后,仅 B2 有值,B3C2 等均为空。

直接读取的问题

若直接通过 row.getCell(column) 读取合并区域内的非左上角单元格,会返回 null 或空值,导致数据丢失。因此,需要:

  • 先判断单元格是否属于合并区域;
  • 若属于,则读取合并区域左上角单元格的值。

核心工具类实现

以下工具类提供合并单元格的判断、内容读取等功能,兼容 .xls.xlsx 格式。

阅读全文 »

POI读取excel报错解决方案:兼容 xls 与 xlsx 格式

在使用 POI 读取 Excel 文件时,因文件格式(.xls.xlsx)不同常出现格式不匹配的错误。本文将详细解析错误原因,提供通用解决方案,并介绍 WorkbookFactory 的使用技巧,帮助你无缝兼容两种格式。

错误原因分析

错误信息解读

当使用 POIFSFileSystem 读取 .xlsx 文件时,会出现以下错误:

1
The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)  
  • 原因:
    • .xls(Excel 2003 及以前)基于 OLE2 格式,需用 HSSF 相关类(如 POIFSFileSystemHSSFWorkbook)处理;
    • .xlsx(Excel 2007 及以后)基于 XML 格式,需用 XSSF 相关类(如 XSSFWorkbook)处理。
    • 若用 HSSF 类读取 .xlsx 文件(或反之),会因格式不匹配报错。

常见错误用法

手动判断文件格式并选择对应类,容易因判断逻辑错误导致兼容问题:

阅读全文 »

spark性能优化全指南:从算法到资源的全方位调优

Spark 作为分布式计算引擎,其性能受算法设计、资源配置、数据分布等多因素影响。不合理的实现或配置可能导致任务运行缓慢、资源浪费甚至失败。本文从算法优化、并行度调整、缓存策略、内存管理、数据倾斜处理等维度,系统讲解 Spark 性能优化的核心方法,帮助开发者将任务效率提升数倍。

算法性能优化:选择高效的算子与数据处理方式

Spark 算子的选择直接影响任务的 Shuffle 数据量和计算复杂度,合理使用算子可减少不必要的开销。

避免低效算子,优先选择聚合类算子

低效算子 高效替代方案 优化原理
groupByKey reduceByKey / aggregateByKey groupByKey 仅分组不聚合,会将所有数据 Shuffle 到 Reduce 端;reduceByKey 在 Map 端先预聚合,减少 Shuffle 数据量
flatMap + groupByKey combineByKey combineByKey 支持自定义 Map 端聚合逻辑,灵活控制中间结果
cartesian(笛卡尔积) 避免使用,或通过过滤提前减少数据量 笛卡尔积会产生 N*M 条数据,极易导致 OOM,仅在小数据集场景使用

使用分区级算子减少任务启动开销

  • mapPartitions 替代 map
    map 对每条数据执行一次函数调用,mapPartitions 对每个分区执行一次函数调用(处理整个分区数据),减少函数初始化开销(如数据库连接创建)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 低效:每条数据创建一次连接  
    rdd.map(record => {
    val conn = getDBConnection() // 重复创建连接
    process(record, conn)
    })

    // 高效:每个分区创建一次连接
    rdd.mapPartitions(iterator => {
    val conn = getDBConnection() // 分区内共享连接
    iterator.map(record => process(record, conn))
    })
  • foreachPartition 替代 foreach:类似 mapPartitions,适合批量输出场景(如批量写入数据库)。

数据倾斜的算法级优化

数据倾斜(某 Key 对应数据量远超其他 Key)会导致单个 Task 耗时过长,可通过加盐散列分散倾斜 Key:

阅读全文 »