架构设计Spring AI Alibaba 项目在架构上包含三个清晰的层次:
Agent Framework:以 ReactAgent 设计理念为核心的 Agent 开发框架,内置了自动上下文工程和 Human In The Loop 等高级能力。
Graph:一个更底层级别的工作流和多代理协调框架,是 Agent Framework 的底层运行时基座,用于实现复杂的工作流编排,同时对用户开放 API。
Augmented LLM**:基于 Spring AI 框架的底层原子抽象,提供了模型、工具、消息、向量存储等构建 LLM 应用的基础。
设计理念ReactAgentReactAgent是 1.1 版本的核心组件之一,它基于 ReAct(Reasoning + Acting) 范式。这意味着 Agent 不仅仅是调用 LLM,它还可以在一个循环中运行,通过“思考(Reasoning)”来分析任务、决定使用哪个“工具(Acting)”,然后“观察(Observation)”工具结果,并迭代此过程,直到任务完成。
就是我们先去进行一个思考,然后再去进行工具的调用,根据结果再去进行思考 ...
高并发日志系统设计我们可以将整个日志生命周期划分为五个关键阶段:采集 -> 传输 -> 处理 -> 存储 -> 应用。
根本性设计:
结构化日志: 将不同日志封装成不同数据结构。
传输解耦: 使用 Kafka 作为日志总线。
分流消费: 一部分流式处理(热路径),一部分存储(冷路径)。
结构设计统一日志规范:
会定义一个公共的日志基础 Schema (Base Schema),所有日志都必须包含某些字段,需要保证:
一致性 (Consistency): 确保任何来源的日志都有相同的核心结构,便于机器解析和人类理解。
可关联性 (Correlatability): 能够将分散在不同系统、不同时间的日志串联起来,形成完整的事件链。
可检索性 (Searchability): 优化核心字段,使其易于索引和查询。
timestamp: 事件发生时间(UTC, 毫秒级精度)。
格式: 必须是 ISO 8601 格式,例如 2025-10-09T06:10:35.123Z。
时区: 必须是 UTC (协调世界时)。这消除了所有因服务器时区不同导致的混乱,是分布式系统的 ...
基础知识容器化想象一下传统开发流程中的经典难题:“在我的电脑上明明是好的,怎么一到服务器上就出问题了?”
这个问题的根源在于环境不一致。开发者的电脑和服务器的操作系统、依赖库、配置文件等可能存在细微差别,导致程序行为不一致。
核心逻辑: 我们需要一种技术,能将我们的应用程序及其所有依赖(代码、库、配置文件等)打包在一起,形成一个标准化的、可移植的“集装箱”。这个“集装箱”在哪里运行,其内部环境都完全一致,从而彻底解决环境依赖问题。
这就是容器化(Containerization)思想的由来。
Docker 就是目前最流行的容器化工具。它引入了几个核心概念来实现这个目标。
2.1 镜像 (Image)
它是什么: 镜像是一个只读的模板,是应用程序的“安装包”或“光盘”。它包含了运行应用程序所需的一切:代码、运行时、库、环境变量和配置文件。
如何构建: 通过一个名为 Dockerfile 的文本文件来定义构建步骤。Dockerfile 就像一张“菜谱”,指导 Docker 如何一步步制作出这个“安装包”。
核心逻辑: 镜像是静态的、标准化的交付物。一次构建,处处运行。这就保证了从开发到测 ...
K8S1.k8s 基础组件有哪些,什么功能?Kubernetes 遵循典型的 C/S(客户端/服务器)架构,由控制平面(Control Plane / Master)和数据平面(Data Plane / Node)组成。
控制平面组件 (Master Components):
kube-apiserver:
功能: 集群的统一入口和大脑中枢。所有组件之间的通信都通过它进行。它以 RESTful API 的形式暴露了 Kubernetes 的所有功能,并负责处理请求的认证、授权、准入控制,然后将有效资源对象的状态持久化到 etcd。
etcd:
功能: 集群的分布式键值存储系统。它负责存储集群的所有状态数据,如 Pod、Service、Deployment 的定义和状态等。etcd 的高可用性和数据一致性是整个 K8s 集群可靠性的基石。
kube-scheduler:
功能: 专职的“调度员”。它持续监听(Watch)apiserver,发现新创建的、尚未分配节点的 Pod。然后根据一系列预设的调度策略(如资源需求、亲和性、污点容忍等)为 Pod 选择一个最合适的 Node, ...
RAG1.什么是RAGRAG,全称是 Retrieval-Augmented Generation,中文可以理解为 “检索增强生成”。
而是一种将信息检索(Information Retrieval)系统与大语言模型(LLM)的生成(Generation)能力相结合的技术框架。
解决了LLM的:
知识局限性 (Knowledge Cutoff):LLM 的知识都来自于其训练数据,这些数据有明确的截止日期。对于截止日期之后的新知识,模型是无法感知的。
事实幻觉 (Hallucination):LLM 在回答它不确定的问题时,有时会“编造”听起来合理但实际上是错误的答案,这在需要高度事实准确性的场景中是致命的。
缺乏领域专有知识 (Lack of Domain-Specific Knowledge):对于一些非常专业或企业内部的私有领域,通用的大模型由于没有接触过相关数据,无法提供精准的回答。
当模型需要回答问题时,不直接让它依赖内部知识进行生成,而是先从一个外部的、可信的知识库中检索出与问题最相关的信息,然后将这些信息作为上下文(Context)和原始问题一起提供给大语言模型,让它基于这 ...
分布式1.分布式事务设计TCC、Saga、本地消息表、事务消息
本地消息表
这是一种实现“最终一致性”的常用方案,核心思想是将业务操作和发送消息这两个步骤,放在同一个本地事务里来保证原子性。
事务发起方:在执行核心业务逻辑时(例如:创建订单),会在同一个数据库事务中,向一张本地的“消息表”插入一条消息记录,这条记录的状态初始为“待发送”。
事务提交:当本地事务成功提交后,订单数据和“待发送”的消息记录会同时落库。
消息投递:我会用一个独立的、可靠的后台任务(比如使用定时任务调度框架如XXL-Job)去轮询这张消息表,把所有“待发送”状态的消息发送到消息队列(MQ)中。
状态确认:消息成功投递到MQ后,后台任务会更新消息表中的记录状态为“已发送”或直接删除。如果投递失败,它会进行重试。
事务消费方:下游服务消费MQ中的消息,并执行相应的业务逻辑。为了防止重复消费,消费方必须保证接口的幂等性。
消息的发送不是实时的,存在一定的延迟。需要额外维护一个后台任务。
事务消息
第一阶段 (Prepare Message):生产者先向MQ Server发送一条“半消息”或“预备消息”。这条消息 ...
异常解决1.就比如说你这个部署到线上了,然后他抛了一个异常,然后那你这个应该怎么排查呢线上出现异常,我会遵循一套从宏观到微观、由表及里的排查SOP(标准作业程序)来定位和解决问题。
第一步:信息收集与初步判断
确认影响范围:首先,快速判断这个异常的影响面有多大。是影响了所有用户,还是部分用户?是核心功能还是边缘功能?这决定了问题的紧急程度。
查看监控告警:立即查看监控系统(如Prometheus/Grafana, Zabbix)的告警信息。检查应用的
关键指标,如:
应用层面:QPS、响应时间(RT)、错误率(Error Rate)是否突增?
JVM层面:CPU使用率、内存占用、GC活动是否异常?
主机层面:服务器的CPU、内存、磁盘I/O、网络流量是否正常?
依赖服务:数据库、Redis、MQ等中间件的健康状况如何?
这一步的目标是快速定位问题是出在应用本身,还是外部依赖。
第二步:日志分析与精准定位
聚合日志平台检索:登录ELK(Elasticsearch, Logstash, Kibana)或类似日志平台,根据告警信息中的时间点、错误信息关键字(如RuntimeEx ...
JavaSE1.流式输出和非流式输出
对比点
流式输出
非流式输出
数据传输
边生产边传输
生成完后一次传输
响应延迟
首字节快,用户能尽快看到结果
必须等所有数据生成后才能看到
内存占用
占用更少内存(分段处理)
可能占用大量内存(一次性加载)
实现复杂度
较高(需要支持分段协议/推送机制)
较低(一次性返回)
应用场景
视频流、日志实时消费、AI Chat逐字打印
小文件下载、查询一次性返回结果
非流式输出是等数据全部生成后一次性返回,而流式输出则是边生成边返回,能降低延迟和内存占用,更适合大数据量和实时场景。
2.HashMap remove 方法的实现细节
首先,remove(key)方法会计算key的hash值。
根据hash值定位到它在底层table数组中的索引位置(即bucket)。
如果该bucket为空,直接返回null。
如果bucket不为空,则遍历该位置的链表或红黑树,逐个节点使用hash值和equals()方法进行比较,直到找到要删除的目标节点。如果遍历完没找到,也返回null。
如果当前是链表结构,是头节点的话,即让头 ...
JUC1.线程池常见的坑
线程池的参数配置:核心线程的数量,和最大线程的数量是业务场景来的,CPU密集型,比如数据的计算业务,就是CPU的数量+1。
IO密集型根据业务压测的值来决定的,最佳线程数=((线程等待时间+线程CPU时间)/线程CPU时间)*CPU数量
比如,我们服务器CPU核数为8核,任务线程CPU耗时20ms,线程等待等等耗时80ms,那么最佳线程数=(80+20)/20*8=40线程,那我们最大线程数就是80个
共享线程池,次要的逻辑拖垮主要的逻辑。避免所有的业务都共享一个线程池,防止一个次要的业务一直在执行业务,占用线程池。而主要的业务并没有足够的线程数来执行,影响到了我们主要的服务。这样做是不合理的。我们应该要做线程池的隔离,使用Future.get方法的时候,使用带超时时间的,因为他是阻塞的,防止被其他抢占。
@Async是Spring中一个注解,他不是线程池,他其实是SimpleAsyncTaskExecutor,不会复用线程,适合执行大量短时间的线程。还是尽量自己定义一个异步的线程池,然后使用@EnableAsync来注册
使用线程池的时候,不使用thr ...
MQ1.消息队列(MQ)消息积压处理当被问及线上Topic消息积压如何处理时,你的第一反应是“清空队列,然后恢复”,这在线上环境中是绝对禁止的操作。在引导下,你提到了扩容消费者。
方案1 紧急扩容消费者并监控下游依赖
监控分析:在扩容前,必须先快速查看消费者应用的CPU、内存、GC情况,以及其下游依赖(如数据库、外部API)的负载情况。确认瓶颈在于消费者本身,而不是下游。
水平扩容:如果瓶颈在消费者,立即增加消费者实例数量。在Kubernetes等云原生环境中,可以通过调整Deployment的replica数量快速实现。
注意Partition数量:确保消费者实例数不超过Topic的Partition数量,因为多余的消费者将处于空闲状态。
方案2 消息转储与异步回补
编写转储程序:快速开发一个简单的程序,它的唯一作用就是消费积压Topic中的消息,然后原封不动地存储到另一个临时Topic或一个临时存储(如文件、数据库)中。
启动转储:启动该程序,快速将积压消息“搬空”。
修复与回补:在修复了原始消费者的Bug或性能问题后,再编写一个回补程序,以一个受控的速率,从临时Topic或 ...
Mybatis1.UserMappe这个类为啥要是接口呢?MyBatis的Mapper之所以必须定义为接口,其根本原因在于MyBatis框架在底层使用了JDK动态代理(JDK Dynamic Proxy)技术,来为我们自动地生成这个接口的实现类。
只定义了UserMapper接口,并在XML文件中写了SQL,但我们从来没有手动编写过一个class UserMapperImpl implements UserMapper。然而,在Service层,我们却可以直接@Autowired注入一个UserMapper的实例并调用它的方法。
启动时扫描:当Spring容器启动时,MyBatis的MapperScannerConfigurer会扫描指定的包路径(如com.example.mapper),找到所有被@Mapper注解标记的接口,或者所有继承了特定标记接口的接口。
注册Bean定义:对于找到的每一个Mapper接口(比如UserMapper.class),MyBatis并不会去创建一个真实的实现类,而是在Spring容器中注册一个特殊类型的Bean定义——MapperFactoryBe ...
计网1.对比一下 HTTP/1.0, HTTP/1.1, 和 HTTP/2.0 这三个版本的主要区别。请从连接管理、性能优化、头部处理等角度展开,并说明每一个版本的演进分别解决了上一代的什么核心痛点?
1.0->1.1
长链接 (Keep-Alive): 是 HTTP/1.1 相对于 HTTP/1.0 最核心的改进之一。HTTP/1.0 默认是短连接,每个请求/响应对都需要一次 TCP 连接。而 HTTP/1.1 默认开启了长链接,允许在一个 TCP 连接上发送多个 HTTP 请求,极大地减少了 TCP 连接建立和关闭的开销。
HTTP/1.1 还引入了管道机制 (Pipelining),允许客户端在收到上一个响应之前就发送下一个请求。但这只是部分解决了队头阻塞(Head-of-Line Blocking)问题,因为服务端的响应仍然必须按顺序返回。
2.0
多路复用 (Multiplexing): 这是 HTTP/2.0 最核心的优势。它允许在一个 TCP 连接上,同时、并行地收发多个请求和响应,并且不按顺序。这彻底解决了 HTTP/1.1 的队头阻塞问题。
头部压缩 (H ...













