分布式ID与幂等性面试题整理

文章目录

  • 分布式ID与幂等性面试题整理
    • 一、分布式ID
      • 1. 为什么需要分布式ID?
      • 2. 分布式ID的核心要求
      • 3. 常见分布式ID方案
        • (1) UUID
        • (2) 数据库自增
        • (3) Redis自增
        • (4) 雪花算法(Snowflake)
        • (5) 美团Leaf/百度UidGenerator
      • 4. 雪花算法详解
    • 二、幂等性
      • 1. 什么是幂等性?
      • 2. 为什么需要幂等性?
      • 3. 实现幂等性的常见方案
        • (1) 唯一索引
        • (2) 乐观锁
        • (3) 状态机
        • (4) Token机制
        • (5) 去重表
        • (6) 全局ID
      • 4. 不同场景的幂等实践
        • HTTP接口幂等
        • 消息队列幂等
        • 定时任务幂等
      • 5. 幂等性与并发控制
    • 三、综合实战
      • 1. 设计一个分布式ID生成服务
      • 2. 支付系统的幂等设计
      • 3. 分布式事务与幂等

一、分布式ID

1. 为什么需要分布式ID?

问题:在分布式系统中,为什么不能直接使用数据库自增ID?

答案

  • 单点故障:自增ID依赖单数据库,数据库挂了整个系统就瘫痪
  • 性能瓶颈:所有ID生成请求都打到同一个数据库,压力大
  • 扩展困难:分库分表时,自增ID会导致重复或需要复杂协调
  • 安全问题:连续的数字ID容易暴露业务量,可能被爬取数据

2. 分布式ID的核心要求

问题:一个好的分布式ID生成方案需要满足哪些要求?

答案

  1. 全局唯一:整个系统内绝对不能重复
  2. 趋势递增:最好是有序的,方便数据库索引
  3. 高可用:ID生成服务不能成为单点故障
  4. 高性能:每秒至少能生成几万ID
  5. 安全:不能暴露业务信息(如订单量)

3. 常见分布式ID方案

问题:常见的分布式ID生成方案有哪些?各自原理是什么?

答案

(1) UUID
  • 原理:随机生成128位数字,格式如550e8400-e29b-41d4-a716-446655440000
  • 优点:简单,本地生成无网络开销
  • 缺点:无序导致索引性能差,字符串存储空间大
(2) 数据库自增
  • 原理:单独数据库表,通过REPLACE INTO或事务获取ID
  • 优点:实现简单,ID有序
  • 缺点:数据库单点风险,性能有限
(3) Redis自增
  • 原理:利用Redis的INCR命令生成ID
  • 优点:性能比数据库好
  • 缺点:需维护Redis集群,持久化问题可能导致ID重复
(4) 雪花算法(Snowflake)
  • 原理:64位ID = 1位符号位(0) + 41位时间戳 + 10位机器ID + 12位序列号
  • 优点:本地生成性能高,ID有序
  • 缺点:依赖机器时钟,时钟回拨会导致ID重复
(5) 美团Leaf/百度UidGenerator
  • 原理:改进版雪花算法,解决时钟回拨问题,引入ZK协调
  • 优点:解决了原生雪花算法的问题
  • 缺点:系统复杂度高

4. 雪花算法详解

问题:详细解释雪花算法的实现原理?

答案

0 | 0001100 10100010 10111110 10001001 01011100 | 00 | 00001 | 000000000000
  • 第1位:符号位,始终为0
  • 中间41位:毫秒级时间戳,可用69年
  • 接着10位:5位数据中心ID + 5位机器ID(最多1024个节点)
  • 最后12位:序列号,每毫秒可生成4096个ID

时钟回拨问题处理

  1. 轻微回拨:等待时间追上
  2. 严重回拨:报警人工介入
  3. 美团Leaf方案:使用ZK记录最大时间戳

二、幂等性

1. 什么是幂等性?

问题:用通俗语言解释什么是幂等性?

答案

  • 通俗理解:同样的操作执行一次和执行N次,效果一样
  • 举例:
    • 支付:同一笔订单只扣一次钱
    • 短信:同一条通知只发一次
    • 状态更新:最终状态一致

