面试题答案
一键面试架构设计
- 消息队列(MQ):引入消息队列如Kafka或RabbitMQ。各微服务将商品更新操作封装成消息发送到MQ。这样可以削峰填谷,将高并发的更新请求缓冲起来,避免ElasticSearch瞬间承受过大压力。
- 更新服务:设计一个专门的更新服务,从MQ中消费消息。该服务负责按照顺序处理商品更新消息,确保同一商品的更新操作按序执行,保证数据一致性。
- 分布式锁:使用分布式锁(如Redis分布式锁)。在更新服务处理更新操作前,先获取对应商品的分布式锁。只有获取到锁的更新操作才能继续执行,防止多个更新操作同时修改同一商品数据。
更新策略
- 版本控制:在ElasticSearch的商品文档中添加版本号字段。每次更新操作,先读取当前版本号,更新时将版本号加1,并在更新请求中带上预期版本号。ElasticSearch在执行更新时,会检查当前文档版本号与预期版本号是否一致,只有一致才会执行更新,否则返回失败。
- 幂等性设计:确保每个更新操作是幂等的。例如,库存变更操作,如果是减少库存,每次操作都基于当前库存进行减少,多次执行相同操作结果一致;价格调整操作直接设置新价格,重复设置相同价格不影响最终结果。
冲突解决机制
- 重试机制:当更新由于版本冲突等原因失败时,更新服务记录失败信息,按照一定策略进行重试。例如,采用指数退避算法,每次重试间隔时间逐渐增加,避免短时间内大量重试再次造成冲突。
- 人工干预:对于多次重试仍失败的情况,将相关信息记录到日志或数据库,通知运维人员或开发人员进行人工干预。分析失败原因,如是否存在数据异常、网络问题等,然后手动修复或调整策略。
实现原理
- 消息队列原理:微服务将更新消息发送到MQ,MQ根据主题(topic)和分区(partition)规则存储消息。更新服务从MQ中按照顺序消费消息,保证同一商品的更新消息按序处理。
- 分布式锁原理:更新服务通过Redis的SETNX(SET if Not eXists)命令获取分布式锁。如果获取成功,表示当前更新操作可以执行;获取失败则等待或重试。操作完成后,通过DEL命令释放锁。
- 版本控制原理:ElasticSearch的乐观锁机制基于版本号。更新服务获取当前商品文档版本号,更新时带上预期版本号。ElasticSearch在更新前对比当前版本号和预期版本号,一致则更新,不一致则返回失败。
优势
- 数据一致性:通过消息队列保证更新操作按序处理,分布式锁防止并发更新,版本控制确保更新的准确性,有效保证了数据的一致性。
- 高可用性:消息队列的削峰填谷功能提高了系统在高并发下的稳定性,即使某个微服务或更新服务出现短暂故障,消息队列中的消息不会丢失,故障恢复后可继续处理。
- 可扩展性:消息队列和分布式锁都具有良好的扩展性。随着业务增长,可通过增加MQ的分区、扩展更新服务实例等方式轻松应对更高的并发和更多的更新请求。
- 幂等性和冲突解决:幂等性设计避免了重复操作带来的问题,重试机制和人工干预保证了更新操作的最终成功,提高了系统的健壮性。