news 2026/9/26 5:54:07

MySQL自增主键与隐藏row_id:从原理到工程化排雷

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL自增主键与隐藏row_id:从原理到工程化排雷

前几天刚处理完一个线上的“怪故障”:某个订单表稳定运行了几年,某天开始持续报主键冲突,新数据写不进去。当时第一反应是某条脏数据导致的重复写入,查了很久才发现,这张表用的自增主键是int,而上限 2147483647 已经快到了。业务每天写入量很大,自增 ID 悄悄爬到边界,InnoDB 不再允许新插入。

MySQL 自增主键 ID 和隐藏 row_id 是两套容易被搞混、但实际完全不同的行标识机制。前者是我们日常写的AUTO_INCREMENT列,以业务列的形式存在;后者是 InnoDB 在没有主键、也没有非空唯一键时,在内部生成的一个 6 字节全局递增数字,用来构造聚簇索引。这两个机制都回答同一个问题:这一行在存储引擎里到底怎么被唯一标识?

这篇文章不玩偏门玩法,只围绕自增主键、row_id、工程化落地三个点展开。我会从底层原理讲到风险边界,再给出可以照着抄的监控和改造步骤。适合两类人看:一类是刚接触 MySQL、正在纠结“int 还是 bigint”的开发者;另一类是已经维护了大量表、需要提前排雷的 DBA 或后端负责人。

1. 自增主键与隐藏 row_id:两套机制,一个核心问题

1.1 自增主键:你最熟悉的“显式主键”

自增主键用起来很简单:

CREATE TABLE t_order ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, order_no VARCHAR(64) NOT NULL, amount DECIMAL(10,2) NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) );

每次插入一行,如果没指定id,MySQL 会自动分配一个比当前计数器更大的值。只要表里存在这个主键,InnoDB 的聚簇索引就直接用主键值来组织数据,二级索引的叶子节点也会存主键值。也就是说,主键决定了整行数据在物理上的存放位置。

自增主键最大的优势是“有序”。新插入的行永远排在已有行后面,页面分裂和随机 IO 都很少。对大部分业务来说,这就是最简单、最不容易出错的主键方案。

但“简单”不等于“没有边界”。自增主键的边界在列类型上:int上限 21.5 亿左右,int unsigned上限约 42.9 亿,bigint unsigned上限约 1844 亿亿。类型选小了,迟早会遇到开头说的那种事故。

1.2 隐藏 row_id:InnoDB 的“兜底方案”

如果一张 InnoDB 表既没定义主键,也没有非空的唯一键,InnoDB 不会傻傻地报错,而是会默默给你生成一个隐藏的 6 字节整型列,官方叫它ROW_ID。这个列只有一个用途:作为聚簇索引的键,把行物理地组织起来。

注意几个关键点:

  • 这个 row_id 是全局共享的,不是每张表一个独立计数器。整个实例的 InnoDB 表共用同一个递增序列。
  • 它的值域是 6 字节无符号整型,最大值是 2^48 - 1,换算过来大约是 281 万亿。
  • 这个列对业务完全不可见,你无法通过SELECT去读取它,也无法在 SQL 里引用它。
  • 如果表有一个非空唯一键,InnoDB 会优先用这个唯一键当聚簇索引,不会生成隐藏 row_id。严格说,只有“没有主键且没有非空唯一键”的表才会走这条兜底路径。

很多开发者在建表时偷懒,不定义主键,觉得“反正 MySQL 会自己处理”。MySQL 确实能处理,但处理方式给你埋了一颗不知道什么时候会爆的雷。

1.3 一张表对比两者的核心差异

对比项自增主键 ID隐藏 row_id
定义方式显式定义PRIMARY KEY AUTO_INCREMENTInnoDB 内部自动生成
业务可见性完全可见,可被查询和引用完全不可见,无法用 SQL 访问
计数范围取决于列类型,int/bigint 各有上限固定 6 字节,上限 2^48 - 1
计数维度每张表独立计数器整个实例所有 InnoDB 表共享
物理作用聚簇索引键聚簇索引键
典型问题类型上限耗尽,写入失败全局回卷,存在重复键风险
运维建议务必显式定义不建议依赖,尽早改造

