MST

星途 面试题库

面试题:Java观察者模式在复杂分布式系统消息传递架构中的应用与权衡

假设要构建一个复杂的分布式系统,涉及多个微服务之间基于Java观察者模式进行消息传递,且对消息的可靠性、一致性和性能都有极高要求。请详细描述你将如何设计整体架构,包括如何选择合适的消息队列,怎样处理观察者的动态注册与注销,以及在这个过程中需要做出哪些权衡。
21.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

整体架构设计

  1. 分层架构
    • 表现层:负责接收外部请求,进行初步的请求验证和参数处理,然后将请求转发给业务逻辑层。
    • 业务逻辑层:实现各个微服务的核心业务逻辑。每个微服务专注于特定的业务功能,如用户管理、订单处理等。这里会基于Java观察者模式实现消息的发布与订阅逻辑。
    • 数据访问层:负责与数据库等持久化存储进行交互,完成数据的读取、写入、更新和删除操作。
  2. 通信机制
    • 采用RESTful API作为微服务之间的主要通信方式,因为它具有良好的通用性、可扩展性和易于理解性。对于消息传递,结合Java观察者模式,使用消息队列作为中间件来实现异步通信。

消息队列选择

  1. Kafka
    • 可靠性:Kafka通过多副本机制保证数据的可靠性。每个分区可以配置多个副本,其中一个为领导者副本,其他为追随者副本。当领导者副本出现故障时,追随者副本可以自动选举出新的领导者,确保数据不丢失。
    • 一致性:Kafka采用ISR(In - Sync Replicas)机制来保证一致性。只有ISR中的副本才会被认为是同步的,生产者发送消息到Kafka时,会等待ISR中的所有副本都确认收到消息后才认为消息发送成功,从而保证了消息的一致性。
    • 性能:Kafka具有高吞吐量的特性,它采用顺序读写磁盘的方式,并且支持批量处理消息,能够在高并发场景下保持高效的性能。
  2. RabbitMQ
    • 可靠性:RabbitMQ支持持久化消息,即消息可以被存储在磁盘上,即使RabbitMQ服务器重启,消息也不会丢失。同时,它提供了确认机制,生产者可以确认消息是否被成功投递到队列中。
    • 一致性:通过镜像队列的方式,RabbitMQ可以保证在多个节点之间数据的一致性。镜像队列会将消息复制到多个节点上,当主节点出现故障时,从节点可以继续提供服务。
    • 性能:RabbitMQ在处理小消息、低延迟场景下表现出色。它采用AMQP协议,具有较好的通用性和灵活性。

综合考虑,如果系统对吞吐量要求极高,且对一致性的要求可以在一定程度上容忍最终一致性,Kafka是一个不错的选择;如果系统对消息的可靠性和一致性要求非常严格,对性能要求相对不是极端高,RabbitMQ更为合适。

观察者的动态注册与注销

  1. 注册机制
    • 定义一个注册中心,例如使用Spring Cloud Eureka。微服务启动时,会向注册中心注册自己的信息,包括服务名称、IP地址、端口等。
    • 观察者微服务通过调用注册中心的API,将自己感兴趣的主题(消息类型)以及自身的回调接口注册到消息发布者所在的微服务。消息发布者维护一个观察者列表,用于存储所有注册的观察者。
  2. 注销机制
    • 观察者微服务可以通过调用注册中心的API,将自己从注册中心注销。同时,它也需要通知消息发布者微服务,将自己从观察者列表中移除。
    • 消息发布者在接收到注销请求后,会从观察者列表中删除对应的观察者信息,确保后续不再向该观察者发送消息。

权衡

  1. 可靠性与性能
    • 可靠性优先:选择如RabbitMQ这样具有强大消息持久化和确认机制的消息队列,可以确保消息不丢失,但可能会因为磁盘I/O和复杂的确认流程而牺牲一定的性能。
    • 性能优先:使用Kafka可以获得高吞吐量,但在某些情况下,如网络分区时,可能会出现短暂的数据不一致问题。
  2. 一致性与可用性
    • 一致性优先:在使用Kafka时,通过配置较高的ISR副本数量和严格的确认机制,可以提高一致性,但可能会降低系统的可用性,因为更多的副本同步需要更多的网络和磁盘I/O资源,增加了节点故障的概率。
    • 可用性优先:适当降低对一致性的要求,如减少Kafka的ISR副本数量或采用RabbitMQ的普通队列模式(非镜像队列),可以提高系统的可用性,但可能会在某些情况下出现数据不一致的情况。
  3. 动态注册与注销的复杂度
    • 实现动态注册与注销机制,虽然提高了系统的灵活性,但增加了系统的复杂度。例如,注册中心的维护和管理需要额外的资源和精力,同时,微服务之间的交互也变得更加复杂,需要处理注册、注销过程中的各种异常情况。