2. 为什么需要幂等性?

问题:分布式系统中为什么特别关注幂等性?

答案

  • 网络问题:请求超时可能导致客户端重试
  • 微服务调用:服务调用失败会触发重试机制
  • 消息队列:消息可能被重复消费
  • 用户行为:用户可能多次点击提交按钮

3. 实现幂等性的常见方案

问题:有哪些实现幂等性的方案?各自适用场景?

答案

(1) 唯一索引
  • 原理:数据库唯一索引防止重复数据
  • 场景:创建订单等插入操作
  • 实现:订单ID、业务编号等加唯一索引
(2) 乐观锁
  • 原理:通过版本号控制更新

  • 场景:更新操作如账户余额变更

  • 实现:

    UPDATE account SET balance=balance-100, version=version+1 
    WHERE id=123 AND version=5
    
(3) 状态机
  • 原理:业务状态流转控制

  • 场景:订单状态等有明确流转的业务

  • 实现:

    UPDATE order SET status='paid' WHERE id=456 AND status='unpaid'
    
(4) Token机制
  • 原理:客户端先获取令牌,服务端校验后删除
  • 场景:防止表单重复提交
  • 实现:
    1. 服务端生成token存入Redis
    2. 提交时携带token
    3. 校验后删除token
(5) 去重表
  • 原理:记录已处理请求ID

  • 场景:消息队列消费等

  • 实现:

    INSERT INTO request_log(request_id, biz_type) VALUES('req123', 'order')
    -- 先查是否存在再处理
    
(6) 全局ID
  • 原理:利用分布式ID的唯一性
  • 场景:所有需要幂等的场景
  • 实现:结合雪花算法等生成唯一业务ID

4. 不同场景的幂等实践

问题:针对以下场景如何保证幂等性?

  1. HTTP接口
  2. 消息队列消费
  3. 定时任务

答案

HTTP接口幂等
  1. GET:天然幂等
  2. POST:
    • 前端:提交按钮禁用+loading
    • 后端:Token机制+唯一索引
  3. PUT/DELETE:天然幂等(需正确实现)
消息队列幂等
  1. RabbitMQ:
    • 消息唯一ID+去重表
    • 手动ack确保处理完成
  2. Kafka:
    • 利用offset控制
    • 消费者组+分区保证顺序
定时任务幂等
  1. 加锁:分布式锁(Redis/ZK)
  2. 状态检查:记录上次执行结果
  3. 时间窗口:允许短时间重复但结果一致

5. 幂等性与并发控制

问题:幂等性和并发控制有什么区别?

答案

  • 幂等性:关注多次操作的结果一致性
  • 并发控制:关注同时操作的顺序和正确性
  • 联系:
    • 都需要唯一标识
    • 都可能导致数据不一致
  • 区别:
    • 幂等解决重复问题
    • 并发控制解决竞争问题

三、综合实战

1. 设计一个分布式ID生成服务

问题:如何设计一个类似美团Leaf的分布式ID服务?

答案

架构设计

  1. 服务层:无状态服务,可水平扩展
  2. 存储层:
    • ZK:协调worker节点分配
    • Redis:缓存号段,提高性能
  3. ID生成:
    • 号段模式:每次获取一批ID(如1-1000)
    • 双Buffer:一个用完前预加载下一个

核心流程

  1. 启动时向ZK注册获取workerID
  2. 从DB获取号段范围(UPDATE max_id=max_id+step)
  3. 内存中分配ID,快用完时异步加载下一号段
  4. 定期持久化当前分配位置

2. 支付系统的幂等设计

问题:支付系统如何防止重复扣款?

答案