看到这儿你应该明白了:自增主键是你可以掌控的,而隐藏 row_id 是引擎为了能工作而硬造的。把“行怎么标识”这个关键决策交给引擎的静默逻辑,是风险管理上最忌讳的事。

2. 自增主键的分配机制与常见误区

2.1 AUTO_INCREMENT 计数器:内存 + 持久化

InnoDB 为每个带自增列的表维护一个AUTO_INCREMENT计数器。插入时如果没显式指定该列值,就取当前计数器值,然后计数器加 1。

这里有一个版本差异需要注意:在 MySQL 8.0 之前,计数器主要缓存在内存中,MySQL 重启后 InnoDB 会通过SELECT MAX(id) FROM t恢复计数。如果业务在重启前删掉了最大 ID 的行,重启后自增可能从更小的值继续,造成主键重用。这个问题一旦发生,往往意味着历史引用错乱,排查起来非常痛苦。

MySQL 8.0 开始,自增计数器的状态会写入 redo log 并持久化,重启后不会再靠扫表恢复。数据库自己追平了这个隐患,但如果你维护的实例还是 5.7 或更老版本,就仍然要小心重启带来的 ID 重用风险。

2.2 自增锁模式如何影响 ID 连续性

InnoDB 生成自增值时需要使用锁,锁的力度由参数innodb_autoinc_lock_mode决定。简单理解:

  • 模式 0:传统模式,所有自增操作都持有表级锁,直到语句结束才释放。最安全,但并发写入体验最差。
  • 模式 1:连续模式,简单插入用轻量互斥量,批量插入仍用表锁。ID 总体连续,是 MySQL 5.7 的默认值。
  • 模式 2:交错模式,所有自增操作都用互斥量,高并发下 ID 可能交错不连续。MySQL 8.0 将默认值改成了这个模式。

这里要特别提醒:如果你还在用基于语句的 binlog 复制(binlog_format=STATEMENT),自增锁模式不当可能导致主从数据不一致。比如主库用模式 2 时,两条并发插入的语句可能先取 ID 后写 binlog,从库重放顺序和主库实际提交顺序不一致,从库拿到的 ID 就和主库不同。

现代生产环境我强烈建议把 binlog 格式改成ROW。这样从库不依赖自增生成逻辑去推导 ID,可以最大程度避免这类复制偏差。如果你因为历史原因必须用 STATEMENT,请把自增锁模式保持在 0 或 1。

2.3 为什么你总会看到自增 ID 跳号

很多初学者第一次发现表里自增 ID 中间缺了一大段,会怀疑系统出了问题。其实跳号是自增机制的正常副作用,最常见的几个来源是:

  • 插入事务回滚。事务里包含插入操作,回滚时已经分配出去的 ID 不会归还到计数器里。
  • 批量插入预留。INSERT ... SELECT、LOAD DATA这类批量操作一次性申请一批 ID,即使后续有部分行失败,预留的 ID 也消耗掉了。
  • INSERT ... ON DUPLICATE KEY UPDATE。如果插入的记录触发了重复键冲突进而执行更新,那次插入仍会消耗一个自增 ID。
  • 删除操作。删掉最大 ID 的行后,计数器通常不会回退。

所以当你看到主键 ID 出现空洞时,先不要慌。只要监控里没有堆积大量锁等待或错误日志,空洞基本都是正常现象。真正要关注的是“当前计数器和上限之间的距离”,而不是“ID 是否连续”。

3. row_id 的生成逻辑与隐藏的全局隐患

3.1 没有主键时 InnoDB 到底怎么存

假设你建了这样一张表:

CREATE TABLE t_log ( content TEXT, created_at DATETIME );

没有主键,没有唯一键,普通二级索引也没有。InnoDB 在内部会生成隐藏的ROW_ID列,作为聚簇索引的键。插入时这个值从全局计数器取,整体趋势是递增的。

麻烦在于,这张表可能有二级索引。比如再加一个CREATE INDEX idx_created_at ON t_log(created_at),二级索引的叶子节点需要指向聚簇索引的键。有主键的表存主键值,没有主键的表就只能存这个隐藏 row_id。外部无法拿到 row_id,也就意味着你无法通过二级索引做精确、高效的“定位型”操作。

