- 博客(316)
- 问答 (1)
- 收藏
- 关注
原创 Nacos启动过程
1、项目启动时,Spring Boot 的自动装配机制会加载 spring-cloud-starter-alibaba-nacos-config包下的 /META-INF/spring.factories文件。2、该文件定义了自动配置类,如 NacosConfigAutoConfiguration。这个配置类会向 Spring 容器中注册一个核心 Bean — NacosPropertySourceLocator。正是这个 Bean 负责在应用启动的早期阶段去获取配置。定位配置数据源与优先拉取。
2025-11-26 21:44:28
304
原创 Java面试题
下单接口是电商系统的核心,也是最复杂的接口之一。它不仅仅是插入一条订单数据,而是涉及用户、营销、商品、仓储、资金、等多个系统的协同工作1、核心业务流程与数据一致性(基本功能)参数校验、商品信息校验、价格计算、数据一致性:下单过程涉及多个数据源的写操作(订单表、库存表、优惠券表、积分表等)2、性能与高并发(保证系统不挂)
2025-11-25 21:10:52
454
原创 缓存一致性面试
这个方案的好处是,更新缓存/删除缓存的操作与业务逻辑完全解耦,由独立的组件来负责,可靠性非常高。其核心矛盾在于,我们引入缓存是为了提升性能,但这增加了数据副本,从而带来了数据一致性的挑战。分布式锁:在写数据时,先获取一个分布式锁,然后进行‘读数据库->更新数据库->删除缓存’的操作,最后释放锁。这是一个兜底的方案,在大多数对一致性要求不非常极致的场景下,简单有效。延时双删:在更新数据库前、后都执行一次缓存删除操作,第二次删除延迟一段时间(如几百毫秒)后执行,以清除可能在此期间被读请求加载的脏数据。
2025-11-19 13:42:46
346
原创 ThreadLocal结构关系
注意:一个线程可以有多个ThreadLocal变量,这些ThreadLocal变量都存储在这个线程的同一个ThreadLocalMap中,通过不同的ThreadLocal对象作为键来区分。3、当我们使用ThreadLocal的set方法时,实际上是在当前线程的ThreadLocalMap中存储一个键值对,键是当前的ThreadLocal对象,值是我们设置的值。2、每个线程(Thread)都有一个ThreadLocalMap,这个Map是线程的成员变量,所以每个线程的Map都是独立的。
2025-11-18 18:03:24
392
原创 Kafka如何记录Offset
消费位移的存储位置消费位移存储在Kafka内部的一个特殊Topic中:__consumer_offsets,这个Topic是Kafka自动创建和管理的:位移在__consumer_offsets中的存储格式__consumer_offsetsTopic中消息的Key-Value结构:Key: [消费者组名, Topic名, 分区号]Value: [位移值, 元数据, 时间戳]例如消费者查找位移的过程Broker挂掉重启后的恢复过程Broker重启对消费位移的影响。
2025-11-17 15:54:31
611
原创 RocketMq面试
1、Queue(队列) - 逻辑概念2、ConsumeQueue是物理实现,是磁盘上实实在在的文件,存储在$RocketMQ_HOME/store/consumequeue/{topic}/{queueId}目录下ConsumeQueue存的是什么?生产者发送消息:生产者发送消息 --> Broker接收 --> 消息追加到CommitLog末尾 --> 返回成功那么什么时候创建索引ConsumeQueue呢?
2025-11-15 15:11:03
464
原创 RocketMQ延迟消息原理
RocketMQ延迟消息实现原理RocketMQ的延迟消息并非在用户指定的精确时间点才投递,而是通过一个“等级”机制,将消息暂存到不同的内部队列中,由定时任务在到达预定延迟等级的时间后,才将其投递到目标 Topic 供消费者消费。
2025-11-14 18:08:28
661
原创 RocketMQ延迟消息的存储和处理
总结关于延迟消息的投递和重试:1、延迟期内没收到是正常的 - 消息存储在SCHEDULE_TOPIC中,对消费者不可见2、到期后没收到会重试 - 遵循普通消息的重试机制(最多16次)3、处理失败会自动重试 - 重试间隔逐渐增加,最终进入死信队列关于清理策略:基础机制相同" - 都基于文件创建时间和磁盘使用率SCHEDULE_TOPIC有特殊策略" - 可能更早被清理,因为只是中间状态转投后的消息按目标Topic策略清理" - 延迟消息到期后变成普通消息。
2025-11-14 14:33:23
383
原创 RocketMQ的存储设计
关键特点1、文件级删除:按整个存储文件删除,不是逐条消息删除2、双重触发:基于时间 + 基于磁盘空间3、协调清理:CommitLog、ConsumeQueue、IndexFile联动删除4、安全保护:避免删除正在使用的文件RocketMQ的存储设计通过顺序写、页缓存、零拷贝等技术实现了高性能,同时通过刷盘机制和主从复制保证了高可靠性。其存储结构以CommitLog为核心,通过ConsumeQueue和IndexFile提供索引,使得消息的存储和检索高效且可靠。
2025-11-14 12:15:58
460
原创 Redis红锁
如果时钟偏差是固定不变的,那么所有锁在真实时间轴上确实会同时过期。1 、时钟漂移会导致偏差逐渐变化 2 、时钟跳跃会导致节点上的锁 "提前过期"这才是Redlock面临的主要风险:不是固定的时间差,而是动态变化的时间差和突然的时钟调整这就是为什么Redis作者Antirez在提出Redlock时特别强调要配置NTP服务防止时钟跳跃,因为时钟的不稳定性而非简单的偏差才是破坏锁安全性的根本原因。
2025-11-13 13:20:29
409
原创 Synchronized总结
1、markword中包含了和Java对象息息相关的一些信息,它的实际大小一般和CPU字长保持一致,如在32位CPU上markword的大小一般为32位,即4字节。对象在内存的结构主要是3大块,对象头,实例数据,对其填充,对象头主要包含两大块,markwork和kclass point。2、Klass Pointer Class 对象的类型指针,它指向对象对应的Class对象的内存地址。在面试中,关于Markword的问题是非常常见的。1、什么是Markword?4、Markword的锁标志位有什么作用?
2025-11-12 17:46:16
235
原创 Redis Cluster设置数据流程
1、可控的数据分布# 手动调整槽位分布示例# 交互式将部分槽位从节点A迁移到节点B2、高效的键值查找槽位计算:O(1)时间复杂度节点定位:基于位图的O(1)查找网络跳转:大多数操作只需1次节点访问3、无缝的扩缩容# 添加新节点# 重新分配槽位4、客户端智能路由。
2025-11-07 11:27:22
446
原创 Redis Cluster槽位位图
/ 方案A:共享位图(不好)// 所有节点共享// 问题:节点间同步复杂,并发控制困难// 方案B:您的理解 - 分区位图(不好)// 只存前一半槽位// 只存后一半槽位// 问题:无法处理槽位重新分配,扩展性差// 方案C:Redis实际采用 - 每个节点完整位图(✅最佳)// 完整槽位空间// 完整槽位空间// 优点:简单、一致、高效。
2025-11-07 11:05:00
274
原创 Guava Cache淘汰算法
Guava Cache 的 LRU 是近似的,主要原因:// 读操作时并不立即更新队列,而是先记录"可能需要更新"if (entry!= null) {// 不是立即移动,而是设置标志位// 实际的队列更新可能批量进行2、分段设计的影响由于缓存被分成多个 Segment,每个 Segment 独立维护 LRU 队列。淘汰时:1、优先淘汰访问频率最低的 Segment" 中的条目2、而不是全局严格的 LRU 顺序。
2025-11-05 15:38:42
268
原创 Mysql中MVCC的流程
1、如果2个快照读的线程并发过来,二者在同一个时刻创建Read View,那么Read View里面的内容是不是一样的?开启了事务,并不会直接记录到版本链中,只有修改了数据,不管是有提交还是没提交,都会在版本链中。不一定,如果事务未提交,也会直接刷到数据页中,这个和以往我们的认知有差异的。2、只要开启事务,不管有没有提交,都会出现在版本链中吗?3、行数据中,隐藏事务ID,一定是事务提交的吗?事务500的Read View和判断过程。利用缓存局部性:直接修改缓冲池中的数据。减少内存拷贝:避免数据来回拷贝。
2025-11-02 14:34:38
449
原创 ConcurrentHashMap扩容过程
注意:一个线程进来,可能给她单独分配迁移空间,也有可能协助其他线程共同迁移一小块区间。// 计算扩容标识戳2、常量定义最小迁移步长,比如32扩64,那么第一个线程的最小迁移的数据就是32-16(步长)也就是16,所以第一个线程迁移【16到32】的数据内容,当然在扩的过程中,其他线程也可以协助他,帮他完成16到32的某个区间。至于怎么做到的,我代码后面会写到。3、控制迁移进度的核心变量// 下一个要分配的迁移区间起始索引,也就是第一个扩容区间的计算。
2025-10-30 14:12:18
415
原创 通俗易懂的说下Hikari
整个系统设计的目标就是:让租车的人(应用程序线程)花最少的时间在租车还车的手续上 (getConnection(), close()),把更多时间用在骑车办事 (执行 SQL) 上!线程进来,先使用空闲连接(minimumIdle),如果空闲连接用完了,就创建新的连接,前提是小于最大连接数(maximumPoolSize),当前连接数等于最大连接数,在进来的线程就进到队列中等待()(housekeeper) 一直按设定好的时间间隔出来巡逻,执行上面说的检查任务(补车、收闲置车、报废旧车、查丢车)。
2025-10-29 13:20:13
682
原创 IntroductionAdvisor切面使用案例
理解 IntroductionAdvisor的关键在于认识到它是 Spring AOP 中一种的特殊增强方式。与常规的 PointcutAdvisor(在方法调用前后插入逻辑)不同,IntroductionAdvisor是为目标类动态添加新接口实现的能力。
2025-10-26 21:52:18
230
原创 Mybatis-Spring重要组件介绍
(1) 数据源配置(Spring Boot自动配置)spring:(2) MyBatis配置@Bean// 设置其他配置,如mapperLocations等@Bean(3) Mapper扫描// 使用@MapperScan注解自动扫描。
2025-10-22 20:28:26
855
原创 SqlSessionFactory、SqlSession、MapperProxyFactory、MapperProxy、MapperMethod是什么
SqlSessionFactory (顶级工厂)↓ 创建SqlSession (数据库会话)↓ 通过 getMapper() 触发MapperProxyFactory (代理工厂)↓ 生成MapperProxy (动态代理)↓ 委托执行MapperMethod (方法执行器)
2025-10-22 15:01:32
464
原创 MapperMethod中的SqlCommand和MethodSignature
职责:封装 SQL 命令的元信息。来源:解析 Mapper 接口方法对应的 XML 或注解中的 SQL 定义。
2025-10-22 14:38:09
250
原创 Eureka 多层缓存机制详解
/ 多级缓存机制(核心优化), Eureka Server 缓存架构伪代码// 只读缓存// 读写缓存// 客户端拉取注册表时,直接从只读缓存获取= null) {// 填充只读缓存// 注册表变更时,先失效读写缓存,定时同步到只读缓存// 立即失效读写缓存// 只读缓存通过定时任务(30秒)更新,避免频繁同步开销缓存更新策略:读写缓存:注册表变更时立即失效只读缓存:定时30秒同步一次(可配置)效果:99%的读请求直接命中缓存,极大降低数据库压力。
2025-10-21 16:35:16
636
原创 Spring生命周期
Spring生命周期主要分为三个阶段:1)实例化阶段,容器创建并配置Bean;2)初始化阶段,执行属性注入和初始化操作;3)销毁阶段,进行资源清理。关键过程包括注册7个核心后置处理器(如自动装配、配置类处理等)、BeanDefinition扫描以及同步刷新操作(包含10个步骤如初始化事件派发器、注册监听器等)。这些组件协同工作,实现了依赖注入、AOP代理等核心功能,确保Bean从创建到销毁的完整生命周期管理。
2025-08-27 17:02:34
1016
原创 JDK8 stream toMap方法介绍
JDK8 List转Map方法,有下3种方法。keyMapper:Key的映射函数valueMapper:Value的映射函数mergeFunction:当Key冲突时,调用的合并方法,对value进行处理。mapSupplier:Map 构造器,在需要返回特定的Map时使用。
2024-03-06 20:25:28
1616
空空如也
有没有更好的实现方案
2022-05-11
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