一份写、一份缓、一份排队——数据流动的三段,各自有哪些坑。
一、MySQL
MVCC
MVCC 让读事务看到某个快照,而不被未提交写阻塞。InnoDB 用隐藏列 trx_id 与 roll_pointer 串起 undo 版本链。Read View 记录活跃事务区间,可见性比较决定读哪一版行。
RC 下每次语句新开 Read View,RR 在事务开始时固定,从而可重复读,但幻读仍可能被当前读(加锁)看到。undo 过长会拖慢 purge,长事务是大敌。
与间隙锁、Next-Key 一起构成 RR 的防幻读方案。排查一致性问题时先看隔离级别与是否用了 SELECT FOR UPDATE。Redis 没有这套行版本,不要拿缓存语义去套数据库快照。
Mysql和Es同步方案
MySQL 与 Elasticsearch 同步常见几条路:定时全量/增量扫描、业务双写、消息队列、Logstash JDBC,以及 Canal 监听 binlog。搜索要的是近实时和可检索字段,库要的是事务真相,两者不能互相替代。
双写最容易不一致,失败补偿必须可重放。binlog 方案延迟低,但要处理 DDL、主键变更和回环。定时扫描实现简单,适合对延迟不敏感的报表类索引。
上线前约定删除策略、幂等键和映射变更流程。用对账任务抽查条数与抽样文档,比只看同步进程存活更能发现静默丢数据。
二、Redis
Redisson
Redisson 在 Redis 之上提供分布式对象:锁、集合、延迟队列和布隆过滤器,API 接近 Java 并发包。它处理续期、pubsub 解锁通知,比手写 SET NX 更不容易漏边界。
锁仍要设合理租约和看门狗,业务阻塞过长会误释放。集群模式选好拓扑,红锁在多数生产里并不比单锁更可靠。序列化方式和连接池大小影响延迟。
把 Redisson 当本地 HashMap 用会把 Redis 打满。大 key、热 key 和阻塞命令要避开。监控等待时间和持锁时间,超时告警比事后查日志有效。
Redis的击穿、雪崩、穿透?
Redis 缓存穿透是查询根本不存在的数据,一直打到存储;击穿是热点 key 过期瞬间大量请求回源;雪崩是大批 key 同时失效或 Redis 自身不可用,流量涌向数据库。
穿透可用布隆过滤或缓存空值并设短 TTL。击穿对热点做互斥重建或逻辑过期。雪崩把过期时间加随机抖动,并准备降级与限流。监控要能区分这三类,处理手段不同。缓存只是加速,数据正确性仍以数据库为准。更新策略选旁路缓存还是双写,必须定义好失败时的补偿,否则会出现长久脏缓存。
三、消息队列
Kafka
Kafka 是分布式日志型消息系统。生产者把记录追加到分区,消费者按位移拉取。同一分区内有序,分区之间只保证并行。副本用 ISR 保证冗余,位移提交决定重复或丢失的风险。它适合高吞吐的事件流、日志收集和系统解耦,而不是作为低延迟 RPC。
主题分区数一旦定下来再扩会改变键的哈希归属,设计时要留余量。消费者组内人数不要长期超过分区数。关键业务用幂等生产和事务,普通日志用至少一次即可。监控看 ISR、消费滞后和请求耗时。磁盘和页缓存决定吞吐。不要把 Kafka 当数据库用长时间查询,需要回放就按位移重读,需要状态就交给下游存储。
RabbitMQ
RabbitMQ 实现 AMQP,用交换机把消息路由到队列。直连、主题、扇出三种交换机覆盖点对点、订阅和广播。生产者发到交换机,消费者从队列取。确认、预取和死信交换机决定会不会丢、会不会打爆消费者。它适合路由规则复杂、流量中等、需要灵活绑定的业务。
队列要持久化,消息也要持久化,节点还要有镜像或 quorum 队列,三者缺一都可能丢。消费必须 ack,异常要 nack 并决定是否重入。预取设太大容易让一个消费者囤积。优先级和 TTL 能做简单延迟,但不是通用调度器。管理台看未确认数和内存告警。插件生态丰富,但生产只开需要的,减少攻击面和运维负担。
RocketMQ
RocketMQ 面向业务消息,强调可靠投递、顺序消息、延时消息和事务消息。NameServer 做路由,Broker 存消息,生产者与消费者按 Topic 和 Tag 过滤。队列是并发与顺序的基本单位:顺序消息要发到同一队列。它在电商、支付这类“不能丢、偶尔可重复”的场景很常见。
消费要做成幂等,因为重试和再平衡会重复。死信队列要有人处理,不能当黑洞。事务消息用半消息加回查,避免本地事务和发消息不一致。堆积时先看消费线程和下游依赖,而不是盲目加机器。版本上要注意客户端与 Broker 协议。监控发送失败、消费 TPS 和死信数量,比只看集群是否存活更接近真实业务健康度。
消息队列出现消息堆积解决方案
消息堆积说明生产速度持续超过消费,或消费被阻塞。先看积压曲线、消费延迟和失败重试,区分是流量洪峰、下游变慢,还是毒丸消息把分区卡住。
短期手段包括扩消费者、提高并发、跳过或转入死信、临时限流生产。长期要拆热点分区、批量消费、异步化下游,并给关键 Topic 设积压告警。顺序消息扩分区前必须确认分区键设计。
回放积压时控制速度,避免把数据库再打穿。幂等是前提,否则加速消费只会制造重复订单。演练时用影子 Topic 验证扩容和跳过策略是否真能在时限内追平。
MySQL、Redis 与消息队列速查
https://lautung.com/archives/mysql-redis-message-queue
评论