news 2026/10/2 19:55:50

RAGFlow四层存储架构拆解:从元数据到缓存的数据流转与排查

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RAGFlow四层存储架构拆解:从元数据到缓存的数据流转与排查

项目落地跑了三个月,我被问得最多的不是"大模型怎么选",而是"RAGFlow 存的东西到底在哪里""为什么有时候检索慢""容器占了几十G空间到底装了什么"。这些问题本质上都指向同一个主题:RAGFlow 的存储架构。它不像传统 Web 项目那样只有一个数据库,而是把数据拆成了四层来管——元数据、对象、检索、缓存,各自负责一类活,又互相配合。这篇我就把这四层拆开讲清楚,结合我实际部署和排查问题的经历,说明每一层存了什么、为什么这么设计、以及它们之间是怎么协作的。

这套架构不是什么花架子。RAGFlow 的核心是文档解析和检索增强,一个 PDF 进来之后,要经历文件落地、内容抽取、向量化、索引构建、查询召回这么一串流程,每一环节的数据形态和读写特征完全不一样。用单一存储硬扛,要么性能拉胯,要么数据管理混乱。四层分工本质上是把"不同类型的数据"放到"最擅长处理它的组件"里,这是 RAG 系统存储设计的基本逻辑。如果你正在搭 RAG 服务,或者准备在生产环境用 RAGFlow,这篇文章能帮你理解数据到底怎么流转,排查问题的时候也更有方向。

1. 为什么要拆四层存储:从一次失败的检索说起

先说一个我真实遇到的场景。客户上传了一批 PDF 合同,问"去年跟 A 公司签的付款条款是什么",结果系统压根没召回相关内容。我当时第一反应是 embedding 模型的问题,查了一圈发现不是,最后定位到是 chunk 文本压根没进检索库。为什么没进?因为文档解析任务虽然在界面上显示成功,但 MySQL 里的任务状态和 ES 里的索引数据出现了不一致,解析完成的回调没触发索引写入。

这个问题的根源就是:RAGFlow 里"文档"这个概念,实际上分散在四个地方管理。存在 MinIO 里的原始 PDF 是一份,MySQL 里记录文件元数据和解析任务是一条,Elasticsearch 里可检索的 chunk 是另一批,Redis 里还存着任务状态和会话缓存。任何一个环节不同步,表现出来就是"文件上传了但检索不到""解析成功但问答没效果"。

所以理解四层存储,不只是搞懂架构图,更是排查问题的基本功。你至少要知道:一个文件进来,每一层分别做了什么,哪一层出了问题会有什么现象。

1.1 单库时代的尴尬

如果只用一个关系型数据库来存 RAG 系统的所有数据,会出现三个很现实的问题。

第一个是二进制大对象的问题。一份带扫描图片的 PDF 可能上百 MB,如果直接塞进 MySQL,光读写就够受的,备份也会变成噩梦。更麻烦的是,RAG 系统经常要做文档版本对比、原文件预览这些操作,这些场景需要的是"直接按路径取文件",而不是"从数据库里查出来再拼成文件"。

第二个是检索性能的问题。向量检索本质上是高维空间里的最近邻搜索,传统数据库的 B+ 树索引对这个场景完全无能为力。几十万条 chunk 数据做暴力扫描,延迟直接到秒级,这在问答场景里是不可接受的。

第三个是读写模式冲突的问题。元数据是小数据量的高频读写,文件对象是大数据量的低频读写,向量索引是写入一次但查询极其频繁,缓存是超高频的临时读写。把这些不同特征的数据混在一个存储里,性能调优会变得非常拧巴——你调了连接数,可能影响的是元数据查询;你调了缓存大小,可能挤占了文件存储的空间。

RAGFlow 的四层设计,本质上是把这个"什么都想做"的单体存储,拆成了四个各司其职的组件。这个思路跟微服务拆分的逻辑一模一样:与其在一个系统里平衡所有需求,不如让每个系统专心做好一件事。

1.2 四层架构的分工逻辑

RAGFlow 的四层存储各有明确的分工范围。

第一层是 MySQL,管元数据。包括知识库配置、文档基本信息、解析任务状态、chunk 与文档的映射关系、用户权限和会话历史。这一层的特点是:数据量不大,但关系复杂,需要事务支持,允许通过 SQL 灵活查询。