更关键的是,这个全局计数器是所有 InnoDB 表共用的。你以为每张无主键表都有自己独立的 row_id 序列,其实它们在同一个大池子里取号。一张表写入量大,会拖着其他无主键表的计数器一起往前走。这种全局耦合,是很多人完全没有预期的。

3.2 row_id 回卷:看似遥远但真实的雷

6 字节的 row_id 上限是 2^48 - 1,也就是大约 2.8 × 10^14。单张表要写入这么多行,对绝大多数业务来说几乎不可能。但“几乎不可能”不代表“不会”。

真正需要考虑的是全局共享:只要实例里所有无主键表的累计写入量达到这个量级,整个实例的无主键表都会面临 row_id 回卷。回卷之后,新生成的 row_id 会从 0 开始继续递增,如果恰好撞上一张表里已经存在的 row_id,聚簇索引就会碰到重复键。表现可能是新行插入报错,也可能在不同版本下产生更复杂的数据覆盖风险。

就算没有回卷,无主键表还会遇到另一个尴尬:你无法用业务手段持续追踪某一行。运营想根据“行号”精确更新一条数据,发现拿不到任何稳定标识;排查数据问题时只能靠全列匹配。运维和研发成本都会显著上升。

所以我的建议很简单:不要依赖 InnoDB 的兜底机制。row_id 是引擎的备用轮胎,它存在是为了让表能用,不是让你开一辈子不换胎。

3.3_rowid与隐藏 row_id:名字像,不是一回事

MySQL 里有个_rowid的写法,很多人误以为它能直接查出 InnoDB 隐藏 row_id。实际上两者没有任何关系。

_rowid是 MySQL 提供的“别名”,它只会指向表里的一个数字主键,或者第一个非空的唯一键。比如表里有一个id主键,SELECT _rowid FROM t返回的就是主键值。如果表既没有数字主键也没有合适的唯一键,这个查询会直接报错。

隐藏的 6 字节 row_id 是 InnoDB 存储引擎内部概念,SQL 层根本没有任何接口可以直接读取。你在官方文档里查它,也只在“聚簇索引如何生成”这个章节出现。

一句话总结:业务上能看到的_rowid是假的,引擎内部藏着真正干活的 row_id 才是决定无主键表命运的关键。

4. 风险剖析:从 ID 耗尽到无主键表的连锁问题

4.1 int 与 bigint:容量边界决定你的抢救窗口

自增主键最经典的风险就是类型耗尽。不同列类型的容量差别非常大:

  • int(有符号):上限 2147483647,约 21.5 亿。
  • int unsigned:上限 4294967295,约 42.9 亿。
  • bigint(有符号):上限 9223372036854775807,约 9.2 × 10^18。
  • bigint unsigned:上限 18446744073709551615,约 1.8 × 10^19。

计算容量不能只看“够不够大”,要看“增长速率”。比如一个电商订单表,如果每天新增 1000 万行,int理论上 214 天就会耗尽。哪怕日增 10 万行,也需要 5.8 年才能到边界。很多团队觉得 5 年很遥远,但系统上线 5 年后还在高速增长的情况太常见了。

真正危险的不是慢增长,而是**“从未监控”**。等到报警出现时,通常已经晚了。自增 ID 耗尽的现场表现很直接:新的INSERT语句报主键重复,或者干脆报自增读取失败,主库写入被锁死,从库可能被跳过,整个业务链路被拖崩。

这里还有一个隐蔽陷阱:int有符号列如果因为某些历史原因已经出现过负数 ID,那么自增计数器依然会从正数继续递增,两个方向的值都可能存在。这会让外部分页、排序和引用逻辑出现各种奇奇怪怪的边界问题,只有改列类型才能彻底解决。

4.2 无主键表为什么会拖垮运维和复制

无主键表不是“能用就行”,它在运维层面带来的麻烦几乎是必然的。

