0%

Kafka 故障时的数据一致性保障:LEO 与 HW 的核心作用

Kafka 中,数据一致性指的是分区的多个副本(Leader 与 Follower)之间数据的同步状态 —— 故障恢复后,所有副本应保持相同的数据内容。这一目标主要通过 LEO(Log End Offset)HW(High Watermark) 两个核心指标,配合故障处理机制实现。

核心概念:LEO 与 HW

LEO(Log End Offset)

  • 定义:每个副本(Leader 或 Follower)本地日志中 “下一条待写入消息的偏移量”,即当前日志中最后一条消息的偏移量 + 1。
  • 举例:若副本日志中最后一条消息的偏移量是 5,则该副本的 LEO 为 6。
  • 作用:标记副本当前的 “数据写入进度”,Leader 和 Follower 各自维护自己的 LEO。

HW(High Watermark,高水位)

  • 定义:分区的 HW 是 ISR(同步副本集)中所有副本的 LEO 的最小值。
  • 举例:若分区的 ISR 包含 Leader(LEO=10)和 Follower1(LEO=8)、Follower2(LEO=9),则该分区的 HW 为 8(三者 LEO 的最小值)。
  • 核心意义:
    • HW 是 “消费者可见的最大偏移量”,消费者只能读取到 HW 之前的消息(即偏移量 ≤ HW-1 的消息)。
    • HW 之前的消息被认为是 “已提交的消息”(committed messages),确保所有 ISR 副本都已同步这些消息,即使发生故障也不会丢失。

故障处理:如何通过 LEO 和 HW 保证一致性

Follower 故障的恢复流程

Follower 故障后,需重新加入集群并与 Leader 同步数据,确保数据一致:

  • 步骤 1:Follower 故障时,Kafka 会将其临时踢出 ISR(因无法在 replica.lag.time.max.ms 内同步数据)。
  • 步骤 2:Follower 恢复后,首先读取本地磁盘记录的自身 HW,并截断日志中所有 offset ≥ HW 的消息(这些消息可能是故障前未同步完成的 “脏数据”)。
  • 步骤 3:从自身 HW 开始,向 Leader 重新同步数据(拉取 Leader 中从该 HW 开始的消息)。
  • 步骤 4:当 Follower 的 LEO 追上 Leader 的 LEO(或达到分区当前的 HW),证明其数据已与 Leader 一致,重新加入 ISR。

目的:通过截断未确认的消息并重新同步,确保 Follower 与 Leader 数据一致。

Leader 故障的恢复流程

Leader 故障后,需从 ISR 中选举新 Leader,并让其他副本与新 Leader 同步,保证数据一致:

阅读全文 »

Windows 端口映射配置指南

在 Windows 系统中,可以通过netsh命令行工具的portproxy功能实现端口映射(端口转发),这在需要将外部网络请求转发到内网服务时非常有用(如远程访问内网服务器、游戏联机等场景)。

端口映射核心命令

1. 查询所有端口映射规则

查看当前系统中已配置的所有 IPv4 到 IPv4 的端口映射规则:

1
netsh interface portproxy show v4tov4

2. 筛选特定 IP 的映射规则

查询包含指定 IP 的所有端口映射(支持内网 IP 或外网 IP):

1
netsh interface portproxy show v4tov4 | find "目标IP"

示例:查询包含内网 IP 192.168.1.1 的映射规则

1
netsh interface portproxy show v4tov4 | find "192.168.1.1"

3. 添加端口映射规则

将来自外网 IP: 外网端口的请求转发到内网 IP: 内网端口

阅读全文 »

Kafka 数据存储机制详解:从分区到日志文件的底层实现

Kafka 的高性能和高可靠性很大程度上依赖于其精巧的数据存储机制。从主题(Topic)的逻辑划分到分区(Partition)的物理存储,再到日志文件的分段与索引设计,每一层都经过优化以支持高吞吐、低延迟的消息读写。本文将以具体示例(3 个 Broker、3 个分区、2 个副本的主题)为切入点,深入解析 Kafka 数据存储的底层原理。

存储架构概览

Kafka 的数据存储遵循 “分层划分、分布式存储” 的原则,核心层次包括:

  1. 主题(Topic):逻辑概念,用于分类消息(如 first 主题)。
  2. 分区(Partition):物理概念,每个主题分为多个分区(如 3 个分区),是并行读写的基本单位。
  3. 副本(Replica):每个分区有多个副本(如 2 个副本),实现高可用(Leader 副本处理读写,Follower 副本同步数据)。
  4. 日志段(LogSegment):每个分区的日志文件被拆分为多个片段(.log 数据文件 + .index 索引文件),优化存储和查询效率。

