- 博客(145)
- 资源 (2)
- 收藏
- 关注
原创 经典排序算法
它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。
2025-05-07 15:11:37
1072
原创 爬楼梯-递归版
原始递归解法:O(2^n) 时间,O(n) 空间(调用栈)记忆化递归:O(n) 时间,O(n) 空间迭代解法:O(n) 时间,O(n) 空间空间优化迭代:O(n) 时间,O(1) 空间最优选择是空间优化迭代解法,它同时具有最佳的时间和空间复杂度。
2025-04-30 16:01:28
158
原创 搭建基于Kafka的企业级实时日志流处理平台
它是一行 Nginx 日志,只不过 Connect 组件在读取它后,会把它包装成 JSON 格式发送到 Kafka,因此,我们需要借助 Gson 来帮助我们把 JSON 串还原为 Java 对象,这就是我在代码中创建 LogLine 类的原因。从图中我们可以看到,日志先从 Web 服务器被不断地生产出来,随后被实时送入到 Kafka Connect 组件,Kafka Connect 组件对日志进行处理后,将其灌入 Kafka 的某个主题上,接着发送到 Kafka Streams 组件,进行实时分析。
2025-04-30 01:00:00
1333
原创 Kafka副本机制详解
根据 Kafka 副本机制的定义,同一个分区下的所有副本保存有相同的消息序列,这些副本分散保存在不同的 Broker 上,从而能够对抗部分 Broker 宕机带来的数据不可用。在实际生产环境中,每台 Broker 都可能保存有各个主题下不同分区的不同副本,因此,单个 Broker 上存有成百上千个副本的现象是非常正常的。
2025-04-30 00:45:00
617
原创 16个SpringBoot 扩展接口
一般情况下,Spring通过反射机制利用bean的class属性指定支线类去实例化bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在bean中提供大量的配置信息。使用场景:用户可以扩展这个类,来为要实例化的bean作一个代理,比如为该对象的所有的方法作一个拦截,在调用前后输出一行log,模仿。可以看到,该类用于执行各种驱动接口,在bean实例化之后,属性填充之后,通过执行以上红框标出的扩展接口,来获取对应容器的变量。这里重点是要关注下这个标准的触发点,这个触发点是在。
2025-04-30 00:15:00
1591
原创 消费者组消费进度监控
对于 Kafka 消费者来说,最重要的事情就是监控它们的消费进度了,或者说是监控它们消费的滞后程度。这个滞后程度有个专门的名称:消费者 Lag 或 Consumer Lag。。比方说,Kafka 生产者向某主题成功生产了 100 万条消息,你的消费者当前消费了 80 万条消息,那么我们就说你的消费者滞后了 20 万条消息,即 Lag 等于 20 万。通常来说,Lag 的单位是消息数,而且我们一般是在主题这个级别上讨论 Lag 的,但实际上,Kafka 监控 Lag 的层级是在分区上的。
2025-04-29 00:30:00
1088
原创 位移提交Committing Offsets
现在,我们假设提交位移之后的 3 秒发生了 Rebalance 操作。对于常规性、阶段性的手动提交,我们调用 commitAsync() 避免程序阻塞,而在 Consumer 要关闭前,我们调用 commitSync() 方法执行同步阻塞式的位移提交,以确保 Consumer 关闭前能够保存正确的位移数据。提交位移主要是为了表征 Consumer 的消费进度,这样当 Consumer 发生故障重启之后,就能够从 Kafka 中读取之前提交的位移值,然后从相应的位移处继续消费,从而避免整个消费过程重来一遍。
2025-04-29 00:15:00
992
原创 位移主题consumer_offsets
自动提交位移有一个显著的优点,就是省事,你不用操心位移提交的事情,就能保证消息消费不会丢失。,用户不能修改,也就是说你不能随意地向这个主题写消息,因为一旦你写入的消息不满足 Kafka 规定的格式,那么 Kafka 内部无法成功解析,就会造成 Broker 的崩溃。但是,ZooKeeper 其实并不适用于这种高频的写操作,因此,Kafka 社区自 0.8.2.x 版本开始,就在酝酿修改这种设计,并最终在新版本 Consumer 中正式推出了全新的位移管理机制,自然也包括这个新的位移主题。
2025-04-28 10:49:54
1028
原创 消费者详解
发布 / 订阅模型倒是允许消息被多个 Consumer 消费,但它的问题也是伸缩性不高,因为每个订阅者都必须要订阅主题的所有分区。举个简单的例子,假设一个 Consumer Group 订阅了 3 个主题,分别是 A、B、C,它们的分区数依次是 1、2、3,那么通常情况下,为该 Group 设置 6 个 Consumer 实例是比较理想的情形,因为它能最大限度地实现高伸缩性。Consumer Group 订阅了多个主题后,组内的每个实例不要求一定要订阅主题的所有分区,它只会消费部分分区中的消息。
2025-04-28 10:49:18
272
原创 幂等生产者和事务生产者
在 0.11 之后,指定 Producer 幂等性的方法很简单,仅需要设置一个参数即可,即 props.put(“enable.idempotence”, ture),或props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)。其次,它只能实现单会话上的幂等性,不能实现跨会话的幂等性。看上去,幂等性 Producer 的功能很酷,使用起来也很简单,仅仅设置一个参数就能保证消息不重复了,但实际上,我们必须要了解幂等性 Producer 的作用范围。
2025-04-28 10:48:42
572
原创 透视HTTP
看上去好像很多,但互联网的快速发展让地址的分配管理很快就“捉襟见肘”。因为IP协议定义了“IP地址”的概念,所以就可以在“链接层”的基础上,用IP地址取代MAC地址,把许许多多的局域网、广域网连接成一个虚拟的巨大网络,在这个网络里找设备时只要把IP地址再“翻译”成MAC地址就可以了。URI另一个更常用的表现形式是URL(Uniform Resource Locator),统一资源定位符,也就是我们俗称的“网址”,它实际上是URI的一个子集,不过因为这两者几乎是相同的,差异不大,所以通常不会做严格的区分。
2025-04-28 10:46:02
786
原创 MySQL 日志:undo log、redo log、binlog
具体更新一条记录 UPDATE t_user SET name = "xiaolin" WHERE id =1 的流程如下:1.执行器负责具体执行,会调用存储引擎的接口,通过主键索引树搜索获取 id=1这一行记录如果 id=1这一行所在的数据页本来就在 buffer pool 中,就直接返回给执行器更新;如果记录不在 buffer pool,将数据页从磁盘读入到 buffer pool,返回记录给执行器如果一样的话就不进行后续更新流程;
2025-04-15 14:38:25
759
原创 如何制造出死锁
两个事务即使生成的间隙锁的范围是一样的,也不会发生冲突,因为间隙锁目的是为了防止其他事务插入数据,因此间隙锁与间隙锁之间是相互兼容的。在执行插入语句时,如果插入的记录在其他事务持有间隙锁范围内,插入语句就会被阻塞,因为插入语句在碰到间隙锁时,会生成一个插入意向锁,然后插入意向锁和间隙锁之间是互斥的关系。
2025-04-15 14:37:51
749
原创 MySQL是怎么加锁的
当查询的记录是「存在」的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock 会退化成「记录锁」。当查询的记录是「不存在!的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的next-key lock 会退化成「间隙锁」当查询的记录「存在」时,由于不是唯一索引,所以肯定存在索引值相同的记录,于是非唯一索引等值查询的过程是一个扫描的过程,直到扫描到第一个不符合条件的二级索引记录就停止扫描,然后在扫描的过程中,
2025-04-15 14:36:52
870
原创 了解Mysql索引
虽然在符合 a>= 1 条件的二级索引记录的范围里,b 字段的值是「无序」的,但是对于符合 a = 1 的二级索引记录的范围里,b 字段的值是「有序」的(因为对于联合索引,是先按照 a 字段的值排序,然后在 a字段的值相同的情况下,再按照 b 字段的值进行排序)。,由于每次插入主键的索引值都是随机的,因此每次插入新的数据时,就可能会插入到现有数据页中间的某个位置,这将不得不移动其它数据来满足新数据的插入,甚至需要从一个页面复制数据到另外一个页面,我们通常将这种情况称为。
2025-04-15 14:35:39
775
原创 自定义参数校验
有些时候 JSR303 标准中提供的校验规则不满足复杂的业务需求,也可以自定义校验规则。自定义注解类,定义错误信息和一些其他需要的内容注解校验器,定义判定规则//自定义注解类/*** 是否允许为空*//*** 校验不通过返回的提示信息*/String message() default "不是一个手机号码格式";/*** Constraint要求的属性,用于分组校验和扩展,留空就好*/Class<?Class<?//注解校验器// 验证手机号/**
2025-04-15 14:35:05
251
原创 用Python操作MySQL
我在下图中列出了 DB API 规范的作用,这个规范给我们提供了数据库对象连接、对象交互和异常处理的方式,为各种 DBMS 提供了统一的访问接口。需要说明的是,我们在使用 SQL 语句的时候,可以向 SQL 语句传递参数,这时 SQL 语句里要统一用(%s)进行占位,否则就会报错。今天我讲解的是 mysql-connector,它是 MySQL 官方提供的驱动器,用来给后端语言,比如 Python 提供连接。在安装之后,你可以创建数据库连接,然后查看下数据库的版本号,来验证下数据库是否连接成功。
2025-04-15 14:33:36
361
原创 Java 泛型详解
Java 泛型通过参数化类型提高了代码的复用性和类型安全性。泛型类、泛型接口、泛型方法和通配符泛型是 Java 泛型的四种主要形式。理解泛型的原理和使用方法,可以帮助我们编写更高效、更安全的代码。Java 泛型是 Java 5 引入的一项重要特性,它允许在定义类、接口和方法时使用类型参数,从而提高代码的复用性和类型安全性。泛型类是在类定义时使用类型参数的类。类型参数可以在类的成员变量、方法参数和返回值中使用。泛型方法是在方法定义时使用类型参数的方法。泛型接口是在接口定义时使用类型参数的接口。
2025-04-15 14:31:32
1146
原创 Java遍历树(深度优先+广度优先)
在编程生活中,我们总会遇见树性结构,这几天刚好需要对树形结构操作,就记录下自己的操作方式以及过程。现在假设有一颗这样树,(是不是二叉树都没关系,原理都是一样的)
2025-03-24 09:28:25
507
原创 了解红黑树
但 Java 实现的红黑树将使用 null 来代表空节点,因此遍历红黑树时将看不到黑色的叶子节点,反而看到每个叶子节点都是红色的。因此若给定黑色节点的个数 N,最短路径的情况是连续的 N 个黑色,树的高度为 N - 1;x 节点的左旋就是把 x 变成 右孩子 y 的左孩子,同时把 y 的左孩子送给 x 当右子树。y 节点的右旋就是把 y 变成 左孩子 x 的右孩子,同时把 x 的右孩子送给 x 当左子树。性质 4 的意思是:从每个根到节点的路径上不会有两个连续的红色节点,但黑色节点是可以连续的。
2025-03-24 09:28:07
120
原创 数据结构回顾:B、B-、B+、B*-Tree
B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3;
2025-03-24 09:27:47
675
原创 CMS垃圾回收
1.7中存在永久代,1.8中没有永久代,替换它的是元空间,元空间所占的内存不是在虚拟机内部,⽽是本地内存空间,这么做的原因是,不管是永久代还是元空间,他们都是⽅法区的具体实现,之所以元空间所占的内存改成本地内存,官⽅的说法是为了和JRockit统⼀,不过额外还有⼀些原因,⽐如⽅法区所存储的类信息通常是⽐较难确定的,所以对于⽅法区的⼤⼩是⽐较难指定的,太⼩了容易出现⽅法区溢出,太⼤了⼜会占⽤了太多虚拟机的内存空间,⽽转移到本地内存后则不会影响虚拟机所占⽤的内存。所有新生成的对象首先都是放在年轻代的。
2025-03-24 09:27:20
472
原创 详解slf4j、log4j、logback、log4j2
笼统的讲就是slf4j是一系列的日志接口,而log4j logback是具体实现了的日志框架。接下来我们跟着官方文档详细的来看一下他们的关系。官方文档的这一段话已经明确描述了三者的关系。slf4j译为简单日志门面,是日志框架的抽象。而log4j和logback是众多日志框架中的几种这里写了几行简单的代码来验证一下。从运行结果可以看到,由于没有给出具体的logger实现,无法在控制台输出日志。也就是说我们在具体开发中,需要绑定一个日志框架,才能正常的使用slf4j。
2025-03-24 09:26:27
526
原创 aop的循环依赖bean加载过程
2、实例化对象之前调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation(实例化对象前的回调方法),如果此时代理了,直接返回代理对象。4、处理MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition,此时处理依赖注入的属性,找到放到beanDefinition中,留后面属性设置的时候处理。6.6按照上面1、2、3、4、5、6走过来。
2025-03-24 09:25:42
1388
原创 如何使用DDD设计微服务代码模型
如果领域服务内的业务逻辑相对复杂,我建议你将一个领域服务设计为一个领域服务类,避免由于所有领域服务代码都放在一个领域服务类中,而出现代码臃肿的问题。这里提示一下:虽然应用层和领域层都可以进行事件的发布和处理,但为了实现事件的统一管理,我建议你将微服务内所有事件的发布和订阅的处理都统一放到应用层,事件相关的核心业务逻辑实现放在领域层。它主要存放领域层核心业务逻辑相关的代码。它主要存放基础资源服务相关的代码,为其它各层提供的通用技术能力、三方软件包、数据库服务、配置和基础资源服务的代码都会放在这一层目录里。
2025-03-24 00:15:00
985
原创 聚合和聚合根
在领域驱动设计(DDD)中,聚合和聚合根是核心概念,它们帮助我们更好地组织和管理领域模型中的实体和值对象。本文将深入探讨聚合和聚合根的概念、作用以及如何在实际开发中设计它们。聚合是一组相关联的对象的集合,它们作为一个整体被对待。在领域模型中,这些对象包括实体和值对象。聚合的边界明确了哪些对象属于同一个聚合,哪些不属于。例如,在电商系统中,一个订单(Order)和它的订单项(OrderItem)可以组成一个聚合,因为它们在业务上紧密相关,通常一起被创建、修改和删除。聚合根是聚合的入口点,它是聚合中唯一的全局可
2025-03-23 00:15:00
289
原创 DDD分层架构
微服务架构模型有好多种,例如整洁架构、CQRS 和六边形架构等等。每种架构模式虽然提出的时代和背景不同,但其核心理念都是为了设计出“高内聚低耦合”的架构,轻松实现架构演进。而 DDD 分层架构的出现,使架构边界变得越来越清晰,它在微服务架构模型中,占有非常重要的位置。那 DDD 分层架构到底长什么样?DDD 分层架构如何推动架构演进?我们该怎么转向 DDD 分层架构?这就是我们这一讲重点要解决的问题。DDD 的分层架构在不断发展。最早是传统的四层架构;后来四层架构有了进一步的优化,实现了各层对基础层的解耦;
2025-03-23 00:15:00
662
原创 实体和值对象
实体与值对象的选择,本质是业务语义与技术实现的权衡实体守护业务核心,承载复杂逻辑与生命周期;值对象提升内聚性,简化设计与数据存储。领域驱动:从业务需求出发,而非数据库范式。上下文隔离:同一对象在不同上下文中可灵活切换角色。演进式设计:随着业务变化,允许模型迭代优化。最终目标是通过清晰的领域模型,构建高响应力、易维护的系统,让技术真正服务于业务价值。
2025-03-22 01:15:00
863
原创 限界上下文
限界上下文不是简单的技术划分工具,而是业务语义的守护者与团队协作的催化剂。业务复杂度可控:将庞杂系统分解为高内聚、低耦合的单元;技术架构敏捷响应:支持快速迭代与局部技术升级;组织效能提升:减少跨团队沟通摩擦,加速价值交付。
2025-03-22 00:15:00
1267
原创 Java8中时间日期库的20个常用使用示例
在Java 8之前,时间日期的格式化可是个技术活,我们的好伙伴SimpleDateFormat并不是线程安全的,而如果用作本地变量来格式化的话又显得有些笨重。多亏了线程本地变量,这使得它在多线程环境下也算有了用武之地,但Java维持这一状态也有很长一段时间了。这次它引入了一个全新的线程安全的日期与时间格式器。它还自带了一些预定义好的格式器,包含了常用的日期格式。比如说,本例 中我们就用了预定义的BASICISODATE格式,它会将2014年2月14日格式化成20140114。
2025-03-21 15:59:54
827
原创 bean的生命周期
Spring 容器首先会加载 Bean 的定义信息()。这些定义信息可以通过以下方式加载:加载的 Bean 定义信息会被注册到 中,具体实现类是 。每个 Bean 的定义信息包括:Spring 容器根据 实例化 Bean。实例化的过程包括:在 Bean 实例化后,Spring 容器会通过依赖注入(DI)填充 Bean 的属性。依赖注入的方式包括:如果 Bean 实现了 Spring 的 接口(如 、、),Spring 容器会调用相应的回调方法,将相关的上下文信息注入到 Bean 中。在 Bean 初始
2025-03-21 15:58:54
1201
原创 注解Autowired和Resource的区别
默认按照名称装配,当找不到与名称匹配的bean才会按照类型装配,可以通过name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象.注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖的对象时候,会回退到按照类型装配,但一旦指定了name属性,就只能按照名称装配了.(这个注解是spring的),默认情况下必须要求依赖对象必须存在,@Resource默认按。
2025-03-21 15:55:54
148
原创 mybatis插件扩展
的方法里有一个setSqlSessionFactory方法,因为设置了按类型自动注入,因此初始化的时候会主动调用这个方法设置依赖,也就会去spring的容器中找SqlSessionFactory的bean,这个bean在哪里,就是上面SqlSessionFactoryBean的getobject创建出来的SqlSessionFactory的bean,后面会分析这个bean细节。继续刚才扫描的过程,我们知道了扫描的域的mapper接口实际上是在容器里创建对应的MapperFactoryBean。
2025-03-21 15:54:58
524
原创 G1垃圾回收
在进行MixedGC过程中,采用的复制算法,如果复制过程中内存不够,则会触发FuIGC,会STW,并采用单线程来进行标记-整理算法进行GC,相当于用一次SerialGC。老年代的占用率达到了-XX:InitiatingHeapOccupancyPercent指定的百分比,回收所有的新生代以及部分老年代,以及大对象区。Eden区满,就会触发G1的YoungGC,对Eden区进行GC。
2025-03-21 15:52:47
367
原创 垃圾回收算法
指定老年代使用ParallelOld GC,这两个配置一个,另一个自动激活。,指定使用Serial GC和Serial Old GC。,指定新生代使用Parallel GC,,指定新生代使用ParNew GC,工作线程暂停,一个线程进行垃圾回收。工作线程暂停,一个线程进行垃圾回收。工作线程暂停,多个线程进行垃圾回收。工作线程暂停,多个线程进行垃圾回收。工作线程暂停,多个线程进行垃圾回收。用户线程和垃圾回收线程同时执行。用户线程和垃圾回收线程同时执行。用户线程和垃圾回收线程同时执行。
2025-03-21 15:52:11
351
原创 JVM参数调优
如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代,对于年老代比较多的应用,这样做可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代存活时间,增加对象在年轻代即被回收的概率。: 设置堆内存年轻代中Eden区与Survivor区大小的比值。设置为4,则两个Survivor区(JVM堆内存年轻代中默认有2个Survivor区)与一个Eden区的比值为2:4,一个Survivor区占 整个年轻代的1/6。
2025-03-21 15:51:35
158
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人