Clay 的技术空间

用进废退 | 艺不压身

大纲

前言

集群模式

RabbitMQ 是基于 Erang 开发的,集群模式分为两种,包括普通模式和镜像模式;可以说镜像模式是普通模式的升级版,其中 RabbitMQ 默认使用的是普通模式。

  • 普通模式:

    • 以两个节点(rabbit01、rabbit02)为例来进行说明,rabbit01 和 rabbit02 两个节点仅有相同的元数据,即队列的结构,但消息实体只存在于其中一个节点 rabbit01(或者 rabbit02)中。当消息进入 rabbit01 节点的 Queue 后,Consumer 从 rabbit02 节点消费时,RabbitMQ 会临时在 rabbit01、rabbit02 间进行消息传输,把 A 中的消息实体取出并经过 B 发送给 Consumer。所以,对于同一个逻辑队列,要在多个节点上建立物理队列,比如使用镜像队列或者 Quorum。换言之,如果使用的是 RabbitMQ 默认队列,Consumer 一定要尽量直连到队列所在的节点,才能避免跨节点传输带来的性能问题。否则,无论 Consumer 连接 rabbit01 还是 rabbit02,出口总在 rabbit01,会产生性能瓶颈。另外,当 rabbit01 节点故障后,rabbit02 节点无法取到 rabbit01 节点中还未消费的消息实体。如果做了消息持久化,那么得等 rabbit01 节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
  • 镜像模式:

    • 在普通模式的基础上,通过镜像队列策略(HA Policy)将需要的队列配置成镜像队列,让队列存储在多个节点上,消息实体会主动在镜像节点之间同步,而不是在客户端取数据时临时拉取,也就是说有多少个镜像节点消息就会备份多少份。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉,所以在对业务可靠性要求较高的场合中适用。由于镜像队列之间消息自动同步,且内部有选举 Master 机制,即使 Master 节点宕机也不会影响整个集群的使用,达到去中心化的目的,从而有效的防止消息丢失及服务不可用等问题

集群节点

RabbitMQ 的集群节点分为磁盘节点、内存节点。RabbitMQ 支持消息的持久化,也就是数据写在磁盘上。在 RabbitMQ 集群中,必须至少有一个磁盘节点,否则队列元数据无法写入到集群中。当磁盘节点宕掉时,集群将无法写入新的队列元数据信息。如果 RabbitMQ 集群全部宕机,必须先启动磁盘节点,然后再启动内存节点。最合适的方案就是既有磁盘节点,又有内存节点;建议至少 2 个磁盘节点,其他节点可以作为内存节点来提高性能,比如采用 2 个 磁盘节点 + 1 个内存节点的集群搭建方式。

节点类型节点特点
disc(磁盘节点)元数据持久化到磁盘,集群元数据(如队列、交换机、绑定、用户、权限的定义等)会复制到这些节点上。至少需要一个 disc 节点才能组成完整的 RabbitMQ 集群。
ram(内存节点)大部分集群元数据仅保存在内存中,性能更高。启动时会从磁盘节点同步元数据,但自身不会持久化元数据。一旦内存节点宕机或重启,它的元数据就会丢失(除非从磁盘节点重新同步)。掉电就丢失元数据,不适合长期存储,只适合当辅助节点使用

磁盘节点补充说明

  • RabbitMQ 默认的集群节点类型是 disc(磁盘节点),至少需要一个 disc 节点才能组成完整的 RabbitMQ 集群。

内存节点补充说明

  • ram(内存节点)决定的是 RabbitMQ 的集群元数据保存在内存中,元数据包括队列、交换机、绑定、用户、权限的定义等,而不是决定队列和消息都存储在内存里面,也就是消息的存储还是由队列持久化、消息持久化决定的。
  • 假设在 RabbitMQ 的一个内存节点上创建了队列,如果这个节点宕机,它的元数据就没了,重启后队列的定义也不存在。但是,如果将队列设置为持久化(durable=true),消息也设置为持久化(delivery_mode=2),即使内存节点宕机了,只要还有磁盘节点存在,就可以恢复内存节点的队列和消息数据。

集群架构

RabbitMQ 集群的典型架构如下图所示,展示了如何通过多个节点实现高可用和负载均衡。这种架构可以有效地提高 RabbitMQ 的吞吐量和容错能力,适用于对消息可靠性和系统可用性要求较高的生产环境。架构说明如下:

  • 客户端连接:​客户端通过虚拟 IP(VIP)连接到集群,VIP 由 Keepalived 管理,实现高可用性。
  • 负载均衡:​HAProxy 作为负载均衡器,将客户端请求分发到后端的 RabbitMQ 节点。在 HAProxy 的配置中启用健康检查后,HAProxy 可以感知到 RabbitMQ 节点的宕机,并自动将其从负载均衡列表中剔除。
  • RabbitMQ 节点:​多个 RabbitMQ 节点组成集群,节点之间通过镜像队列(Mirrored Queue)机制同步消息,确保消息的高可用性。