第一,行定位困难。MySQL 的 binlog 以行格式记录变更时,需要通过主键或唯一键定位行。没有主键的表,无法高效定位,只能把整行的所有列作为判定条件。遇到一模一样的重复行,UPDATE 和 DELETE 的语义都可能出问题。组复制、半同步复制对无主键表的容忍度也远低于有主键表。

第二,数据订正困难。线上偶尔要按条件修改某条异常数据,DBA 会写UPDATE t SET ... WHERE 某个业务字段 = ...。如果这个业务字段没唯一索引,就可能影响多行。有主键时我们可以拿主键精确锁定,无主键就只能提心吊胆地更新。

第三,主从切换风险。切换过程中如果从库需要通过行事件定位数据,而无主键表恰好有多行完全相同的记录,复制就可能在从库上产生“找不到匹配行”或“更新了多行”的报错。这几乎是定时炸弹。

所以,我在团队里有一条硬性要求:所有 MySQL 表必须有主键,没有的限期改造。这条规则不是为了好看,是为了让后续所有工程操作都有底盘可以踩。

4.3 自增主键的复制一致性风险

自增主键本身不是“零风险”,它和复制配置强相关。

在主从架构里,主库生成自增 ID 的顺序和 binlog 写入顺序不一定完全一致。如果遇到并发插入,语句 A 可能先分配 ID 1、3,语句 B 分配 ID 2、4,最后提交顺序却是 B 先、A 后。在 statement 复制模式下,从库重放语句时重新计算自增值,可能得出完全不同的 ID。

解决方案按优先级排序:

  1. 使用binlog_format=ROW。
  2. 保持主从自增锁模式一致。
  3. 需要严格 ID 连续的场景,考虑不用数据库自增,而是用中心化发号器。

在实际操作中,第 1 条基本就能解决绝大多数复制一致性问题。如果你还停留在 statement 模式,建议尽快评估升级成本。

5. 工程化落地:选型、改造与监控

5.1 主键类型怎么选:无脑默认 bigint unsigned

很多表结构设计规范里主键类型写的是int,理由是“够用且节省空间”。但在今天的硬件环境和业务增长速率下,为了省那 4 个字节去选int,性价比很低。

如果让我给一个默认值,那就是bigint unsigned。聚簇索引叶子节点存主键时,二级索引也会冗余一份主键值。主键更大,索引确实会更大,但由此换来的容量余量足以覆盖绝大多数业务的增长曲线。特别是互联网业务,一旦爆量,一个晚上就能把未来三年的自增配额吃掉。

建表示例:

CREATE TABLE t_order ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, order_no VARCHAR(64) NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINE=InnoDB;

如果你的库已经上线比较久,且大量表是int主键,建议把核心表逐步迁移到bigint unsigned。迁移方式很简单:

ALTER TABLE t_order MODIFY COLUMN id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT;

这条 DDL 在 MySQL 5.6+ 的在线 DDL 机制下通常不会长时间阻塞读写,但还是建议在低峰期操作,老版本尤其要小心。

5.2 无主键表识别与在线改造实操

先找出所有没有主键的 InnoDB 表:

SELECT t.TABLE_SCHEMA, t.TABLE_NAME, t.TABLE_ROWS FROM information_schema.TABLES t WHERE t.TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys') AND t.ENGINE = 'InnoDB' AND t.TABLE_TYPE = 'BASE TABLE' AND NOT EXISTS ( SELECT 1 FROM information_schema.TABLE_CONSTRAINTS tc WHERE tc.TABLE_SCHEMA = t.TABLE_SCHEMA AND tc.TABLE_NAME = t.TABLE_NAME AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' );

这个查询会列出所有无主键业务表。对每一张表,先看行数和占用空间。小表可以直接执行:

ALTER TABLE t_log ADD COLUMN id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;

如果表特别大,比如几十 GB 级别,直接 DDL 会触发长时间元数据锁或重建操作。这时候建议用在线变更工具,比如pt-osc或gh-ost。以gh-ost为例:

gh-ost --host=127.0.0.1 --user=user --password=pass \ --database=testdb --table=t_log \ --alter="ADD COLUMN id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY" \ --execute

执行前一定要确认磁盘空间。无主键表加上主键,意味着整个聚簇索引要重建,原有的每行数据都要重新组织,磁盘临时占用可能是原表的一到两倍。

