SIMD 指令与缓存局部性

SIMD:一条指令同时处理多个数据 SIMD 全称 Single Instruction Multiple Data(单指令多数据),是 Flynn 分类法里的一种:一条指令同时对一组数据执行相同的操作,属于数据并行。与之相对的是普通的标量指令(SISD,Single Instruction Single Data),一条指令只处理一个数据。 CPU 指令集里的指令并不是都能批量操作数据的:只有一部分特定操作(加减乘除、位运算如异或/与/或、比较、移位等)才提供了"批量版本",这部分指令就叫 SIMD 指令;分支跳转这类指令就没有对应的 SIMD 形式。批量操作的前提是数据要打包进宽寄存器——比如一个 256 位的 YMM 寄存器可以看作 8 个 32 位整数拼在一起,一条 SIMD 指令对这个寄存器操作时,是把 8 个"数据槽"同时各自执行同一个操作(8 次加法或 8 次异或同时完成),而不是把整个 256 位当成一个数来算。这一整批 SIMD 指令加上背后的宽寄存器,合在一起就构成了一个 SIMD 指令集扩展。 现代 CPU 都提供了专门的向量寄存器和向量指令集来支持 SIMD: 架构 指令集 寄存器宽度 x86 SSE / SSE2 128 位 x86 AVX / AVX2 256 位 x86 AVX-512 512 位 ARM NEON 128 位 ARM SVE 可变长(128~2048 位) 举个例子,如果要对两个长度为 4 的 float 数组逐元素相加,用标量指令需要 4 次加法;如果用 128 位的 SSE 寄存器(正好能装下 4 个 32 位 float),一条向量加法指令就能同时算完这 4 组加法,吞吐量提升了 4 倍。 ...

Created 13136-07-13 · Updated 14146-07-14 · 2 min · 243 words · -

MySQL 宽表写入性能问题:为什么会慢,何时该考虑时序库

背景 在业务增长阶段,很多系统都会遇到类似问题:写入路径以 insert 为主,单条记录字段很多,写入频率持续升高,最终出现写入延迟抬升、队列积压、应用侧内存压力变大。 这类问题通常被称为“宽表高频写入瓶颈”。这里把它拆开讲清楚:为什么会慢、先做什么优化、以及什么时候该考虑从关系型数据库迁移到时序数据库。 一个真实案例可参考:物联网平台协议解析服务生产环境 OOM:MySQL 迁移 InfluxDB。 为什么宽表高频写入容易慢 宽表写入慢,通常不是单点问题,而是多个开销叠加: 单行体积大:每次写入涉及更多页修改和日志写入。 索引维护成本高:索引越多,单次 insert 需要更新的 B+Tree 越多。 随机写放大:页分裂、二级索引回表结构维护,会放大 I/O。 事务与刷盘约束:redo/binlog/fsync 的组合决定了吞吐上限。 后台线程竞争:flush、checkpoint、purge 跟前台写入争抢资源。 这里的“更多页”并不是指“每一行一定跨很多页”,而是指一次写入会牵动更多数据页:InnoDB 以页(默认常见为 16 KB)为最小读写单位。行越宽,单页可容纳的记录数越少,同样数据量需要更多页;插入时更容易触发页满和页分裂。同时,写入不只改数据页,还会改聚簇索引页、二级索引页以及对应日志;如果包含较大 TEXT/BLOB 字段,还可能涉及溢出页。结果是单次写入的页修改与日志写入成本一起上升。 在高并发下,这些开销叠加后,常见表现是:写入 RT 上升,连接占用时间变长,线程池阻塞,进而把上游消费链路拖慢。 先做 MySQL 侧排查和优化 在决定换库前,建议先把 MySQL 侧可优化项跑一遍: 表结构:拆分冷热字段,把大字段从核心写入表拆出去。 索引策略:只保留必要索引,避免“为查而建”过多索引拖慢写入。 主键设计:优先使用短且有序的主键,降低页分裂概率。 批量写入:小批次 batch insert,减少事务提交次数。 连接池与并发:避免连接池过大导致数据库抖动,结合压测设上限。 存储参数:检查 innodb_buffer_pool_size、innodb_flush_log_at_trx_commit、sync_binlog 等配置是否与场景匹配。 观测指标:重点盯写入 RT、TPS、磁盘写 IOPS、redo 生成速率、checkpoint age、锁等待。 如果这些动作做完后仍然无法满足目标吞吐,再考虑架构级改造更稳妥。 什么时候考虑时序数据库 当业务数据明显符合以下特征时,时序数据库通常更有优势: 写多读少,且主要是追加写。 读请求以时间范围查询为主。 业务天然带时间戳主维度。 接受按保留策略做冷热分层与过期清理。 这类场景下,时序引擎在写路径和压缩存储上的结构性优势,往往比继续堆关系库参数更有效。 迁移建议 从 MySQL 到时序库,建议用“双写 + 渐进切读”: 先双写,确保新旧链路数据可对账。 下游按服务分批切读,避免一次性切换。 保留回退开关,出现异常可快速切回旧链路。 观察一段稳定窗口后,再下线旧写入逻辑。 InfluxDB 相关基础可参考:InfluxDB。 ...

