尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
MySQL MVCC原理详解:从undo log到ReadView的并发控制机制
作为一个和数据库打了多年交道的人每次聊到 MySQLMVCC 都是绕不开的核心话题。不管你是准备面试还是在线上排查死锁、慢查询抑或是纠结为什么 RR可重复读下明明有锁还会有“幻读”争议最后基本都会回到 MVCC 这套机制上。我写这篇总结并不是想复读教科书里那套“多版本并发控制”的定义而是想把 MVCC 从原理到实操从源码逻辑到面试回答完整地捋一遍。这篇文章适合正在准备 MySQL 面试的开发者也适合 DBA 和日常需要优化业务的后端同学读完后你能清楚地知道 MVCC 解决了什么问题、底层是怎么实现的、RC 和 RR 的区别到底是什么以及它和锁是怎么配合的。1. 先搞明白 MVCC 解决的是什么问题1.1 并发事务的三个老大难面试时经常有人被问到“事务隔离级别有哪几种”背答案很容易但很少有人能说清楚为什么要有这些级别它们到底在防什么答案就是并发事务下的三个经典问题脏读、不可重复读、幻读。我习惯用具体场景来说。假设有一张订单表里面有一条订单金额是 100 元。事务 A 把这条金额改成了 200 元但还没提交这时候事务 B 读取这条数据看到的是多少如果 B 看到的是 200并且基于这个“还没提交”的值做了业务判断而 A 最后回滚了那 B 就是读到了一个错误数据这叫脏读。脏读本质上是读到了别人未提交的中间态。不可重复读则发生在同一个事务内。事务 C 先查了一次订单金额得到 100事务 D 此刻修改了这条记录为 200 并提交事务 C 再查一次发现金额变成了 200。同一个事务里同一条记录两次查询结果不一样这就是不可重复读。它扰乱的是一次事务执行过程中对同一数据的多次判断逻辑。幻读比不可重复读更隐蔽。事务 E 第一次执行SELECT * FROM orders WHERE amount 100查出 5 条记录事务 F 插入了一条金额为 150 的新订单并提交事务 E 再次执行同样的查询发现多了一行。多出来的这一行就像“幻觉”一样之前明明不在结果集里现在却出现了。幻读针对的已经不是某一条已存在记录的“值变”而是整个结果集的行数变化。1.2 纯靠加锁有多痛最朴素的想法是既然并发会出问题我就在读之前加个锁写之前也加个锁让所有操作串行化不就行了理论上行得通实践上代价极高。读写全部互斥意味着任意时刻只有一个事务能操作数据并发能力直接归零。对互联网业务来说这是不可接受的——大部分场景都是“读多写少”读读并发完全安全根本没必须写互斥。如果简单粗暴用锁把读和写也互斥掉等于让在线服务花钱买了个“单线程数据库”。所以 MySQL 需要一种机制能让读操作和写操作并发执行写事务之间依然保持隔离同时读事务还能读到某个一致的快照。这就是 MVCC 的价值。1.3 一句话讲清 MVCC 的思路MVCCMulti-Version Concurrency Control的核心思路可以概括为写操作不直接覆盖旧数据而是生成一条新版本读操作选择某个合适的历史版本让读写互不阻塞。可以类比成 Git 的版本管理。你改代码时不是在原文件上直接覆盖到不可恢复而是提交一个新 commit形成一条提交历史。别人可以随时切换到一个旧 commit 查看当时的代码不会因为你正在编辑就把文件锁死。MVCC 也是类似的逻辑数据行背后挂着多个版本每个版本带有自己的时间戳或事务ID读操作通过版本的可见性规则决定自己看到哪一个版本。这个方案让写事务之间可以继续互斥因为真正改数据必须基于最新版本但读事务完全不需要加锁甚至可以在写事务还没提交时就读旧版本读写从此井水不犯河水。2. MVCC 的地基隐藏列、undo log 与版本链2.1 数据行上的三个隐藏字段说到 MVCC 就不得不提 InnoDB 聚簇索引结构里的隐藏列。不要以为一行数据只包含你建表时定义的字段实际上每一行还藏着三个和 MVCC 直接相关的属性DB_TRX_ID最后修改该行的事务 ID。DB_ROLL_PTR回滚指针指向该行之前的版本在 undo log 中的位置。DB_ROW_ID行 ID如果没有指定主键且没有非空唯一键 InnoDB 会用它作为聚簇索引键。这三个隐藏列是 MVCC 的物理基础。事务在修改某一行时不是把这行的旧值直接抹掉而是再生成一个新版本新版本的DB_TRX_ID记录自己的事务 IDDB_ROLL_PTR则指向旧版本的位置。从逻辑上看这一行其实变成了一条由多个版本串起来的链表链尾是最新值链头是最老的版本。没错还可以补一句话DB_TRX_ID不只是记录事务 ID还充当了版本链上的“时间戳”因为事务 ID 是严格递增的所以事务 ID 越大表示修改发生得越晚。版本新旧本质上不是看时间而是看事务 ID 的先后。2.2 undo log 如何保存历史版本隐藏列里的DB_ROLL_PTR指向的正是 undo log。每次事务对数据进行修改UPDATE 或 DELETEInnoDB 都会先把旧值写入 undo log然后才更新数据行。具体来说undo log 里存的是一个“反向操作”。如果当前操作是 UPDATEundo log 里记录的是更新前的旧值如果操作是 DELETEundo log 里记录的是被删除行的原始内容。这样做的直接用途有两个事务回滚时可以用 undo log 把数据恢复MVCC 读取历史版本时也要通过 undo log 找到之前的数据。这里有个值得注意的点DELETE 在 MVCC 世界里并不是物理删除而是给该行标记为已删除它的旧版本仍然留在版本链中。真正把数据从磁盘清掉是后面 purge 线程通过判断没有任何事务需要该版本了才悄悄完成的。2.3 版本链的完整生命周期结合隐藏列和 undo log我们可以还原一条记录从诞生到被多次修改的完整版本链。假设一行记录初始由事务ID10 插入。此时版本信息是trx_id10, roll_ptrnull。接着事务ID20 对它执行 UPDATE旧值被写进 undo log版本链变成新版本trx_id20的DB_ROLL_PTR指向旧版本trx_id10。然后事务ID30 再 UPDATE 一次新版本trx_id30的指针继续指向trx_id20的版本。这样一条记录就形成了30 - 20 - 10的版本链。任何读事务只需要顺着DB_ROLL_PTR往回找就可能读到旧版本。而应该停在哪个版本上依赖的就是后面要讲的 ReadView 可见性判断。顺便提示一句如果版本链太长说明这条记录被频繁修改对应的 undo log 也会很大。这不仅仅影响读取时的遍历成本更会影响数据库的膨胀和清理。所以业务上尽量避免对同一条记录做高频 UPDATE这在后面“常见问题”里我还会细说。3. ReadViewMVCC 的可见性判官3.1 一致性视图到底长什么样MVCC 读操作使用的是快照读它读的是一张“一致性视图”。这个视图就是 ReadView。ReadView 并不是什么复杂的数据结构它内部维护了几个关键属性m_ids生成 ReadView 时当前系统中所有活跃未提交事务的 ID 列表。min_trx_idm_ids中最小的事务 ID。max_trx_id生成 ReadView 时系统尚未分配的下一个事务 ID。注意这个值不是某个事务的 ID而是“边界值”所有大于等于max_trx_id的事务对当前 ReadView 都是不可见的。creator_trx_id创建这个 ReadView 的事务自己的事务 ID。可见性规则就是围绕这四个值展开的。你可以把 ReadView 想象成一张“在某个瞬间拍下的照片”。照片只反映按下快门那一刻的事务状态。之后提交的新事务在这张照片里一律不可见。3.2 每一行版本的可见性判断算法当读操作遍历版本链时对每个版本都会执行以下判断逻辑决定是否使用该版本假设当前版本的事务 ID 为trx_id。如果trx_id creator_trx_id表示这个版本是本事务自己修改的那必须可见。自己改的东西自己看不到业务就彻底乱套了。如果trx_id min_trx_id表示修改该版本的事务在 ReadView 生成之前就已经提交该版本可见。如果trx_id max_trx_id表示修改该版本的事务是在 ReadView 生成之后才启动的事务该版本不可见。如果min_trx_id trx_id max_trx_id则需要进一步判断trx_id是否在m_ids列表中如果在m_ids列表中说明该事务尚未提交该版本不可见。如果不在m_ids列表中说明事务已经提交该版本可见。如果当前版本不可见沿着DB_ROLL_PTR指针找到上一个版本重新执行整套判断直到找到第一个可见的版本为止。这里我想强调一个易错点判断事务是否提交看的不是“事务当前有没有结束”而是“在 ReadView 生成的那一刻它是否已经提交”。这正是快照读和当前读最根本的区别。快照读的可见性在 ReadView 生成时就固定了之后别人再提交也不影响。3.3 一个具体的判断演练为了更好理解上面的算法我用一个具体例子走一遍。假设当前系统事务 ID 已经分配到了 100。事务 AID90启动并创建 ReadView。此时系统中有三个未提交事务ID80、ID90A 自己、ID95。同时 ID70 的事务已经提交。那么 A 的 ReadView 参数是m_ids[80, 90, 95]min_trx_id80max_trx_id101下一个待分配的 IDcreator_trx_id90。现在 A 查询一条记录版本链上有三个版本分别由事务 70、85、98 修改。版本 70trx_id70 min_trx_id(80)可见。版本 85min_trx_id(80) 85 max_trx_id(101)且 85 不在m_ids中m_ids里没有 85说明它已提交可见。版本 9898 max_trx_id(101)不成立注意 98 小于 101所以继续走第四步。98 在m_ids列表中吗不在所以 98 已提交可见。等等这个例子有个细节要纠正。max_trx_id是 101所以 98 属于[80, 101)区间它不在m_ids列表中意味着是“在 ReadView 生成前已提交”的事务。所以版本 98 也是可见的。我们换个稍微不同的场景。如果事务 98 在 A 创建 ReadView 时还未提交那么m_ids就应该包含 98此时 98 版本对 A 就是不可见的A 需要沿着指针找旧版本。也就是说一个事务如果是 A 启动之后才启动并提交的只要它启动时间晚于 ReadView 生成它对 A 的快照就是不可见的。这就是为什么 RR 级别下一个事务内多次快照读结果完全一样。4. 核心对比RC 与 RR 下 MVCC 的差异4.1 ReadView 的生成时机完全不同MVCC 中的可见性判断依赖 ReadView但 ReadView 什么时机生成数据库在不同隔离级别下的策略是不同的。这是 RC 和 RR 在 MVCC 层面最大的分水岭。在 RC读已提交隔离级别下每次执行快照读都会生成一个新的 ReadView。这意味着事务 T1 第一次查询生成 ReadView1第二次查询又会生成 ReadView2。如果在这期间有其他事务提交了ReadView2 就会看到新提交的内容。这正好解释了 RC 为什么会出现不可重复读——同一事务两次读的其实是不同时刻的数据库快照。在 RR可重复读隔离级别下只有事务内第一次执行快照读时才会生成 ReadView之后所有快照读都复用同一个 ReadView。那事务 T1 无论执行多少次 SELECT看到的都是同一张“老照片”其他事务提交了多少次都不影响。这就是“可重复读”名称的由来。4.2 用一张表说清两者差异维度RC读已提交RR可重复读ReadView 生成时机每次快照读都生成新 ReadView事务内第一次快照读生成后续复用能否避免脏读能只看到已提交能能否避免不可重复读不能会读到最新已提交值能快照固定能否避免幻读不能新插入记录会被读到快照读能当前读需要锁配合适用场景业务需要实时看到最新提交结果需要事务内数据一致性比如报表类4.3 实测验证 RC 和 RR 的差别纸上谈兵意义不大我用一个实际场景带着大家验证一把。建一张简单的测试表CREATE TABLE t_account ( id INT PRIMARY KEY, balance INT ) ENGINEInnoDB; INSERT INTO t_account VALUES (1, 100);先把会话隔离级别调整为 RCSET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;事务 T1 执行第一次查询读到 100事务 T2 执行UPDATE t_account SET balance200 WHERE id1并提交。T1 再执行一次查询你会看到 balance 变成 200。这就是 RC 下的不可重复读现象。把隔离级别改成 RRSET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;同样的操作顺序事务 T1 在 T2 提交后再次查询balance 依然是 100。事务 T1 从头到尾只“看”到了自己快照生成那一刻的数据。这个验证建议你亲自跑一遍因为只记住结论而不动手很容易在面试时被追问细节就答不流畅。5. 快照读与当前读的界限MVCC 和锁如何配合5.1 两种读模式的本质区别InnoDB 中SELECT 分两类加锁的是当前读不加锁的是快照读。快照读就是普通的SELECT它通过 MVCC 直接读取可见版本不需要加锁。当前读则包括SELECT ... FOR UPDATE、SELECT ... LOCK IN SHARE MODE、UPDATE和DELETE。当前读必须读取记录的最新版本并且对读取的记录加锁防止其他事务并发修改。为什么当前读不能走 MVCC因为像UPDATE这类操作必须基于最新值进行修改否则就会出现丢失更新问题。假设事务 A 通过快照读到 balance100事务 B 已经把它改成了 200A 再基于 100 做balancebalance50操作就会把 B 的改动覆盖掉。所以修改类操作必须走当前读读取最新值同时借助锁来和其他修改事务互斥。MVCC 管的是“读旧版本”的快照读锁管的是“操作最新版本”的当前读。两者看似是两套体系但其实互补共生。5.2 RR 下的幻读为什么还需要锁来兜底很多人误以为 RR 隔离级别下 MVCC 已经天然解决了幻读这是不对的。MVCC 解决的只是快照读场景下的幻读同一事务内多次普通 SELECT结果集保持一致。但当前读场景下MVCC 没有办法兜住并发插入。举个例子。RR 下事务 T1 执行SELECT * FROM t_account WHERE balance 100 FOR UPDATE;此时所有满足条件的记录被加锁但 balance 100 的范围内没有记录锁自然也没加到任何行上。如果事务 T2 此时插入一条 balance150 的记录然后提交T1 再执行同样的FOR UPDATE查询就会发现多了一行。为了堵住这个漏洞InnoDB 引入了间隙锁Gap Lock和临键锁Next-Key Lock。在 RR 级别下当前读不仅会锁住命中的记录还会锁住它们之间的间隙。上面的例子中查询范围是 balance 100那么 (100, ∞) 这个区间会被间隙锁锁住T2 在该区间内插入记录就会被阻塞直到 T1 提交。这样就解决了当前读下的幻读问题。所以严格来说RR 解决幻读是“MVCC 解决快照读幻读 间隙锁解决当前读幻读”的组合拳缺一不可。这也是为什么面试时你要把 MVCC 和锁放在一起讲而不是分开答。5.3 一个常见的误解UPDATE 也会触发锁很多业务开发同学以为 MVCC 能规避所有锁竞争于是写代码时完全不考虑并发控制。实际上 UPDATE 和 DELETE 走的是当前读遇到目标行被其他事务锁定一样会阻塞。我以前排查过一个线上问题某个热点账户的余额字段被大量 UPDATE导致接口耗时从 20ms 涨到 3s 以上。原因就是这个账户的单行记录上同时存在多个未提交事务每个 UPDATE 都在等待前一个事务提交形成排队。这个场景下 MVCC 一点忙都帮不上因为写写操作天然互斥唯一能做的就是优化业务减少对同一行的热点更新或者使用更合理的分桶策略。这一点必须牢记MVCC 解决的是读写冲突而不是写写冲突。6. 实战感悟MVCC 相关的典型问题和面试高频题6.1 长事务引发的三种连锁问题MVCC 机制的无锁读体验很美好但长事务会把这个美好一点点拖垮。我在 SQL 优化和故障排查中遇到过不少因为长事务导致的事故这里集中聊一聊。首先是 undo log 膨胀。MVCC 需要保留历史版本历史版本就存在 undo log 里。如果有事务迟迟不提交它创建的 ReadView 会一直引用旧版本InnoDB 的 purge 线程就不能清理这些版本。事务执行时间越久历史底稿积压越多undo 表空间就会持续膨胀。极端情况下磁盘空间会被撑爆实例被迫进入只读模式那基本就是事故级别了。其次是慢查询。版本链长度增加后每次快照读沿着DB_ROLL_PTR遍历的代价就更大。尤其是一些大表一条记录被频繁更新后版本链可能上百条普通查询直接从读取数据变成遍历链表时延成倍增长。最后是一致性问题的复杂度。长事务的 ReadView 保留时间太长会让数据库垃圾清理机制无法正常推进进而影响所有事务。所以我在实际工作中有一条硬规矩业务代码里的事务必须短小精悍绝不允许在事务内执行远程调用、大循环、复杂计算这类耗时操作。本质就是在保护 MVCC 的版本链不至于失控。6.2 排查 MVCC 相关问题的三个常用命令发现问题之后怎么定位我常用的工具和手段如下。用information_schema.innodb_trx查询当前所有活跃事务重点看trx_started字段SELECT trx_id, trx_state, trx_started, TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS running_seconds, trx_mysql_thread_id FROM information_schema.innodb_trx ORDER BY running_seconds DESC;这条语句可以快速定位运行时间最长的几个事务结合业务日志找到对应连接判断是不是长事务源头。如果怀疑 undo log 膨胀可以用以下命令查看SHOW ENGINE INNODB STATUS;输出信息里会包含History list length这个值越大表示未清理的历史版本越多。我一般会在监控里持续跟踪这个指标一旦发现趋势性上升就说明系统里存在长事务或大量更新操作。想进一步定位到具体连接可以用performance_schema查询事务对应线程的 SQL 语句SELECT THREAD_ID, EVENT_NAME, SQL_TEXT FROM performance_schema.events_statements_current WHERE THREAD_ID IN ( SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID 具体连接ID );这套组合拳基本可以应对日常 MVCC 相关的性能排查。6.3 面试问 MVCC 时回答层次怎么铺作为面试官我听到过太多把 MVCC 背得滚瓜烂熟、但深入一聊就漏洞百出的回答。这里我把考察层次拆开讲给出我认为最稳固的回答路径。第一层用一句话说清 MVCC 是什么。我会这样起头“MVCC 是 MySQL 通过保存历史版本和一致性视图让读操作不加锁也能读到一致数据从而解决读写冲突的并发控制机制。”第二层解释版本链和 ReadView。说明每行记录通过DB_TRX_ID和DB_ROLL_PTR维护版本链undo log 保存旧值同时说明 ReadView 包含m_ids、min_trx_id、max_trx_id、creator_trx_id四个部分可见性判断依据这四者推导。第三层对比 RC 和 RR 下 ReadView 的生成时机并点出这直接决定了不可重复读能否被规避。第四层把 MVCC 和锁的关系讲透指出快照读依赖 MVCC、当前读依赖锁、RR 下当前读的幻读依赖间隙锁兜底。只要这四层都能说清楚面试官基本就认可你是真正理解 MVCC而不是背了一篇八股文。6.4 关于 MVCC 的四个高频追问与参考回答接下来把几个追问最频繁的问题整理成速查表每个问题我附上我认为比较稳妥的答题角度。高频问题核心答题角度MVCC 是如何解决脏读的脏读源于读到未提交事务的修改。ReadView 中未提交事务的 ID 在m_ids中快照读遇到trx_id在m_ids中的版本会直接跳过所以看不到未提交数据。为什么 RR 还会出现幻读RR 下快照读通过复用 ReadView 避免了幻读但当前读必须读最新值且会加行锁锁不住间隙时新插入数据仍会出现所以需要间隙锁补位。RC 下为什么 undo log 清理更及时RC 每次快照读生成新的 ReadView旧 ReadView 很快失效历史版本可被更快清理。而 RR 的 ReadView 持续到事务结束清理明显更滞后。只读事务会不会产生事务 ID在只读事务中如果它不修改数据InnoDB 通过trx_assign_read_view机制可以不分配事务 ID而是使用只读视图或直接读取。但一旦涉及写操作事务 ID 还是会被分配。面试能提到这点会显得很有深度。6.5 给业务写代码时的两句话提醒文章快要结尾时我还是想从实战角度再给两句提醒因为原理理解到位了业务代码却写错照样白搭。第一句事务尽量短提交尽量快。事务整个生命周期里ReadView 都不会释放。一个事务挂得越久它身后的垃圾历史版本就越堆积。很多 DBA 老手喜欢看History list length就是这个原因。第二句热点行的 UPDATE 没有 MVCC 护驾。从业务系统角度来说如果某个字段比如库存、余额会被大量并发更新光指望数据库隔离机制是不够的。可以考虑在应用层做行级合并更新或者利用 CAS 思想配合版本号字段来减少锁冲突。一句话写写冲突永远要用更聪明的业务逻辑来化解而不是指望数据库无限承载。MVCC 是一个非常精巧的设计理解透它的内部结构、可见性判断、隔离级别差异和与锁的配合关系你对 MySQL 的认知会上一个台阶。这篇是我多年来阅读源码、排查性能问题、准备面试的综合性总结把原理、实践、面试的每个切口都覆盖到了。如果还有没讲透的地方欢迎在评论区交流互相补充。
RELATED