改造完后,再跑一次前面的“无主键表检查 SQL”,结果应该是空的。这一步也应写入季度巡检清单,防止新同学上线表结构时漏掉主键。

5.3 分库分表后放弃自增的替代方案

自增 ID 在单库单表里很好用,一旦进入分库分表,就会面临全局唯一性问题。两张分表各自从 1 开始自增,业务上没法区分。

常见方案有三种:

  • 设置不同的初始值和步长。比如两个库节点,一个从 1 开始每次加 2,另一个从 2 开始每次加 2。优点是简单,缺点是全局严格单调递增做不到,扩容节点时还要调整步长,维护成本高。
  • 使用雪花算法类 ID。生成一个 64 位整型,包含时间戳、机器编号、序列号。全局唯一,趋势递增,不需要数据库参与发号。缺点是部署时要保证机器编号不冲突。
  • 使用独立发号服务。用一个中心服务批量生成 ID 段,业务拿一段到本地再分配。这是最可控的方式,代价是多一个中间件要维护。

从工程化角度,我建议分库分表后优先选雪花算法类的 ID 生成方案。它和 MySQL 自增主键不冲突,甚至可以把生成的 ID 直接落到现有表的bigint primary key里,后续运维手段完全复用。

5.4 自增 ID 容量监控与告警

自增 ID 耗尽不是“突然发生”的灾难,而是可以提前预测的。核心数据源就是information_schema.TABLES里的AUTO_INCREMENT字段,它表示下一行将被分配的自增值。

写一个按列类型计算使用率的查询:

SELECT t.TABLE_SCHEMA, t.TABLE_NAME, t.AUTO_INCREMENT, c.COLUMN_TYPE, CAST(t.AUTO_INCREMENT AS DECIMAL(30, 0)) / CASE c.COLUMN_TYPE WHEN 'int' THEN 2147483647 WHEN 'int unsigned' THEN 4294967295 WHEN 'bigint' THEN 9223372036854775807 WHEN 'bigint unsigned' THEN 18446744073709551615 END * 100 AS usage_percent FROM information_schema.TABLES t JOIN information_schema.COLUMNS c ON c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME AND c.EXTRA = 'auto_increment' WHERE t.AUTO_INCREMENT IS NOT NULL AND c.COLUMN_TYPE IN ('int', 'int unsigned', 'bigint', 'bigint unsigned') ORDER BY usage_percent DESC;

把这个查询做成定时任务,每天跑一次,当usage_percent超过 80% 时就发告警。超过 80% 后,你有充足的时间去改列类型或做数据归档。

有一种情况要特别提醒:AUTO_INCREMENT值在高并发环境下会先从引擎同步到数据字典缓存,information_schema查到的值可能滞后。所以要作为“水位趋势”参考,而不是“当前精确值”。核心业务的精确水位,还是结合当前表的最大主键来综合判断。

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

6.1 自增 ID 跳号与恢复初始值

现象:表里最大 ID 是 10000,但SHOW TABLE STATUS显示AUTO_INCREMENT是 10100,中间空出一大段。跳号很正常,不建议人工回缩,因为它不会导致任何故障。

如果你确实想把计数器恢复到接近最大值,比如从备份恢复后把AUTO_INCREMENT改大,可以用:

ALTER TABLE t_order AUTO_INCREMENT = 10001;

改完验证一下:

INSERT INTO t_order (order_no, amount) VALUES ('TEST001', 1.00); SELECT LAST_INSERT_ID();

如果返回 10001,说明计数器生效了。这个操作要注意:AUTO_INCREMENT必须大于当前表里已有的最大主键值,否则 MySQL 会自动按“最大主键值 + 1”来重新调整。所以更稳妥的是先查再改:

SELECT MAX(id) + 1 FROM t_order; ALTER TABLE t_order AUTO_INCREMENT = 10001;

6.2 如何判断一张表当前的自增水位

判断一张表已经用掉了多少自增额度,最简单的办法是查information_schema:

SELECT TABLE_NAME, AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 't_order';