Created 3036-06-03 · Updated 3036-06-03 · 1 min · 84 words · -

MySQL 大表优化

MySQL 大表优化 这篇是我基于一篇早期讨论内容整理的实践笔记,重点放在“遇到大表性能问题时,按什么顺序处理更稳妥”。 原讨论链接: https://www.zhihu.com/question/19719997/answer/81930332 处理顺序(先低成本,再高成本) 大多数系统都适合按以下顺序推进,避免一上来就分库分表: 先优化 SQL 和索引。 再加缓存(如 Redis),减少数据库读压力。 再做读写分离(主从)或副本扩展。 再评估分区表(前提是查询条件能命中分区键)。 再做垂直拆分(按业务域拆库)。 最后才是水平拆分(分库分表 + 路由)。 核心原因是:越往后改造成本越高,业务侵入越强,回退也越困难。 SQL 与索引是第一优先级 很多慢库问题并不是“数据库不行”,而是这三件事没有做透: SQL 写法没有针对索引设计。 索引数量过多或选择不对,拖慢写入。 优化单条 SQL 时忽略了全局负载,出现“局部变快、整体变慢”。 建议先做这套最小闭环: 用慢查询日志找 Top N SQL。 用 EXPLAIN 验证执行计划。 在压测环境对比“改前/改后”整体 RT、QPS、CPU、IO。 分区、垂直拆分、水平拆分怎么选 分区表 适合“时间范围明显、查询常带分区键”的表。优点是对业务代码相对透明;缺点是分区命中差时容易扫全分区。 垂直拆分 适合按业务域解耦,把不同模块压力拆到不同库。它能降低单实例总压力,但不能解决单表本身太大的问题。 水平拆分 适合单表已达到容量或吞吐瓶颈。收益大,但代价也最大: 需要稳定的分片键设计。 SQL 路由、聚合查询、跨分片事务复杂度明显上升。 常常需要改表结构、做冗余字段、改应用代码。 关于 InnoDB 与 MyISAM 的取舍 在当前线上系统里,绝大多数场景优先 InnoDB: 支持事务与行级锁。 并发写能力更稳。 故障恢复能力更好。 MyISAM 在某些纯读场景可能有优势,但在写多或读写混合场景里,通常不是优先选项。 实战建议 如果你正在处理“大表 + 写入变慢”,建议按下面清单落地: 先确认瓶颈在 SQL、锁、IO、还是连接池。 明确读写模型(读多写少、写多读少、时间范围查询比例)。 先完成 SQL/索引/缓存优化,再决定是否拆分。 如果进入拆分阶段,先做垂直拆分,再做水平拆分。 延伸阅读 MySQL 宽表写入性能问题:为什么会慢,何时该考虑时序库 数据库水平拆分垂直拆分 MySQL INNODB

Created 22226-12-22 · Updated 3036-06-03 · 1 min · 77 words · -