第二层是 MinIO,管对象。包括上传的原始文件(PDF、DOCX、图片)、解析过程中生成的辅助文件、可能有的图片裁剪结果。这一层的特点是:存的是二进制大对象,按路径访问,不需要事务,但要求可靠持久化。

第三层是 Elasticsearch,管检索。包括解析后的 chunk 文本、向量化之后的 embedding、用于全文检索的倒排索引。这一层的特点是:写入路径固定(解析完成后写入),但查询路径极其频繁,延迟要求毫秒级。

第四层是 Redis,管缓存。包括任务执行状态的临时标记、拆分成多个子任务后的进度汇总、问答会话的上下文缓存、可能的限流计数。这一层的特点是:数据生命周期短、读写超高频、允许丢失后重建。

四层之间不是孤立的。元数据层和对象层之间有引用关系,检索层的数据来源是对象层解析的结果,缓存层则服务于所有层的并发协调。理解了这个依赖关系,才能真正看懂 RAGFlow 的部署架构。

2. 元数据存储层:MySQL 才是真正的"大脑"

很多人以为 RAGFlow 的核心是 Elasticsearch,因为检索是重点。但从数据管理的角度讲,MySQL 才是整个系统的大脑。知识库列表、文件清单、任务调度、解析进度,全部由 MySQL 统一管理。

2.1 元数据到底存了什么

RAGFlow 的 MySQL 数据库里,最核心的是几类表:知识库表、文档表、任务表,以及文档与 chunk 的关联关系表。我用实际数据来举例。

知识库表记录的是"用户创建了一个叫'合同库'的知识库",包括知识库的 ID、名称、embedding 模型配置、检索参数设置(比如 topK 默认值、相似度阈值)。文档表记录的是"合同库下上传了'2024年度采购合同.pdf'"这个文件的基本信息,包括文件名、文件大小、文件类型、上传时间、解析状态。任务表记录的是"这个文档的解析任务被拆分成了哪几个子任务、每个子任务跑在哪个节点、当前进度是多少、失败了是什么错误信息"。

这里有一个容易被忽略的点:chunk 的文本本身不存 MySQL,但 chunk 的 ID、所属文档 ID、在源文件中的页码位置、在知识库中的顺序号,这些"关于数据的数据"是存在 MySQL 里的。检索阶段从 ES 拿到了命中的 chunk ID 列表之后,系统会回到 MySQL 查这些 chunk 的关联信息,比如去定位原始文档、去拼装引用来源。

这个设计的原因很现实:ES 擅长检索但不太适合做关系查询,MySQL 擅长关系管理但不太适合向量检索。把 chunk 的内容和 chunk 的元信息分开放,各自用最合适的方式管理,这是混合存储架构里非常典型的做法。

2.2 元数据与文件和索引的绑定关系

元数据层最关键的价值,是它作为文件对象和检索索引之间的桥梁。这个桥梁关系如果不理解,排查"文件上传了但检索不到"这类问题就容易抓瞎。

一个文档在系统中的完整 ID 链条是这样的:知识库 ID 标识"属于哪个知识库",文档 ID 标识"是哪一次上传的文件",任务 ID 标识"解析进程在哪一个批次",chunk ID 标识"解析出来的第几段文本"。四个 ID 逐层绑定,MySQL 里维护着这些绑定关系。

实际排查中,我发现很多问题的根因都在这个绑定链路上。比如上传了一个 20MB 的 PDF,解析任务失败在某个子任务上,但界面显示"已上传"而不是"解析失败"——这是因为文档表的"上传状态"和"解析状态"是两个字段,上传成功不代表解析完成。再比如同一个文件删了重新上传,生成了新的文档 ID,但旧 chunk 还残留在 ES 里,如果不清理,检索时会出现"明明删了还能搜到"的诡异现象。

所以我对使用 RAGFlow 的朋友有一个建议:把 MySQL 里的 document 表和 task 表当作排查问题的起点。文件上传了没有?解析任务成功没有?chunk 生成没有?三个问题依次确认,60% 以上的检索异常都能定位到环节。

3. 对象存储层:MinIO 撑起大文件底座

MinIO 在 RAGFlow 里管的是最重的数据:原始文件。你可能觉得"存个文件而已,为什么还要单独部署一个服务",但实际用下来就明白,文件存储远远不是"把字节写进磁盘"那么简单。

3.1 为什么不能把文件塞进数据库