提示

由于篇幅有限,本文只介绍如何使用多机搭建 RabbitMQ 集群,不再介绍如何使用 Keepalived + HAProxy 来实现 RabbitMQ 集群的负载均衡,可以参考这里的 Keepalived + HAProxy 使用教程。

重要提示

无论 RabbitMQ 集群是运行在普通模式,还是启用了镜像模式(使用镜像队列),客户端(包括生产者和消费者)都可以直接连接到集群中的任意节点进行消息的发送与接收(类似于无状态设计)。RabbitMQ 集群节点之间通过内部通信机制来保持数据同步和状态一致,从而对客户端屏蔽了具体的队列位置,使得客户端无需关心消息实际存储在哪个节点上,连接任一节点即可正常使用。这就是为什么可以使用 Keepalived + HAProxy 来实现 RabbitMQ 高可用负载均衡集群的原因。若希望进一步提高可用性,推荐使用 RabbitMQ 的 Quorum Queue + Keepalived + HAProxy + Prometheus + AlertManager 的组合,可以构建一个企业级高可用消息中间件系统。

阅读全文 »

学习资源

RabbitMQ 的基础概念

AMQP(Advanced Message Queuing Protocol)高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。AMQP 的主要特征是面向消息、队列、路由(包括点对点和发布 / 订阅)、可靠性、安全。RabbitMQ 是一个开源的 AMQP 标准实现,服务器端用 Erlang 语言编写,支持多种客户端,如:Python、Ruby、C#、Java、PHP、GO、JavaScript 等。RabbitMQ 用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具、插件系统等方面表现不俗。

阅读全文 »

微服务与微服务架构

微服务的概述

微服务理论的提出者马丁。福勒(Martin Fowler) 在其博客中详细描述了什么是微服务。微服务强调的是服务的大小,它关注的是某一个点,是具体解决某一个问题 / 提供落地对应服务的一个服务应用;狭意的看,可以看作 Eclipse 里面的一个个微服务工程 / 或者 Module。

微服务架构的概述

微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分为一组小服务,每个服务运行在自己的独立进程中,服务间通信采用轻量级通信机制 (通常是基于 HTTP 的 RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应该尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储技术。

阅读全文 »

前言

本文适用于 CentOS/Debian/Ubuntu 等 Linux 发行版系统。

JDK 安装

由于 Gradle 的运行依赖于 JDK,但是安装 Oracle JDK 不是必需的,如果不想安装可以使用 Open-JDK 替代,而且大多数 Linux 发行版自带 Open-JDK。

阅读全文 »

大纲

MyBatis 实用场景

MyBatis 批量操作

调用不带参数的 openSession() 方法时,创建的 SqlSession 对象具有如下特性:

  • 会开启一个事务(不会自动提交)
  • 数据库连接对象会从由环境配置的数据源实例得到
  • 事务隔离级别将会使用驱动或数据源的默认配置
  • 预处理语句不会被复用,也不会批量处理更新

值得一提的是,openSession() 方法的 ExecutorType 类型的参数是枚举类型,取值如下:

  • SIMPLE:这个执行器类型不做特殊的事情(默认执行器),它会为每个 SQL 语句的执行创建一个新的预处理语句。
  • REUSE:这个执行器类型会复用预处理语句。
  • BATCH:这个执行器会批量执行所有更新语句。
阅读全文 »

基于 ZooKeeper 实现分布式锁

  • 由于下面使用了 Curator 客户端,因此需要引入相应的依赖
1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.5.0</version>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.5.0</version>
</dependency>
阅读全文 »

大纲

MyBatis 四大对象

四大对象介绍

MyBatis 的四大对象包括:Executor、StatementHandler、ParameterHandler、ResultSetHandler。四大对象的工作职责如下:

  • Executor(执行器):负责整个 SQL 执行过程的总体控制
  • StatementHandler(语句处理器):负责和 JDBC 层交互,包括预编译 SQL 语句和执行 SQL 语句,以及调用 ParameterHandler 设置参数
  • ParameterHandler(参数处理器):负责设置预编译参数
  • ResultSetHandler(结果集处理器):负责将 JDBC 查询结果映射到 JavaBean 对象
阅读全文 »

大纲

缓存机制

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。MyBatis 中默认定义了两级缓存:

  • 一级缓存和二级缓存
    • 默认情况下,只有一级缓存(SqlSession 级别的缓存,也称为本地缓存)开启
    • 二级缓存需要手动开启和配置,它是基于 namespace 级别的缓存
    • 为了提高扩展性,MyBatis 定义了缓存接口 Cache,可以通过实现 Cache 接口来自定义二级缓存
阅读全文 »