如果想看历史增长速度,找 30 天前的监控数据,用当前AUTO_INCREMENT减掉旧值,除以天数,就是平均日增长量。再结合列类型上限,就能算出预计耗尽日期。比如当前值 20 亿,日增量 100 万,距离int上限大约还有 14 亿,也就是大约 140 天就要报警。

这个估算方法简单有效,我建议在监控告警里直接写入“预计可用天数”这个指标,比使用百分比更直观。

6.3 从备份或异常恢复后自增值回退的处理

有时候手动改了数据,或者从备份恢复,会发现AUTO_INCREMENT小于当前表里已经存在的最大主键。新插入语句会走正常递增逻辑,理论上不会马上和已有行冲突。但如果在特殊情况下插入了不合理的值,就可能在几分钟内出现主键冲突。

处理流程:

SELECT MAX(id) + 1 FROM t_order; -- 如果 max_id 是 50000,当前 AUTO_INCREMENT 是 40000 ALTER TABLE t_order AUTO_INCREMENT = 50001;

改完后再插入一条测试数据,确认不会撞到已有行即可。

6.4 已经耗尽主键容量的抢救方案

如果表压到极限了,不要试图继续插入,先把写入停了。最核心的修复动作是把列类型升级到bigint unsigned:

ALTER TABLE t_order MODIFY COLUMN id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT;

int改bigint属于元数据变更,多数情况下不用重建整表。但如果原表已经因为自增溢出出现大量异常报错,建议先修复数据,再执行 DDL,最后恢复正常流量。

如果这张表是int unsigned,直接改bigint unsigned即可。如果原来是int有符号,改完后原有的负数 ID 依然保留,新 ID 从当前计数器继续走,业务侧不用感知变化。

对我来说,这类事故的最佳处理时间点是“发生之前”。每次设计新表时花 10 秒想一想:这张表五年后会有多少行?默认给bigint unsigned会让未来的自己省掉一次惊心动魄的救火。

最后分享一个小习惯:我会在每个 MySQL 实例上常备无主键表巡检脚本和自增水位查询脚本,一个月跑一次,结果归档到团队文档里。很多问题不是因为技术太复杂才出事故,而是因为没人定期看一眼水位线。数据库不会主动提醒你“我快撑不住了”,但它留下的数字已经说明了一切。

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

U-Mamba复现第一步:conda环境、PyTorch与nnU-Net依赖配置详解

如果你最近在复现医学图像分割方向的论文,大概率绕不开 U-Mamba 这个名字。它是在 nnU-Net 基础上扩展出来的 3D 分割框架,算是“代码复现”圈子里热度很高的一份工作。作为一个跑过 U-Mamba 完整训练流程的人,我可以很负责任地说&#xff1a…

作者头像 李华
网站建设 2026/9/26 5:53:47

C语言printf格式符原理与实战:从内存到屏幕的全链路解析

1. 这不是语法表,是C语言输出的“翻译官说明书”你刚打开《C语言程序设计》教材第3章,看到printf("%d", age);这行代码,旁边标注着“%d表示整数”——但你心里其实有三个没说出口的问题:为什么非得用百分号开头&#xf…

作者头像 李华
网站建设 2026/9/26 5:52:45

从零到一:用 TaoToken 统一 Key 打通 AI 编程学习工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 5:51:46

MQ架构实战:从双写一致性到Pulsar Key_Shared与消息压缩

上半年最忙的一段时间刚过去,趁着记忆还新鲜,把 COSCon‘25 和 Pulsar Developer Day 2025 合办的专场里那些让我印象深刻的议题,结合我自己在生产环境折腾 MQ 的实战经验,系统地梳理一篇。这次活动最核心的几个话题,其…

作者头像 李华
网站建设 2026/9/26 5:51:17

Agnes AI 无限期免费文本图片视频模型与AI编程工具实战指南

1. 这个工具到底能干什么:先搞清楚它的能力边界Agnes AI 这段时间在圈子里被讨论得挺多,核心卖点就一句话:文本、图片、视频三类模型无限期免费,还附带一个 AI 编程工具。听起来像是天上掉馅饼,但我实际用下来&#xf…

作者头像 李华