相关推荐

Prototypical Networks原理与PyTorch实战:少样本学习的度量范式

Prototypical Networks原理与PyTorch实战:少样本学习的度量范式

1. 为什么原形网络不是“另一个分类模型”,而是少样本学习的底层范式重构Prototypical Networks(原形网络)这个词,第一次看到时我下意识以为是某种带原型设计的CNN变体——直到我在一个医疗影像项目里被逼到绝境:手头只…

📅 2026/10/5 3:18:43
GIKT知识追踪实战:图卷积网络与LSTM融合的题目-技能二部图建模

GIKT知识追踪实战:图卷积网络与LSTM融合的题目-技能二部图建模

简介:面向在线教育平台知识追踪任务的研究者与工程技术人员,这份资源围绕基于图卷积网络的GIKT模型展开,用于缓解题目-技能数据稀疏与多技能关联带来的预测难题,提升对学生新题目掌握程度的预测准确性。资源包共1个PDF文件&#x…

📅 2026/10/5 3:18:43
大模型+智慧河长:从巡河识别到知识问答的落地实践

大模型+智慧河长:从巡河识别到知识问答的落地实践

简介:这份PPT资料面向水利信息化从业者、智慧水务方案设计人员及河长制管理平台开发者,围绕大模型与智慧河长理念的结合,系统梳理河流管理从现状痛点到落地实施的完整思路。内容涵盖大模型技术原理与应用场景、智慧河长系统分层架构设计、水质…