全链路设计

  1. 订单创建

    • 订单ID使用雪花算法
    • 订单表order_id唯一索引
  2. 支付请求

    • 前端:支付按钮防重
    • 生成支付流水号(支付系统唯一)
  3. 支付核心

    // 伪代码
    public Result pay(String orderId, BigDecimal amount) {// 1. 检查订单状态Order order = orderDao.get(orderId);if (order.isPaid()) {return Result.success("已支付");}// 2. 乐观锁更新int updated = orderDao.updateStatus(orderId, "unpaid", "paying");if (updated == 0) {return Result.fail("并发操作");}// 3. 实际扣款boolean success = accountService.debit(order.getUserId(), amount);// 4. 最终状态if (success) {orderDao.updateStatus(orderId, "paying", "paid");} else {orderDao.updateStatus(orderId, "paying", "failed");}
    }
    
  4. 对账补救:定时核对订单与支付记录

3. 分布式事务与幂等

问题:分布式事务场景下如何保证幂等性?

答案

结合方案

  1. TCC模式
    • Try阶段:生成事务ID,记录预备状态
    • Confirm/Cancel:通过事务ID保证幂等
  2. 本地消息表
    • 业务与消息表在同一个事务
    • 消息ID作为去重依据
  3. Saga模式
    • 每个步骤有补偿操作
    • 通过业务ID保证补偿幂等

关键点

  • 事务ID全局唯一
  • 操作前检查状态
  • 补偿操作也要幂等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/91913.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/91913.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/91913.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

node.js学习笔记1

目录 Node.js是什么 Node.js下载与安装 Buffer缓冲区 一些计算机硬件基础 程序运行的基本流程 Node.js是什么 node.js是一个JavaScript运行环境,或者说,node.js是一个可以运行JavaScript的软件。 可以用于开发服务端、桌面端、工具类应用。 服务器…

游戏开发日志

我来为您逐行详细讲解这个 ViewMgr.cs 文件。这是一个Unity游戏中的视野管理系统,用于优化游戏性能。## 文件结构概览这个文件主要包含以下几个部分: 1. 数据结构和接口定义 2. 视野管理器 ViewMgr 类 3. 工具类 ViewTools让我逐行为您讲解:#…

使用 PlanetScope 卫星图像绘制水质参数:以莫干湖为例

1.数据采集 我使用ArcGIS Pro 中的Planet Imagery插件下载了 2023 年 6 月 25 日的安卡拉莫干湖卫星图像。 图 1:使用 Planet 插件下载卫星图像 图 2:下载图像的日期和传感器选择 我查阅的研究中指出,使用无降水时期的卫星图像对于水质测定…

Docker部署前后端分离项目——多项目共享环境部署

目录 一、简介 二、文件目录结构 三、前端部署流程(多nginx) 3.1 前端打包 3.2 编写部署文件——项目1(consult-system) 3.3 编写部署文件——项目2(person-system) 3.4 前端部署至linux服务器 3.5…

学习笔记(39):结合生活案例,介绍 10 种常见模型

学习笔记(39):结合生活案例,介绍 10 种常见模型线性回归只是机器学习的 “冰山一角”!根据不同的任务场景(分类、回归、聚类等),还有许多强大的模型可以选择。下面我用最通俗易懂的语言,结合生活案例&#…

BabyAGI 是一个用于自构建自主代理的实验框架

这个最新的 BabyAGI 是一个用于自构建自主代理的实验框架 核心是一个新的函数框架 (functionz),用于存储、管理和执行数据库中的函数。它提供了一个基于图形的结构,用于跟踪导入、依赖函数和身份验证密钥,并具有自动加…

商业秘密视域下计算机软件的多重保护困境

作者:邱戈龙、柯坚豪重庆商业秘密律师广东长昊律师事务所引言:计算机软件保护的复杂性 在商业秘密保护的宏大版图中,计算机软件因其技术密集性和创新性占据着特殊地位。软件的真正价值不仅在于其代码本身,更在于其背后的流程、逻…

深入理解 Spring Boot 自动配置原理

Spring Boot 之所以能“开箱即用”,其核心就在于 自动配置机制(Auto Configuration)。本文将深入剖析 Spring Boot 自动配置的工作原理,从注解入手,再到底层的源码机制,揭开 Spring Boot 背后的“魔法”。 …

Ubuntu18.04开机启动执行脚本