从 MySQL 的角度看,把 PDF 文件塞进数据库意味着每条记录都带一个巨大的 BLOB 字段。这会导致三个问题:一是表空间膨胀严重,备份和迁移的时间成本暴增;二是查询性能下降,即使只是查文件的元信息,也要扫描大字段;三是应用层的数据处理复杂度上升,跨机器的文件共享变得困难。

RAGFlow 选择 MinIO 是更合理的路径。MinIO 本身就是为对象存储设计的服务,采用 S3 兼容协议,文件以对象形式存放在桶(Bucket)里,用路径即可访问。它在 RAGFlow 里的角色很像网盘:只管文件的存放和读取,不关心文件内容是什么含义。

还有一层原因和容器化部署有关。RAGFlow 官方推荐用 docker compose 部署,MinIO 作为独立服务,它的数据目录单独挂载在宿主机上。这带来的好处是:哪怕 RAGFlow 应用容器需要升级重建,原始文件数据也不会丢失。这个特性让我在多次升级 RAGFlow 版本的时候非常安心,不用像以前单体应用那样担心升级导致用户上传资料丢失。

3.2 RAGFlow 中的对象流转过程

MinIO 在 RAGFlow 里承接的对象流转,大概分成三个阶段。

第一阶段是上传落地。用户上传 PDF 时,文件先写入 MinIO 的指定桶,写入成功后 MySQL 里才生成文档记录。这个顺序很关键:先有文件,后有元数据,避免出现"数据库有记录但文件找不到"的悬挂引用。

第二阶段是解析读取。文档解析任务启动后,解析服务从 MinIO 拉取原始文件,在内存或临时目录中做版面分析、OCR 识别、文本抽取。解析完之后,有时候还需要把中间产物(比如裁剪出的表格图片)存回 MinIO,供后续"看原文"功能引用。

第三阶段是预览回读。用户在前端点击"查看原始文档"时,后端不经过 MySQL,直接向 MinIO 发起文件读取请求,通过预签名 URL 的方式把文件流返回给浏览器。这一步绕开数据库的好处是,大文件的传输不会占用 MySQL 的连接和内存。

我遇到过的一个坑是:MinIO 的访问凭证到期后,解析任务会批量失败,但界面提示又不够明显。后来我在检查容器日志的时候才发现,报错信息里全是"AccessKeyId does not exist"。所以如果你把 RAGFlow 数据目录整个迁移到新机器,一定要记得检查 MinIO 的部署配置里是否有持久化的环境变量配置,否则容器重建后凭证信息重置,旧数据就"看不见"了。

4. 检索存储层:Elasticsearch 的混合检索战场

如果说 MySQL 是大脑,Elasticsearch 更像 RAGFlow 的"检索肌肉"。所有解析出来的文本块和向量,最终都要在 ES 里完成索引构建,用户的问题也要在这里做召回。这一层对性能的影响最直接,也是优化空间最大的地方。

4.1 索引数据结构和 Mapping

RAGFlow 在 ES 里索引的数据,每个文档(在 ES 语义下)对应一个 chunk。chunk 包含几个关键字段:chunk 的 ID、所属文档的 ID、所属知识库的 ID、chunk 的文本内容、chunk 的向量值(embedding 数组),以及可能有的页码和位置信息。

这些字段的 Mapping 设计是有讲究的。文本字段需要配置分词器,中文环境一般用 IK 分词器,这样"付款条款"可以被切分成有意义的词元;向量字段则声明为 dense_vector 类型,维度和 embedding 模型的输出维度一致(常见的如 768 维或 1024 维),同时要配置相似度度量方式,RAGFlow 默认用余弦相似度来做向量距离计算。

这里有一个容易忽视的细节:向量维度不是随意设置的,它必须和 embedding 模型对齐。如果你切换了 embedding 模型,新模型的向量维度变了,旧索引里的向量数据就全部失效了,必须重建索引。我有一次在界面上切换了模型,结果检索一直返回空,折腾了半天才意识到是维度不匹配导致查询报错。

ES 的索引在 RAGFlow 里是按 embedding 模型维度来组织管理的。每个模型对应一套索引,同一个模型下的多个知识库共享索引,用知识库 ID 字段来做过滤。这种设计避免了"每个知识库建一个索引"带来的资源浪费,因为 ES 的索引数量太多会严重影响集群的资源调度和写入性能。

4.2 从向量召回到底层重排

