实习经历(2)
1 当时你是怎么发现 Redis 标记丢失和多线程竞争导致 ES 数据不一致的
代码问题:ES同步标记存放在redis中,有过期时间,24h过期(昨天修复)(是本次ES丢数据的主因)。
性能原因:多线程开启ES数据同步,导致ES出现断开接收的情况(多线程。昨天改了一版异步方案,正在测试)(MQ形式)
2 为什么选择 MQ 异步补偿 + 分表策略,而不是其他方案(比如加锁、事务、调整同步机制)?
- MQ 可以将数据写入与 ES 同步解耦,生产端只管写入并发送消息,消费端负责异步同步到 ES,即使 ES 暂时不可用,消息也能在 MQ 中堆积,不会阻塞主流程。
- 分表策略可以将单表的千万级数据拆分到多个表中,降低单表查询压力,同时结合 ES 查询时的路由优化,减少不必要的分片扫描。
- MQ 作为缓冲层,可以削峰填谷,保护核心数据库和搜索服务。
3 分表的原因是什么
ES 的索引会被拆分为多个分片(shard),默认情况下,文档会根据_id的哈希值均匀分配到不同分片。查询时,如果不指定路由规则,ES 会广播查询请求到所有分片,每个分片独立查询后再汇总结果 —— 这就是 “全分片扫描”,在数据量大时会非常耗时。
路由优化的核心,是让查询只命中特定分片,避免全扫描。我的做法是:
分表与路由规则绑定:因为已经做了分表(比如按用户 ID 范围分表),所以在将数据同步到 ES 时,会把 “分表标识”(比如用户 ID 前缀)作为 ES 文档的routing值。
查询时指定路由:当查询某个用户的数据时,直接用该用户的分表标识作为路由参数,ES 就会精准定位到对应的分片,避免其他分片参与查询。
4 如何使用MQ进行消费填谷
“削峰填谷” 是指通过 MQ 缓冲突发流量,避免下游服务被瞬时高并发压垮。我的实现逻辑是:
峰值缓冲:业务系统(比如订单创建、权限变更)产生数据变更时,不直接调用 ES 同步接口,而是先发送一条消息到 MQ(比如 RabbitMQ 的持久化队列)。此时即使短时间有 10 万级别的数据变更,也会被 MQ 暂存,业务系统只需 “扔完消息就走”,不会被 ES 的写入性能拖累。
匀速消费:ES 同步服务作为 MQ 的消费者,会根据 ES 的处理能力(比如每秒最多处理 1000 条数据)设置消费速率(通过线程池大小、QoS 限流等)。即使 MQ 中有堆积的消息,也会按固定速度被消费,避免 ES 因瞬时写入压力过大而崩溃。
错峰处理:比如白天是业务高峰期,MQ 会堆积一部分消息;到了凌晨低峰期,消费者可以自动提高消费速率,快速消化堆积消息,保证数据最终一致性。
5 分表的依据是什么?分表后如何处理跨表查询?
分录表Hash分表,主表+ES联合查询优化。

浙公网安备 33010602011771号