以示例主题 first 为例(3 个 Broker、3 个分区、2 个副本),其存储架构如下:

  • Broker 分布:3 个 Broker(ID 为 0、1、2)。
  • 分区副本分配:每个分区的 2 个副本分布在不同 Broker 上(如分区 0 的副本在 Broker 0 和 2 上)。
  • Leader 选举:每个分区的 Leader 副本分散在不同 Broker 上(如分区 0 的 Leader 在 Broker 2,分区 1 的 Leader 在 Broker 0),实现负载均衡。

分区:数据存储的基本单元

分区的核心作用

  • 并行扩展:多个分区可分布在不同 Broker 上,支持并行读写(如 3 个分区可同时处理 3 倍于单分区的吞吐量)。
  • 顺序写入:消息按顺序追加到分区的日志文件(磁盘顺序写性能接近内存)。
  • 偏移量(Offset):每个分区内的消息有唯一偏移量(从 0 开始递增),标记消息的位置(如分区 0 的第 1 条消息偏移量为 0,第 2 条为 1)。

分区的副本机制

以主题 first 为例,3 个分区的副本分配如下(信息存储在 ZooKeeper 的 /brokers/topics/first/partitions 节点):

分区 ID 副本分布(Broker ID) Leader 副本 ISR 列表(同步副本)
0 [2, 0] 2 [2, 0]
1 [0, 1] 0 [0, 1]
2 [1, 2] 1 [1, 2]
  • Leader 副本:处理所有读写请求(如分区 0 的 Leader 在 Broker 2)。
  • Follower 副本:从 Leader 同步数据(如分区 0 的 Follower 在 Broker 0),Leader 故障时可被选举为新 Leader。
  • ISR 列表:与 Leader 保持同步的副本(包括 Leader 自身),只有 ISR 中的副本可参与 Leader 选举。

ZooKeeper 中的分区元数据

kafka数据存储机制之broker

Kafka 通过 ZooKeeper 存储分区的元数据(如 Leader 位置、ISR 列表),路径为 /brokers/topics/<topic>/partitions/<partition>/state。例如:

阅读全文 »

Lucene 简介:开源搜索引擎的核心引擎

Lucene 是 Apache 基金会旗下的一款高性能、可伸缩的开源信息检索库,它提供了完整的索引构建、检索和排序功能,是 Elasticsearch、Solr 等主流搜索引擎的底层核心。本文将详细解析 Lucene 的核心概念、索引机制及工作流程。

Lucene 核心概念

Lucene 围绕 “索引” 和 “检索” 构建了一套完整的抽象模型,以下是关键概念:

索引库(Index)

  • 定义:Lucene 中,一个目录即一个索引库,目录下的所有文件共同构成一个完整的索引,包含多个文档(Document)。
  • 特点:索引库是 Lucene 操作的基本单位,所有文档的索引数据(如倒排索引、词项信息)都存储在该目录中。
  • 类比:类似数据库中的 “数据库实例”,一个索引库可对应一个业务场景(如 “商品索引”“文章索引”)。

段(Segment)

段是 Lucene 索引的 “子单元”,一个索引库由多个段组成,每个段是一个独立的、不可修改的索引片段。

核心特性:
  • 不可变性:段一旦写入磁盘,就只能读取,不能修改(保证索引稳定性和查询性能)。
  • 增删改处理:
    • 新增:新文档会生成新段(先写入内存,批量刷盘以减少 IO)。
    • 删除:不直接删除段中数据,而是通过 .del 文件标记被删除的文档 ID,查询时过滤这些文档(段合并时才真正移除)。
    • 修改:等价于 “删除旧文档 + 新增新文档”(旧文档被标记删除,新文档写入新段)。
  • 段合并:当段数量过多时,Lucene 会自动合并小段位大段(减少文件句柄占用,提升查询效率)。
延迟写机制:

新增数据先写入内存缓冲区,积累到一定量后批量刷盘生成新段,同时生成提交点(记录已刷盘的段信息)。这一机制减少了磁盘 IO 次数,提升性能。

阅读全文 »

final 关键字详解

在 Java 中,final是一个重要的关键字,可用于修饰变量、方法和类,分别赋予它们不同的特性。下面详细解析其用法和特性:

final 修饰方法

核心作用

final修饰的方法不允许被子类重写,从而保证方法行为的稳定性。

特殊说明

  • 类中所有private方法默认隐式为final。因为private方法只能在当前类中访问,子类无法继承,自然无法重写。
  • 若子类中定义了与父类private方法同名的方法,这并非重写,而是子类新定义的方法,编译不会报错。

优势

  1. 行为一致性:防止子类通过重写改变核心方法的逻辑。
  2. 性能优化:
    • 编译器可对final方法进行静态绑定(无需运行时动态解析方法调用)。
    • 可能触发内联优化:用方法体代码直接替换调用处,减少方法调用的栈操作开销。

final 修饰类

核心作用

final修饰的类不允许被继承,即该类没有子类。

阅读全文 »