用户发起查询时,ES 上的操作比想象中复杂。首先,用户的自然语言问题会被同一个 embedding 模型向量化,生成一个查询向量。然后,ES 会同时执行两条检索路径:一条是向量检索,用 HNSW 算法在高维空间里找最近的 topN 个向量;另一条是全文检索,用户问题里的关键词去匹配倒排索引。两条路径的结果合并去重后,进入重排阶段。

重排(Rerank)是 RAGFlow 检索质量的关键。初步召回的结果可能有一两百条,但真正和用户问题语义高度相关的可能只有前几条。RAGFlow 会用一个交叉编码器模型(比如 bge-reranker)对候选 chunk 逐条打分,把分数最高的几条(通常是 topK 条)作为最终结果返回给大模型。

这里要提一个和四层存储有关的点:ES 召回的结果,只包含初步的相似度分数,但 RAGFlow 会从 MySQL 补全 chunk 的元信息(比如原文页码、所属文档标题),从 MinIO 关联原始文件的预览地址。最终呈现给用户的引用来源,实际上是 MySQL、ES、MinIO 三层数据拼装出来的成果。如果引用来源显示异常,排查重点不是 ES,而是元数据层的关联关系是否完整。

检索层的优化心得:不要一上来就调 embedding 模型。先确认 ES 的分片数量和副本数是否合理,再确认查询语句里有没有加知识库过滤条件,最后再考虑调整 topK 和相似度阈值。很多"检索不准"其实是配置问题,不是模型问题。

5. 缓存层:Redis 在 RAGFlow 里到底缓存了什么

Redis 在 RAGFlow 里的存在感最低,容易被忽略,但它撑起了整个系统的并发协调和会话管理。没有 Redis,大批量文件上传和解析时会出各种并发问题。

5.1 会话缓存与并发控制

RAGFlow 的文档解析是一个长耗时任务。一个几十 MB 的 PDF,从上传到解析完成可能要好几分钟。RAGFlow 会把这种长任务拆分成多个子任务并行处理,子任务的进度需要实时汇总。

这时候 Redis 的价值就体现出来了。子任务在 Redis 里写入进度标记,主任务定期读取所有子任务的进度,在界面上展示"正在解析第 3/10 块"。这种设计比直接写在 MySQL 里高效得多,因为进度更新是超高频的写操作——如果每个子任务的每一条进度都要更新 MySQL 字段,数据库的写入压力会非常大,还可能造成行锁竞争。

Redis 还承担了会话上下文的缓存。用户在对话界面里的临时上下文、正在进行的回答状态、等待大模型流式输出时的中间结果,都存在 Redis 里。这些数据的生命周期很短,回答结束后就过期删除,不需要长期持久化。

限流和任务队列的协调也是 Redis 的活。RAGFlow 在并行处理任务时会控制同时运行的数量,避免一次性把所有子任务全部塞给解析服务导致内存溢出。这个协调逻辑用 Redis 的计数器来实现非常方便,还能避免多个 worker 节点同时抢任务造成冲突。

5.2 缓存失效与一致性问题

Redis 缓存有一个天然问题:数据不是强一致的。在 RAGFlow 里,这个问题在"删除知识库""切换模型"这类操作后尤为明显。

举个例子:一个知识库里有 100 个文档,全部解析完并建立了索引。如果用户删除这个知识库,MySQL 里的元数据会删掉,ES 里的索引文档可能也会删掉,但 Redis 里如果还残留着跟这个知识库相关的缓存 key,内存里就有了"死数据"。这些数据占用的内存不大,但如果不定期清理,日积月累也会造成内存碎片。

另外一个常见的缓存问题是会话状态串台。多用户同时使用 RAGFlow 时,Redis 的 key 设计里必须包含会话 ID。我排查过一个"用户 A 的问答案例出现在用户 B 的聊天记录里"的问题,最后发现是 Redis 里 session key 的过期时间设置过长,导致旧会话没有被及时清理,新会话复用了同一个 key。

我的经验是:给 Redis 设置合理的内存淘汰策略,比如 allkeys-lru,让不常用的缓存自动被淘汰。RAGFlow 的缓存数据基本都是可重建的,丢失了重新跑一次任务就行,不需要保护性缓存。

6. 四层协作全链路:一个文件从上传到回答的完整旅程

