Clay 的技术空间

用进废退 | 艺不压身

大纲

版本说明

软件版本描述
ElasticSearch7.4.2ElasticSearch 的版本
Curl7.29.0Curl 的版本

Mapping

Mapping 简介

Mapping 是用来定义文档(Document),以及它所包含的字段(Field)是如何存储和检索的,这类似创建 MySQL 数据库表时指定表的字段类型,主要作用如下:

  • 定义 Index 下的字段名
  • 定义字段类型,比如数值型、浮点型、布尔型等
  • 定义倒排索引相关的设置,比如是否索引、记录 Position 等
阅读全文 »

大纲

版本说明

软件版本描述
ElasticSearch7.4.2ElasticSearch 的版本
Curl7.29.0Curl 的版本

ElasticSearch 导入数据

学习 ES 的时候,往往需要大量的测试数据,建议导入 ES 官方 GitHub 仓库中的 JSON 数据文件,这样方便后续学习 ES 的复杂查询。首先将 ES 官方提供的 JSON 数据保存到 accounts.json 文件里,或者直接从本站下载 数据文件,然后执行以下命令批量导入数据。

1
curl -X POST -H 'Content-Type:application/json' http://127.0.0.1:9200/bank/account/_bulk --data-binary @accounts.json
阅读全文 »

大纲

版本说明

软件版本描述
ElasticSearch7.4.2ElasticSearch 的版本
Curl7.29.0Curl 的版本

ElasticSearch 介绍

ElasticSearch 概述

ElasticSearch 是基于 RESTful 标准的高扩展高可用的实时数据分析的全文搜索工具。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。ElasticSearch 是在 Lucene 的基础上用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。Elasticsearch 在云计算中,拥有实时搜索、稳定、可靠、快速、安装使用方便等优势。构建在全文检索开源软件 Lucene 之上的 Elasticsearch,不仅能对海量规模的数据完成分布式索引与检索,还能提供数据聚合分析的功能。

阅读全文 »

大纲

J2Cache 的 Gradle 配置

在项目中引入以下依赖后,需要根据项目具体的运行状况调整 Gradle 的依赖配置,以下配置使用到 SpringBoot。

1
2
3
compile 'net.oschina.j2cache:j2cache-core:2.7.6-release'
compile 'net.oschina.j2cache:j2cache-mybatis:2.7.0-release'
compile 'net.oschina.j2cache:j2cache-spring-boot2-starter:2.7.6-release'

MyBatis 使用 J2Cache

首先在 MyBatis 的全局配置文件中开启二级缓存,然后根据下面的两种情况进行配置(二选一)

1
2
3
4
<settings>
<!-- 开启二级缓存,默认false -->
<setting name="cacheEnabled" value="true"/>
</settings>
阅读全文 »

前言

Linux 环境下安装 NodeJS,可以选择手动编译安装或者直接使用编译好的二进制包来安装。如果是手动编译安装,需要安装对应版本的 gc++、python。本文适用于 Centos/Debian/Ubuntu 等 Linux 发行版系统。

NodeJS 编译安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 软件依赖
g++4.8.2
python2.6 或者 python2.7

# 下载源码压缩包
# wget https://nodejs.org/dist/v10.16.0/node-v10.16.0.tar.gz

# 解压源码压缩包
$ tar -xvf node-v10.16.0.tar.gz

# 编译安装
# cd node-v10.16.0
# ./configure --prefix=/usr/local/node-10.16.0
# make -j4
# make install

# 配置环境变量
# vim /etc/profile
export PATH=${PATH}:/usr/local/node-10.16.0/bin

# 使环境变量生效
# source /etc/profile

# 查看Node、NPM的版本
# npm -v
# node -v
阅读全文 »