📅 2026/10/5 3:18:43
MORE NEWS

更多资讯

📰

8款AI论文写作软件实测:自考论文从选题到降重全流程推荐

自考本、专升本、成人本科的朋友们,写到论文这一关,是不是感觉比考十门课还头疼?选题没方向、大纲不会列、正文憋不出来、查重还得一降再降,关键是身边没人能帮你逐句改。我自己当年就是被论文折腾掉一层皮,所以这两年…

📰

社区医院管理系统实战:SpringBoot+Vue+MyBatis+MySQL架构解析

1. 项目概述与系统定位1.1 这套系统的核心价值与适用人群做社区医院管理系统,和做电商、OA这类系统完全不是一个思路。社区医院的业务流非常固定:挂号、分诊、门诊、收费、发药、留观,再加上医保结算和日常统计报表,流程清晰但环节…

📰

燃料电池混合动力汽车能量管理:ADMM双层凸优化Matlab实践

“ADMM”“双层凸优化”“Matlab”这三个词往燃料电池混合动力汽车上一叠,很多人第一反应是:这又是一篇纯堆数学的论文复现,跟工程没什么关系。我去年做燃料电池能量管理策略时,恰好把这套框架从文献里的公式一路跑到Matlab可仿真…

📰

Python堆与heapq:TopK、优先队列与内存优化实战

前阵子帮一个做日志分析的同事改代码,他那段程序要从每天上亿条请求日志里捞出响应时间最长的100条。第一版实现特别直白:全量解析完排个序,再切片取前100。结果呢?近一亿条记录解析完直接吃掉16G内存,光排序就跑了40多…

📰

高质量数据集构建与治理:从定义到落地的全流程实践

这两年,凡是做AI的,几乎没有谁没被“垃圾进,垃圾出”这句话扎过心。模型结构换了一茬又一茬,算力也堆了不少,最后发现决定效果上限的,往往就是你喂进去的数据。高质量数据集的构建和治理,也从后…

📰

Linux进程间通信实战:管道、共享内存与信号量的选型与陷阱

先说一个我早年间遇到的真实场景:一台采集服务器上跑了四个分析进程,每隔几秒就要从主进程手里取一批日志数据。最开始我图省事,直接用文件落地加轮询,结果不仅因为文件锁搞得调度顺序乱,还白白多了很多磁盘IO。后来老…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