四层存储分开讲完了,但实际的系统运行是四层联动。我始终觉得,理解了全链路的数据流转,才算真正看懂了 RAGFlow。这一节我以一份 PDF 合同为例子,完整走一遍从上传到最终问答的流程。

6.1 上传与解析阶段

第一步,用户把 PDF 上传到 RAGFlow 前端,文件流先进入 nginx,再由后端转发到 MinIO,落盘到指定桶。这一步完成后,MySQL 的 document 表插入一条记录,状态标记为"已上传待解析"。

第二步,后端创建解析任务,向消息队列投递任务消息。任务消息里携带文档 ID 和存储路径,因为文件本体已经在 MinIO 里了,消息不需要携带文件内容。这一步就是元数据层和对象层的第一次协作:MySQL 提供文档 ID 作为引用,MinIO 提供文件读取路径。

第三步,解析 worker 节点从消息队列拉取任务,从 MinIO 读取原始文件。解析过程包括版面分析、段落切分、OCR 识别、表格提取,最终得到一批 chunk 文本。每个 chunk 带着自己的页码、坐标和文档 ID,这些信息之后会写进 MySQL 和 ES。

第四步,解析完成后,worker 调用 embedding 模型为每个 chunk 生成向量。然后把这些向量连同文本一起批量写入 ES。写入完成后,通过 Redis 上报任务进度,MySQL 的 document 表更新解析状态为"完成"。

6.2 索引与检索阶段

用户发起提问后,流程完全反过来。

第一步,RAGFlow 判断这个问题需要走检索流程,把用户问题和会话 ID 写入 Redis 作为请求上下文。

第二步,系统读取知识库配置里的 embedding 模型信息,把用户的问题文本转成查询向量。这个向量会带着知识库 ID 去 ES 里做检索。

第三步,ES 执行向量检索和全文检索的混合查询,合并结果后做重排,返回 topK 个 chunk 的 ID 列表和对应文本。这一步也是检索层出结果的一步,整个查询通常控制在 100 毫秒以内。

第四步,后端拿着 chunk ID 列表去 MySQL 查询关联的文档信息和 chunk 元数据。比如"这个 chunk 来自《2024年度采购合同.pdf》第 3 页",这些信息用于拼装回答的引用来源。

第五步,系统把所有召回内容和元数据一起组装成 Prompt,发送给大模型。大模型生成回答后,引用来源从 MinIO 获取原始文件预览。最终用户看到的效果是:回答正文 + 引用列表 + 可点击的原文预览。

从这条链路上可以看出来,一个简单的问答背后,四层存储全部参与了一遍。只要任何一层出现延迟或数据异常,用户都会直接感受到——要么回答慢了,要么引用的原文打不开,要么检索结果不相关。

7. 常见问题与排查技巧实录

最后分享一些我实际运维 RAGFlow 过程中的排查经验和技巧。这些问题不一定每个都会遇到,但遇到了之后知道从哪里下手,能省很多时间。

7.1 高频问题排查速查表

问题现象排查思路解决方向
文件上传成功但解析一直卡住检查任务消息队列,看 worker 是否有报错查看容器日志,定位解析报错
解析成功但检索不到内容确认 ES 索引是否写入成功,检查 knowledge base 过滤条件对比 MySQL 任务状态和 ES 文档数量
问答回答慢查看 ES 查询耗时,确认向量检索和重排都参与了调整 ES 分片数量、增加硬件配置
引用来源加载失败确认 MinIO 中的文件是否还存在,检查预签名 URL 有效期检查 MinIO Bucket 配置和凭证有效性
删除知识库后仍能搜到内容确认 ES 索引文档是否同步删除清理 ES 中的残留索引
切换 embedding 模型后检索异常检查向量维度是否匹配删除旧索引并重建知识库索引
容器磁盘空间被撑满查看 MinIO 数据目录大小和 ES 索引大小清理不需要的知识库,归档旧文档

7.2 docker 部署与数据目录规划

RAGFlow 的 docker 部署看起来简单,跑起来也简单,但如果你想长期稳定运行,有几个数据目录规划的细节值得注意。

第一,宿主机上为每个存储组件规划独立挂载点。不要把所有数据卷放在同一个磁盘分区。MySQL、MinIO 和 ES 的 IO 特征完全不同:MySQL 偏随机读写,MinIO 偏顺序读写,ES 的读写压力更大。放在不同磁盘上能有效避免 IO 争抢。SSD 优先给 ES 和 MySQL,机械盘可以用来放 MinIO 的大文件。