#!/bin/bash # 运行 .NET Core 应用程序 dotnet /home/bruce/atg/SmartConsole.dll &# 打开浏览器 firefox 给文件权限sudo chmod 777 start.sh运行gnome-session-properties打开系统自带的一个启动程序

c语言进阶 字符函数和字符串函数

字符函数和字符串函数字符函数和字符串函数1. strlenstrlen 函数详解模拟实现1.计数器方式2.不能创建临时变量计数器(递归)3.指针-指针的方式2. strcpystrcpy 函数详解模拟实现3. strcatstrcat 函数详解模拟实现4. strcmpstrcmp 函数详解模拟实现5. strn…

(LeetCode 每日一题) 1233. 删除子文件夹 (排序)

题目:1233. 删除子文件夹 思路:排序,时间复杂度0(L*nlogn)。 文件夹a的子文件b,b字符串字典序列一定是大于a的,所以直接将字符串数组folder升序排序。每次只需判断当前字符串,是否是父文件夹数组v最后一个…

集成算法学习bagging,boosting,stacking

baggibg(rf随机森林) adaboostibg 用来展示 Project Jupyter | Home 展示源码 Eclipse IDE | The Eclipse Foundation Eclipse 下载 |Eclipse 基金会 教程8-Adaboost决策边界效果_哔哩哔哩_bilibili (23 封私信) 图解机器学习神器:Scikit-Learn - 知乎 Baggi…

HOOPS SDK赋能PLM:打造全生命周期3D数据管理与协作能力

在制造业和工业领域,产品全生命周期管理(PLM) 已成为驱动企业数字化转型、提升创新力与运营效率的核心引擎。一个高效的PLM平台不仅需要管理海量的设计数据,还必须在设计、制造、供应链、销售和服务等多个环节之间无缝流转信息&am…

解决 Selenium 页面跳转过快导致的内容获取问题:从原理到实践

在使用 Selenium 进行网页自动化操作时,很多开发者都会遇到一个头疼的问题:页面还没加载完,代码就已经执行到下一句了。结果要么是元素找不到,要么是获取的内容不完整,甚至直接抛出异常。今天我们就来聊聊如何优雅地解…

【Python练习】051. 编写一个函数,实现简单的定时器功能

051. 编写一个函数,实现简单的定时器功能 051. 编写一个函数,实现简单的定时器功能 代码说明: 示例运行: 扩展功能 代码说明: 实现Python定时器的几种方法 051. 编写一个函数,实现简单的定时器功能 以下是一个简单的Python函数,用于实现定时器功能。这个定时器可以设置…

springboot基础-demo

1.创建学生信息表 create table stu(id int unsigned primary key auto_increment comment ID,name varchar(100) comment 姓名,age tinyint unsigned comment 年龄,gender tinyint unsigned comment 性别, 1:男, 2:女,score double(5,2) comment 成绩,phone varchar(11) comme…

关于transformer的一些疑点总结

残差连接的作用 Transformer中的残差连接(Residual Connection)是其深层架构能稳定训练的核心设计之一,主要通过以下机制发挥作用: 1. 缓解梯度消失,支持深层训练 梯度保护机制:在反向传播时,…

【终极指南】解决 Windows 11 更新后 Docker 连接 localhost 奇慢(卡顿、超时十几秒)的通用方案

聪明人能看得出这是 ai 写的,但也是我亲身实践的,最后让 ai 总结写了一篇,放心食用 一、 结论先行(直接用)问题现象: 升级到某个 Windows 11 版本后,在本地访问 Docker 容器中部署的任何服务&am…

Stream API

Java 8 引入的 Stream API 是处理集合数据的强大工具,它允许你以声明式方式处理数据集合,支持各种聚合操作和并行处理。以下是 Stream API 的核心知识点及具体代码示例: 1. Stream 概述 Stream 是数据渠道,用于操作数据源&#xf…

相机参数的格式与作用

在计算机视觉中,相机标定是非常重要的一步,主要目的是从图像中恢复出物体的三维信息。为了做到这一点,我们需要了解和使用一系列的数学工具,这些工具描述了相机的成像过程,包括相机的内参、外参、畸变系数、投影矩阵和…