控制 Quartz 只执行一次

  • 纯 API 调用的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ScheduleTest {

private static final String JOB_NAME = "job";
private static final String JOB_GROUP = "jobGroup";

public void runOnceTime() throws Exception {
Scheduler scheduler = schedulerFactory.getScheduler();
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(JOB_NAME, JOB_GROUP).build();
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(0).withRepeatCount(0);
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(JOB_NAME, JOB_GROUP).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
}
阅读全文 »

Snap 介绍

Snap 是 Ubuntu 母公司 Canonical 于 2016 年 4 月发布 Ubuntu-16.04 时引入的一种全新的、安全的、易于管理的、沙盒化的软件包管理方式,与传统的 dpkg/apt 有着很大的区别,背后主要的动机是解决 Linux 平台的碎片化问题。Snap 的安装包扩展名是 .snap,类似于一个容器,它包含一个应用程序需要用到的所有文件和库(Snap 包里包含一个私有的 root 文件系统,里面包含了依赖的软件包)。不管底层系统如何,Snap 都可轻松安装、升级、降级和移除应用,因此 Snap 的应用程序很容易安装在任何基于 Linux 的系统上,而且支持用户在同一个系统中安装同一应用程序的多个版本。使用 Snap 包的好处就是它解决了应用程序之间的依赖问题,使应用程序之间更容易管理,但是由此带来的问题就是占用更多的磁盘空间。类似的应用程序容器技术还有大名鼎鼎的 FlatpakAppImage。Snap 适用于 CentOS 7.6+ 和 Red Hat Enterprise Linux 7.6+,它很好地弥补了 Centos 桌面软件资源不多的缺点,可以从 Extra Packages for Enterprise Linux(EPEL)存储库安装。Snap 的工作原理如下图所示:

snap-framework

阅读全文 »

概述

读写分离要做的事情就是决定一条 SQL 该到哪个数据库去执行,至于谁来做决定数据库这件事,要么数据库中间件去做,要么应用程序自己去做。首先针对应用程序自己去做的场景,读写分离的职责应该属于数据访问层而不是业务层,其次读写分离不应该入侵到代码中。因此在 Service—DAO—ORM— 数据库驱动的调用链中,要想做到代码弱入侵性或者零入侵性,只能将读写分离写在 ORM 层或者数据库驱动层,写在 ORM 层就和具体 ORM 框架耦合,写在数据库驱动层,就和具体数据库耦合。至于在 ORM 层还是在数据库驱动层实现读写分离,主要看更换 ORM 框架和数据库哪个成本更高和实现的难易程度。一般来讲,读写分离的核心方案主要有以下几种:

  • 第一种构建多套环境,优势是方便控制也容易集成一些简单的分布式事务,缺点是非动态同时代码量较多,配置难度大;
  • 第二种是依靠数据库中间件(例如:MyCat),由中间件做读写分离,优势是对整个应用程序都是透明的,缺点是降低性能,不支持多数据源事务;
  • 第三种是应用程序自己去做,例如使用支持读写分离的数据库驱动、使用 Spring 原生提供的 AbstractRoutingDataSource。后者需要控制只读事务和读写事务切换到主库,写操作切换到主库,读操作切换到从库;同时保证单个事务里面所有的 SQL 都是在同一个数据源里执行。缺点是多数据源的配置不灵活,不支持多数据源事务。具体实现方式可参考 基于 Service 层的 Spring 路由数据源 + AOP / Annotation基于 ORM 层的 Spring 路由数据源 + Mybatis 插件 / Annotation
阅读全文 »

大纲

相关资源

缓存介绍

主流缓存框架

Ehcache、Caffeine 、Spring Cache、Guava Cache、JetCache、Hazelcast、Infinispan

主流缓存解决方案

  • 内存缓存(如 Ehcache、Caffeine) — 速度快,进程内可用
  • 集中式缓存(如 Redis、Memcached)— 可同时为多节点提供服务
阅读全文 »

大纲

前言

集群模式

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 的组合,可以构建一个企业级高可用消息中间件系统。

阅读全文 »