第二,ES 的内存设置是性能瓶颈的关键。ES 的 JVM 堆内存默认值可能不适合你的机器配置。堆内存太小会导致频繁 GC,检索延迟飙升。一般来说,给 ES 分配不超过物理内存 50% 的堆内存,留足够空间给操作系统做文件缓存,能获得更好的检索性能。

第三,批量处理文件时控制并发数。RAGFlow 支持批量上传和解析,但一次性塞几百个文件进去,任务队列会瞬间打满,Worker 节点内存可能直接耗尽。我在生产环境里的做法是分批上传,每批控制在 50 个以内,根据机器配置调整。

第四,定期做数据清理和备份。MySQL 可以做逻辑备份,MinIO 可以做桶级别的同步备份,ES 可以做索引快照。不要等磁盘满了再去处理,RAGFlow 的存储组件之间数据强关联,清理某一个组件的数据常常需要联动其他组件,临时处理容易出问题。

7.3 个人实操中的一点体会

用 RAGFlow 一年多,我最深的感触是:这套四层存储架构虽然看起来复杂,但它解决的是真实问题。单机系统用单体数据库可能能跑,一旦数据量上来、并发上来、文档复杂度上来,分层带来的隔离性和弹性优势会越来越明显。

如果你要基于 RAGFlow 做二次开发,我建议优先研究 MySQL 里各表之间的关系,再对比 ES 索引结构,最后才去碰对象存储和缓存。因为整个系统的核心逻辑是"关系数据驱动一切":文件、任务、索引、会话,最终都汇聚到元数据层的记录上。把这条主线的数据模型吃透了,后面所有扩展和问题排查都会轻松很多。

四层存储不是一种炫技,而是一种务实的选择。每一层都有它不可替代的理由,理解这些理由,比死记架构图有用得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 19:55:11

Linux用户管理入门到实战:登录、用户组与权限配置全解析

1. 写在前面:这节笔记要解决什么问题Linux用户管理这块,经常被人当成“会敲几个命令就行”的小事。可实际一上手,添加用户、删除用户、切换用户、调整用户组,每一步都可能踩坑。这篇笔记围绕用户登录与注销、用户管理以及用户组来…

作者头像 李华
网站建设 2026/10/2 19:55:08

FlexSim发生器四种用法详解:从基础参数到复杂供料建模

在FlexSim里做仿真,十有八九是从拖一个发生器开始的。但很多人用了一年发生器,还只会调Inter-Arrival Time那一个参数,结果一遇到复杂的供料节奏就卡壳,要么手工改表、要么写一堆触发器,绕了大远路。这篇文章想聊的就是…

作者头像 李华
网站建设 2026/10/2 19:55:03

Windows软件卸载不干净?火绒卸载工具深度清理残留全攻略

1. 为什么卸载个软件这么难:先搞清残留从哪来 先说个最扎心的场景:你用 Windows 自带的“卸载程序”删掉某个软件,打开 C 盘一看,目录还躺着几十 MB 旧文件;再打开注册表编辑器,一搜软件名字,还…

作者头像 李华
网站建设 2026/10/2 19:54:26

Android Studio 模拟器 HAXM 报错:硬件加速方案与冲突排查

1. 先把报错看明白:它到底在抱怨什么你一觉醒来打开 Android Studio,点那个绿色的运行按钮,AVD 窗口没弹出来,反而在 Event Log 里刷了一行红字:intel haxm is required to run this AVD. HAXM is not installed. Inst…

作者头像 李华
网站建设 2026/10/2 19:54:22

云计算第一次作业实战指南:从概念到云主机部署全攻略

收到“云计算第一次作业”这个题目的时候,大部分人的第一反应其实是懵的:云计算这个概念还没完全吃透,老师就已经要求写报告、做实验了。我刚学云计算那会儿也一样,面对云平台的控制台,按钮一大堆,根本不知…

作者头像 李华
网站建设 2026/10/2 19:52:24

分布式锁原理与实战:Redis、ZooKeeper与数据库方案对比及避坑指南

分布式锁听起来像个老生常谈的技术点,但面试挂在这上面的人一抓一大把。早几年我做电商订单系统的时候,库存扣减和防重复支付两件事就把我折腾得不轻:服务从单体拆成多实例部署之后,原来顺手好用的synchronized和ReentrantLock突然…

作者头像 李华