Bootstrap

Java学习笔记(二十四)

1 策略模式

1.1 策略模式概述

策略模式(Strategy Pattern) 是一种行为设计模式,定义了一系列算法,并将它们封装成独立的类,使它们可以互相替换而不会影响使用它们的客户端代码。
策略模式的核心思想是将行为与环境解耦,使得行为可以灵活替换。适用于需要在运行时根据条件选择不同算法或行为的情况。


1.2 策略模式的关键组成

  1. 上下文(Context)

    • 维护对策略对象的引用。
    • 调用策略对象定义的接口以执行具体的行为。
  2. 抽象策略(Strategy)

    • 定义所有支持算法的公共接口。
  3. 具体策略(ConcreteStrategy)

    • 实现具体的算法或行为。

1.3 策略模式的优点

  • 遵循 开闭原则(Open-Closed Principle):可以在不修改上下文类的情况下引入新的策略。
  • 消除大量条件语句(如 if-elseswitch-case)。
  • 策略的实现代码可以独立于使用它的客户端代码,使代码更容易理解和维护。

1.4 策略模式的代码示例

以一个简单的支付系统为例。不同的支付方式(如支付宝、微信支付、信用卡支付)是不同的策略。

1.4.1 Python 实现
from abc import ABC, abstractmethod

# 抽象策略类
class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount: float):
        pass

# 具体策略:支付宝支付
class Alipay(PaymentStrategy):
    def pay(self, amount: float):
        print(f"Using Alipay to pay {amount} dollars.")

# 具体策略:微信支付
class WeChatPay(PaymentStrategy):
    def pay(self, amount: float):
        print(f"Using WeChat Pay to pay {amount} dollars.")

# 具体策略:信用卡支付
class CreditCardPay(PaymentStrategy):
    def pay(self, amount: float):
        print(f"Using Credit Card to pay {amount} dollars.")

# 上下文类
class PaymentContext:
    def __init__(self, strategy: PaymentStrategy):
        self._strategy = strategy

    def set_strategy(self, strategy: PaymentStrategy):
        self._strategy = strategy

    def pay(self, amount: float):
        self._strategy.pay(amount)

# 客户端代码
if __name__ == "__main__":
    # 初始化支付方式
    alipay = Alipay()
    wechat_pay = WeChatPay()
    credit_card_pay = CreditCardPay()

    # 使用上下文类
    context = PaymentContext(alipay)
    context.pay(100)  # 使用支付宝支付

    context.set_strategy(wechat_pay)
    context.pay(200)  # 使用微信支付

    context.set_strategy(credit_card_pay)
    context.pay(300)  # 使用信用卡支付

1.4.2 Java 实现
// 抽象策略
interface PaymentStrategy {
    void pay(double amount);
}

// 具体策略:支付宝支付
class Alipay implements PaymentStrategy {
    public void pay(double amount) {
        System.out.println("Using Alipay to pay " + amount + " dollars.");
    }
}

// 具体策略:微信支付
class WeChatPay implements PaymentStrategy {
    public void pay(double amount) {
        System.out.println("Using WeChat Pay to pay " + amount + " dollars.");
    }
}

// 具体策略:信用卡支付
class CreditCardPay implements PaymentStrategy {
    public void pay(double amount) {
        System.out.println("Using Credit Card to pay " + amount + " dollars.");
    }
}

// 上下文类
class PaymentContext {
    private PaymentStrategy strategy;

    public PaymentContext(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void pay(double amount) {
        strategy.pay(amount);
    }
}

// 客户端代码
public class StrategyPatternDemo {
    public static void main(String[] args) {
        PaymentStrategy alipay = new Alipay();
        PaymentStrategy weChatPay = new WeChatPay();
        PaymentStrategy creditCardPay = new CreditCardPay();

        PaymentContext context = new PaymentContext(alipay);
        context.pay(100); // 使用支付宝支付

        context.setStrategy(weChatPay);
        context.pay(200); // 使用微信支付

        context.setStrategy(creditCardPay);
        context.pay(300); // 使用信用卡支付
    }
}

1.5 应用场景

