- 博客(352)
- 资源 (1)
- 收藏
- 关注
原创 Spring线程池优雅关闭
线程池大家一定不陌生,常被用来异步执行一些耗时的任务。但是线程池如何优雅的关闭,却少有人关注。当 JVM 进程关闭时,你提交到线程池的任务会被如何处理?如何保证任务不丢?
2025-01-03 17:16:49
1024
原创 Dubbo分布式日志跟踪实现
随着越来越多的应用逐渐微服务化后,分布式服务之间的RPC调用使得异常排查的难度骤增,最明显的一个问题,就是整个调用链路的日志不在一台机器上,往往定位问题就要花费大量时间。如何在一个分布式网络中把单次请求的整个调用日志给串起来,变得刻不容缓。
2024-11-11 20:08:17
1287
原创 Dubbo Telnet服务追踪源码分析
Dubbo 的 Telnet 特性允许开发者通过 Telnet 客户端直接连接到 Dubbo 服务提供者,执行一系列命令以获取服务状态、调试信息和进行服务管理。这种特性在开发和运维过程中非常有用,尤其是在需要快速定位问题或查看服务状态时。本文介绍 Telnet 中最为常用的 trace 命令,它可以追踪服务提供者的某个服务的某个方法,把服务调用的入参出参以及执行耗时输出到 Telnet 客户端。
2024-11-04 19:29:24
459
原创 基于Flink MySQL CDC技术实现交易告警
CDC 的全称是 Change Data Capture,是一种用于捕获数据库变更数据的技术。例如 MySQL 对数据的所有变更都会写入到 binlog,CDC 就可以通过监听 binlog 文件来实现对 MySQL 数据变更的捕获,然后做进一步的处理。Flink CDC 将CDC技术和 Flink 流计算整合到一起,把CDC捕获到的数据变更作为 Flink数据源,以实现对数据变更的流式处理。
2024-10-15 16:45:58
1409
2
原创 Flink状态一致性保证
一个Flink作业由一系列算子构成,每个算子可以有多个并行实例,这些实例被称为 subTask,每个subTask运行在不同的进程或物理机上,以实现作业的并行处理。在这个复杂的分布式场景中,任何一个节点故障都有可能导致 Flink 作业宕机,Flink 状态本地化虽然可以实现极致的访问速度,但是节点故障后的状态恢复问题也是Flink必须要解决的。
2024-10-15 16:45:12
1291
原创 Flink算子状态为何只能用ListState?
Flink 将状态是否要按照 key 进行分类,将状态分为键值状态(Keyed State)和算子状态(Operator State)两种,两者除了状态本身的作用域不同外,其中算子状态的状态类型更是被 Flink 限制为 ListState,这是为什么呢?
2024-10-15 16:44:33
1357
原创 Flink有状态计算
状态是什么?状态就是数据,准确点说,状态是指 Flink 作业计算时依赖的历史数据或中间数据。如果一个 Flink 作业计算依赖状态,那它就是有状态计算的作业,反之就是无状态计算的作业。举个例子,服务端应用为了方便扩缩容,一般会设计成无状态的,但是对外服务的接口又是有状态的,这是因为服务端应用本身不存储数据,数据存储在关系型或非关系型数据库中,此时的“状态”就从服务端迁移到数据库中了。Flink 同理,一个稍微复杂一点的作业,基本都会使用到状态。
2024-10-15 16:44:01
1376
原创 Flink双流时间窗口联接
Flink 除了可以在一条数据流上使用各种时间窗口算法来处理数据,还支持两条数据流上的一段时间窗口内的数据进行联接操作,类似于SQL中的 join 操作。
2024-10-15 16:43:27
917
原创 Flink移除器Evictor
实现接口即可自定义 Evictor,泛型要注意,第一个是元素类型,第二个是窗口类型。举个例子,我们定义一个 Evictor,它在 ProcessFunction 计算前把窗口内所有的奇数全部移除掉,只保留偶数。@Override= 0) {@Override编写一个简单的 Flink 作业验证一下我们自定义的 Evictor,数据源手动指定为数字1到6,统一分配到 GlobalWindow 窗口,Trigger 元素等于6个就出发计算,最终输出窗口内的元素@Override});
2024-10-15 16:42:44
801
原创 Flink触发器Trigger
通过子类继承 Trigger 重写相应的方法,即可自定义我们自己的触发器。举个例子,我们自定义一个和时间不相关的 Trigger,我们等窗口积攒到一定数量的元素再出发计算。@Override// 通过Flink state来保存窗口内积攒的元素数量@Override@Override@Override接下来验证一下我们的Trigger是否生效。
2024-10-15 16:41:33
1300
原创 Flink窗口分配器WindowAssigner
窗口对象被 Flink 统一封装为抽象类TimeWindow 基于时间范围的窗口,包含开始时间戳和结束时间戳GlobalWindow 全局窗口,与时间无关的窗口如果内置的这两种窗口无法满足你的需求,你也可以自定义窗口。需要注意的是,窗口本身是要在算子间传输的,所以你在自定义窗口的同时,还必须提供一个窗口序列化器,以便于 Flink 可以将你的窗口对象序列化传输。如下示例,我们定义了一个基于数字范围的 NumberWindow,可以将一个数字划分到对应的数字范围窗口内。return min;
2024-10-15 16:41:02
1075
原创 Flink时间窗口程序骨架结构
Flink 作业的基本骨架结构包含三部分:创建执行环境、定义数据处理逻辑、提交并执行Flink作业。日常大部分 Flink 作业是基于时间窗口计算模型的,同样的,开发一个Flink时间窗口作业也有一套基本的骨架结构,了解这套结构有助于我们更快地上手时间窗口作业开发。
2024-10-15 16:40:32
1659
原创 Flink事件时间和Watermark
内置 WatermarkGenerator 不满足需求时,也可以自定义Watermark生成策略。如果数据本身携带 Watermark 标志,那么可以重写 onEvent() 来发送 Watermark。@Override// 假设数据格式中 字符串W开头是Watermark,其中f1是时间戳@Override// NOOP如果数据本身没有Watermark标志,我们也可以直接根据系统时钟,周期性的发送 Watermark。
2024-10-15 16:39:59
1369
原创 Flink时间语义和时间窗口
在实际的流计算业务场景中,我们会发现,数据和数据的计算往往都和时间具有相关性。归纳总结可以发现,这些和时间相关的数据计算可以统一用一个计算模型来描述:每隔一段时间,计算过去一段时间内的数据,并输出结果。这个计算模型,就是时间窗口。
2024-10-15 16:39:19
1750
原创 Flink作业骨架结构
Flink是大数据流计算引擎,本质上是对大数据的计算处理,那么首先要解决的问题是:数据从哪儿来?解决这个问题,就是给Flink作业定义数据源,数据源被抽象成了 SourceFunction 接口,实现该接口重写 run 方法即可接收数据。有了数据,接下来就是声明要对这些数据做哪些处理?对数据的处理被抽象成了 ProcessFunction 接口,实现该接口重写 processElement 方法即可处理一条条数据。常见的数据处理操作有:过滤、转换、聚合等。
2024-10-15 16:38:35
1399
原创 初识Flink
伴随现代信息技术的持续发展,我们能清晰地察觉到,信息生产的规模不断扩张,信息更新的速率持续攀升。以电商系统为例,用户从搜索商品到下单支付,整个链路可能短短几秒就可以完成,倘若能在这条链路里更迅速地分析与挖掘出价值更高的信息,便能取得优势地位。在这种需求推动的宏大背景下,各类批处理、流处理引擎得以快速发展,其中 Apache Flink 更是成为后来居上的佼佼者。
2024-10-15 16:37:50
902
原创 Elasticsearch查询类型
搜索是Elasticsearch最核心的功能之一,它能够在海量数据中精准、快速地召回我们期望的文档。Elasticsearch支持各种复杂的条件搜索,查询类型之多,往往让新手一头雾水。甚至同一个搜索需求,可以用不同的查询类型来实现,但是效率却天差地别,理解Elasticsearch提供的各种查询类型,可以帮助我们更好的搜索我们的数据。
2024-10-15 16:36:25
1500
原创 Elasticsearch文档操作
Elasticsearch索引是一组相关文档的集合,文档在Elasticsearch中用JSON来表示,每个文档都有一个唯一的”_id“字段来标识。每个文档又是一组字段的集合,字段可以有自己的数据类型,可以是数字、字符串、日期、布尔类型等,Elasticsearch可以索引文档,并对索引的文档做检索和数据分析。
2024-10-15 16:35:40
1197
原创 Elasticsearch Ingest Pipelines
在将第三方数据源的数据导入到Elasticsearch中时,原始数据长什么样,索引后的文档就是什么样。文档数据结构不统一,导致后续数据分析时变得麻烦,以往需要额外写一个中间程序来读取原始数据,转换加工后再写入到Elasticsearch,比较麻烦,于是官方推出了Ingest pipeline。Ingest pipeline 允许文档在被索引之前对数据进行预处理,将数据加工处理成我们需要的格式,例如删除或增加一些字段等。
2024-10-15 16:34:34
1485
原创 Elasticsearch文本分析器
Elasticsearch规定,任何分析器都由0个或多个字符过滤器、1个分词器、0个或多个分词过滤器组成,官方内置了大量的基础组件,同时又基于这些基础组件定义了一堆内置的分析器。如果这些内置分析器不能够满足我们的需求,我们也可以任意搭配组合定制化一个分析器。假设,我们现在创建一个questions索引,用来索引问题,然后可以根据关键词搜索问题。question字段使用text类型,同时使用我们自定义的文本分析器my_analyzer。自动过滤掉文本中的标点符号简单点,针对“/"符号来做分词吧。
2024-10-15 16:23:46
1083
原创 Elasticsearch字段数据类型
ES文档的每个字段都至少有一个数据类型,此类型决定了字段值如何被存储以及检索。例如,字符串类型可以定义为text或者keyword,前者用于全文检索,会经过分词后索引;后者用于精准匹配,值会保持原样被索引。ES字段类型按族分组,同一族中的类型具有完全相同的搜索行为,但可能具有不同的空间使用或性能特征。
2024-10-15 16:22:55
2504
原创 Elasticsearch索引映射定义
索引是文档的集合,文档是字段的集合,每个字段都有自己的数据类型。在映射数据时,需要创建一个映射定义,其中包含与文档相关的字段列表。映射定义还包括元数据字段,如_source字段,它自定义如何处理文档的关联元数据。
2024-07-16 08:55:15
1252
原创 Java线程池execute和submit的区别
ThreadPoolExecutor提供了两种方法来执行异步任务,分别是execute和submit,也是日常开发中经常使用的方法,那么它俩有什么区别呢?
2024-06-04 16:44:25
1705
1
原创 Elasticsearch索引定义
在索引文档前,首先需要定义索引。包括:索引名称、索引设置、索引映射、别名、分析器等。如下示例,我们创建了一个名称为“student”的索引,它拥有1个分片数和1个副本数;在索引映射里我们定义了三个字段分别是:学号 student_id、姓名 name、性别 gender,字段类型都是keyword,用于精准匹配;同时该索引还有一个别名:student_alias。
2024-04-30 16:23:18
2036
2
原创 Elasticsearch快速上手
索引是文档的容器,就像关系数据库中,要存储行记录必须先创建数据库和表一样。ES6 及之前的版本还存在”类型“的概念,一个索引下可以存储多个类型的文档,但是不同类型下的文档却不是相互独立的,这些文档同属于一个 Lucene 索引,仅通过_type字段做逻辑区分,导致不同类型下的相同字段名无法实现不同的数据类型而出现问题,于是 ES7 废弃了类型的概念,ES8 彻底移除了类型。文档是可以被索引的最小信息单元,相当于关系数据库中的行记录。文档由若干个字段(Field)组成,每个字段是一个键值对。
2024-04-07 18:18:01
1252
原创 Spring事件监听机制
Spring 的事件监听机制,采用了观察者的设计模式。一套完整的事件监听流程是这样的,首先定义事件类,即ApplicationEvent的子类,它包含事件发生的时间戳timestamp和产生事件的来源source,以及自定义的其它事件属性;然后实现事件监听器 ApplicationListener 并注册到容器,订阅感兴趣的事件,Spring 会在事件发生时触发监听器;最后通过事件发布器 ApplicationEventPublisher 发布自定义事件。
2024-03-04 19:41:11
1299
1
原创 基于Redis商品库存扣减方案
电商业务场景下,对于库存的处理是比较重要的,表面上看只是对商品库存数做一个扣减操作,但是要做到不超卖、不少卖,同时还要保证高性能,却是一件非常困难的事。
2024-02-22 17:10:23
2103
原创 Spring Bean的生命周期
Spring Bean 是 Spring IOC 容器负责实例化、组装和管理的对象,它和普通的 Java 对象并没有什么区别,唯一的区别就是它不是由开发人员自己 new 出来的,而是由容器负责创建的。IOC 容器除了实例化对象,还会负责管理对象之间的依赖关系,自动注入依赖和属性,甚至创建代理对象来对原始对象进行增强。生命周期是一个对象从创建到被销毁经历的整个过程,普通Java对象的生命周期是JVM分配内存,调用构造函数实例化对象,当该对象没有被引用后再由GC负责销毁并释放内存。
2024-02-18 20:33:50
2493
1
原创 Redis分布式可重入锁实现方案
在单进程环境下,要保证一个代码块的同步执行,直接用关键字或即可。在分布式环境下,要保证多个节点的线程对代码块的同步访问,就必须要用到分布式锁方案。分布式锁实现方案有很多,有基于关系型数据库行锁实现的;有基于ZooKeeper临时顺序节点实现的;还有基于 Redis setnx 命令实现的。本文介绍一下基于 Redis 实现的分布式锁方案。
2024-02-18 15:03:32
2400
原创 ThreadLocalMap为什么用线性探测解决哈希冲突
ThreadLocal 本身不存储值,访问的是当前线程 ThreadLocalMap 里存储的数据副本,实现了线程间的数据隔离。只有当前线程能访问,也就不存在并发访问时的安全问题了。ThreadLocal 的核心是 ThreadLocalMap,它和 HashMap 不同的是:面对哈希冲突时,后者用的是链表法,而前者用的是线性探测法,为什么呢???
2024-01-19 11:33:26
1108
1
原创 自定义Dubbo RPC通信协议
然后是定义grpc的 Service 和消息格式DispatcherService.proto 请求分发服务的定义RequestData.proto 请求消息的定义,主要是对 Invocation 的描述ResponseData.proto 响应消息的定义,主要是对 AppResponse 的描述使用插件把 proto 文件生成对应的 Java 类。
2024-01-18 08:42:07
1510
原创 Dubbo分层设计之Protocol层
Dubbo 框架采用分层设计,自上而下共分为十层。最底下的 Serialize 层关心的是如何序列化对象、往上的 Transporte 层关心的是如何把数据传输到远程、再往上的 Exchange 层关心的则是如何实现 请求-应答 消息交换模式、再往上就是 Protocol 层,它关心的是如何封装 RPC 调用,屏蔽底层细节。
2024-01-18 08:41:16
1294
原创 Dubbo分层设计之Exchange层
Dubbo Exchanger 也可以基于 SPI 一键替换,我们实现一个自定义的 Exchanger,加深理解。首先,我们新建一个模块,并引入依赖:
2024-01-17 19:44:42
1060
原创 基于JavaSocket重写Dubbo网络传输层
新建一个模块用来封装我们自己的传输层实现。因为要写的是 Dubbo 传输层的一个实现策略,所以要依赖
2024-01-17 19:44:03
1062
原创 Dubbo分层设计之Transport层
Dubbo 框架采用分层设计,最底下的 Serialize 层负责把对象序列化为字节序列,再经过 Transport 层网络传输到对端。一次 RPC 调用,在 Dubbo 看来其实就是一段请求报文和一段响应报文的传输过程。
2024-01-15 11:14:26
1155
原创 Dubbo分层设计之Serialize层
Serialization 被设计成 SPI 接口,所以它可以很轻松的被替换。接下来,我们就基于 Fastjson2 写一个序列化模块,替换掉默认的 hessian2,让你对整个序列化过程理解的更加清楚。首先,我们新建一个模块。因为我们要依赖 Dubbo 提供的接口去实现一套新的序列化组件,所以自然要引入模块。又因为我们是基于 fastjson2 实现的,所以也得引入 fastjson2 的依赖。
2024-01-15 11:12:22
1186
原创 Spring Boot Starter设计实现
Starter 是 Spring Boot 非常重要的一个硬核功能。通过 Starter 我们可以快速的引入一个功能或模块,而无须关心模块依赖的其它组件。关于配置,Spring Boot 采用“约定大于配置”的设计理念,Starter 一般都会提供默认配置,只有当我们有特殊需求的时候,才需要在里进行单独配置以覆盖掉默认配置。例如,我们开发一个 Web 应用,需要用到 Spring MVC、Tomcat 等组件,我们只需要依赖。
2024-01-11 16:52:27
752
原创 SpringBoot内嵌Tomcat启动流程
Spring MVC 让开发者不用了解 Servlet 细节,专注于 Controller 编写 API 接口。Spring Boot 更是采用约定大于配置的设计思想,通过内嵌 Tomcat 的方式让开发者可以快速构建并部署一个 Web 应用。怎么做到的呢?
2024-01-11 16:51:12
1125
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人