  1. 电商平台的支付方式切换
  2. 数据压缩工具支持多种压缩算法
  3. 游戏中角色的不同技能组合
  4. 日志系统中不同的日志存储方式(如文件、数据库、云服务)

策略模式适合使用在运行时需要灵活替换算法或行为的场景,是一种极具扩展性和灵活性的设计模式。

2 Kafka 和 Spring Boot 的版本对应关系

以下是 Kafka 和 Spring Boot 的版本对应关系,基于 Spring 官方提供的兼容性指南和常见的版本使用实践:


2.1 Spring Boot 与 Kafka 的版本对应关系

Spring Boot 版本Spring for Apache Kafka 版本Apache Kafka 客户端版本备注
3.1.x3.1.x3.5.x支持最新 Kafka 3.5.x 功能
3.0.x3.0.x3.4.x支持 Kafka Streams 和最新特性
2.7.x ~ 2.6.x2.7.x2.8.x ~ 2.7.x支持 Kafka 2.8.x 和早期版本
2.5.x ~ 2.3.x2.5.x ~ 2.3.x2.5.x ~ 2.3.x通常与 Kafka 2.x 系列配合使用

2.2 如何查看具体的版本兼容性?

2.2.1 Spring Boot 官方 BOM

Spring Boot 管理 Kafka 客户端和 Spring for Apache Kafka 的版本。你可以查看 Spring Boot 的 官方 BOM 文档。

2.2.2 Spring for Apache Kafka Release Notes

Spring Kafka 文档明确了支持的 Kafka 客户端版本,例如:

2.2.3 Kafka 自身的版本支持

Kafka 客户端通常向后兼容早期的 Kafka Broker 版本,但建议尽量保持客户端和 Broker 的版本一致。


2.3 示例配置

2.3.1 Maven 配置

Spring Boot 的依赖管理通常自动匹配 Spring Kafka 和 Kafka Client 的版本。例如:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>
2.3.2 手动指定 Kafka 客户端版本

如果需要特定版本的 Kafka 客户端,可以显式声明:

<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>3.5.1</version> <!-- 根据实际需求调整 -->
</dependency>

2.4 注意事项

  1. Kafka 客户端与 Broker 的兼容性
    Kafka 客户端一般兼容同版本及以下版本的 Kafka Broker(向后兼容)。

  2. 测试环境验证
    在实际使用中,推荐使用相同版本的 Kafka 客户端和 Broker,避免潜在兼容性问题。

  3. 升级路径
    如果需要升级 Kafka 或 Spring Boot,请先查阅对应的 Release Notes,逐步升级相关依赖并进行全面测试。

3 和其他消息队列相比,kafka的优势

Kafka 相较于其他消息队列(如 RabbitMQ、ActiveMQ、Redis 等)的主要优势包括以下几个方面:


** 3.1 高吞吐量**

Kafka 设计为能够处理高吞吐量数据流,原因包括:

  • 分布式架构:Kafka 支持分区和分布式部署,能够线性扩展处理能力。
  • 顺序磁盘写入:Kafka 使用顺序磁盘写入代替随机写入,极大地提高了 I/O 性能。
  • 批量处理:支持批量消息的生产和消费,降低了网络传输和磁盘操作的开销。

3.2 高可用性和持久性

  • 复制机制:Kafka 的数据分区支持多副本,确保即使某些节点宕机,数据仍然可用。
  • 分布式存储:数据存储在磁盘中,且通过日志存储实现消息的持久化,提供了可靠性。

3.3 可扩展性

  • Kafka 的分布式架构允许无缝增加节点,通过简单的水平扩展就可以提高集群的处理能力和存储能力。

3.4 低延迟

Kafka 针对大规模实时数据流处理进行了优化,可以实现毫秒级延迟,适用于实时分析和事件处理场景。


3.5 消息顺序保证

Kafka 的分区机制确保同一分区内的消息是有序的,这对于需要严格顺序的应用场景非常重要。


3.6 灵活的消费模型

Kafka 提供了多种消费方式:

  • 多种消费模式:支持发布-订阅模式和点对点模式。
  • 消费者组:通过消费者组实现并行消费和负载均衡。

3.7 强大的生态系统

Kafka 具有强大的生态系统支持:

  • Kafka Streams:内置流式处理框架,用于处理消息流。
  • Kafka Connect:支持与各种外部系统(如数据库、文件系统)的连接。
  • 支持多语言:Kafka 提供多语言的客户端(Java、Python、Go 等)。

3.8 支持回溯和多次消费

Kafka 的消息保存在磁盘上,可配置保留时间,消费者可以通过偏移量回溯消费,不同消费者可以以不同的速度读取相同的数据。


3.9 成本效率

Kafka 的高性能使其在大多数场景下能够以较低的硬件和资源消耗处理高吞吐量的数据流。


3.10 社区活跃与企业广泛使用

Kafka 由 Apache 社区支持,生态系统和更新速度非常活跃,是大多数企业(如 LinkedIn、Uber、Netflix)在大数据和流处理场景下的首选。


3.11 对比总结

特性KafkaRabbitMQActiveMQ
吞吐量
消息持久化强(磁盘日志存储)中(需要配置)中(需要配置)
消费模式发布订阅、消费者组点对点、发布订阅点对点、发布订阅
消息顺序分区内有序无序(需要额外设置)无序(需要额外设置)
可扩展性优秀(分布式架构)一般(扩展困难)一般(扩展困难)
生态系统丰富(Kafka Streams, Kafka Connect)较少较少

Kafka 在高吞吐量、大规模实时数据处理以及复杂数据流集成场景中表现尤为突出,适合大数据平台、实时监控、日志分析等场景。

4 kafka 如何实现搞可靠性

Kafka 的可靠性来源于其独特的架构设计和多层次的保障机制,以下是 Kafka 实现高可靠性的主要原因:


4.1 数据持久化

  • 顺序写磁盘:Kafka 将消息以顺序方式写入磁盘日志,避免随机写操作的高开销,大幅提高磁盘写入效率。
  • 分段日志存储:消息日志分为多个分段文件(Segment),新消息写入最新的分段,老分段被归档或删除。
  • 零拷贝传输:利用操作系统的零拷贝技术,减少数据在内存和磁盘间的拷贝次数,提高可靠性和性能。

4.2 副本机制

  • 多副本复制:每个分区可以配置多个副本,主副本负责读写,副本用于同步数据以防主副本故障。
  • Leader 和 Follower
    • 每个分区有一个 Leader 副本,其余为 Follower 副本。
    • 只有 Leader 接受生产者和消费者的读写请求,Follower 异步同步数据。
  • ACK 确认机制
    • Kafka 提供不同的 acks 设置:
      • acks=0:生产者不等待确认,最低可靠性。
      • acks=1:Leader 确认接收到消息后返回,可靠性适中。
      • acks=all:所有 ISR 副本确认接收到消息后返回,最高可靠性。

4.3 ISR(In-Sync Replica,同步副本集)

  • ISR 是一组与 Leader 副本保持同步的 Follower 副本。
  • 只有 ISR 副本能够在 Leader 副本故障时被选为新的 Leader,保证数据一致性。
  • Kafka 定期检查副本的同步状态,滞后过大的副本会被移出 ISR。

4.4 数据分区和副本分布

  • 分区机制:每个主题被划分为多个分区,分区是 Kafka 的并发和容错基础。
  • 副本分布策略:Kafka 自动将分区副本分布在不同的 Broker 上,防止单点故障。
  • Broker 冗余:即使部分 Broker 故障,Kafka 能够继续运行,保证高可用性。

4.5 消息确认和重试机制

  • 消息确认:消费者通过提交消费位移(Offset)来确认已消费的消息。
  • 未确认消息重试:如果消费位移未提交,Kafka 不会将消息标记为已消费,消费者可以重新消费这些消息。
  • 自动恢复:生产者或消费者在故障后可通过重试机制恢复操作。

4.6 强制数据不丢失的配置

  • 配置参数
    • min.insync.replicas:指定 Leader 必须保持同步的副本数量,小于该值时拒绝写入。
    • replica.lag.time.max.ms:限制 Follower 的同步延迟时间,超时的副本会被移出 ISR。
    • unclean.leader.election.enable:是否允许未同步的副本成为 Leader。设置为 false 可以避免数据丢失。

4.7 Broker 和 Controller 的协作

  • Kafka 集群通过 ZooKeeper(或 KRaft 模式)来管理 Broker 和分区的元数据,保证分区 Leader 的选举和负载均衡的正确性。
  • Controller 负责监控 Broker 状态,并在故障发生时快速重新分配分区 Leader。

4.8 生产者和消费者的容错机制

  • 生产者重试:生产者在消息发送失败时可以自动重试,配合幂等性配置(enable.idempotence=true)防止消息重复。
  • 消费者组再平衡:消费者组支持动态成员管理,在消费者加入或退出时,分区会被重新分配,确保消费任务不会中断。

4.9 高效的日志清理策略

  • Kafka 提供基于时间或日志大小的清理策略,配合 Compact 模式实现按键去重,保持消息持久化的同时节省存储空间。

4.10 总结

Kafka 的可靠性源于其多副本机制、日志持久化、确认和重试机制等设计。通过合理配置参数(如 acks=allmin.insync.replicas),并结合分区和副本分布策略,Kafka 能够提供高度可靠的数据存储和传输保障。

;