百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

深度解析:大型互联网公司分布式ID方案总结与实践

mhr18 2024-10-09 12:21 27 浏览 0 评论

在现代互联网架构中,不同服务分布在多个节点上进行协作是常态。为了确保各个节点生成的数据能够唯一且高效地进行标识,一个稳定的分布式ID生成方案至关重要。这篇文章将总结大型互联网公司在分布式ID生成方面的经验和实践,深入解析几种常见的分布式ID方案,帮助你选择并实现最合适的方案。


目录

  1. 背景介绍
  2. 单点ID生成器
  3. 数据库自增序列
  4. 基于Redis的ID生成方案
  5. ZooKeeper分布式锁
  6. Twitter Snowflake
  7. 百度 UID Generator
  8. 总结与对比

1. 背景介绍

一个好的分布式ID生成方案需要具备以下特性:

  • 唯一性:生成的ID必须全局唯一,避免冲突。
  • 高可用性:ID生成过程不能成为系统瓶颈,需要高可用。
  • 高性能:在高并发环境下,能够高效生成ID。
  • 有序性:对于某些应用场景,ID需要具备有序性。

2. 单点ID生成器

2.1 实现原理

单点ID生成器是一种较为简单的实现方式。在这种方案中,我们可以通过一个单独的服务生成ID,然后将其分发到需要的节点。

2.2 实现步骤

  1. 部署单点ID生成器服务:例如一个简单的REST API服务器。
  2. 生成ID:通过数据库自增序列或内存中的自增计数器生成唯一ID。
  3. 分发ID:通过API请求获取ID。

2.3 优缺点

优点:

  • 实现简单,容易上手。
  • ID具有全局唯一性。

缺点:

  • 单点故障问题严重,服务挂掉会导致ID生成中断。
  • 在高并发环境下,性能瓶颈明显。

3. 数据库自增序列

3.1 实现原理

利用关系型数据库中的自增序列特性,生成唯一的ID。

3.2 实现步骤

  1. 创建自增序列:如MySQL中的AUTO_INCREMENT或Oracle中的SEQUENCE。
  2. 获取ID:插入数据时自动生成并获取唯一ID。

3.3 优缺点

优点:

  • 实现简单。
  • ID有序性好。

缺点:

  • 数据库成为单点瓶颈,性能有限。
  • 难以扩展到多机房、多实例的分布式系统。

4. 基于Redis的ID生成方案

4.1 实现原理

利用Redis的原子操作特性,生成唯一ID。

4.2 实现步骤

  1. 在Redis中定义一个Key:表示ID的序列。
  2. **原子自增操作INCR**:通过Redis的INCR命令生成唯一ID。

4.3 优缺点

优点:

  • Redis性能高,能够支持高并发。
  • 实现较为简单。

缺点:

  • Redis单点问题,需保证Redis的高可用性。
  • 不支持本地生成ID,有一定网络延迟。

5. ZooKeeper分布式锁

5.1 实现原理

利用ZooKeeper强一致性的特性,通过分布式锁机制生成唯一ID。

5.2 实现步骤

  1. 创建ZooKeeper客户端:与ZooKeeper集群建立连接。
  2. 获取分布式锁:保证同一时间只有一个节点生成ID。
  3. 释放分布式锁:节点完成ID生成后,释放锁以供其他节点使用。

5.3 优缺点

优点:

  • 强一致性,适用于需要严格顺序的应用场景。
  • 高可用性较好。

缺点:

  • 实现复杂,需维护ZooKeeper集群。
  • 性能相对较低,特别是在高并发环境下。

6. Twitter Snowflake

6.1 实现原理

Snowflake算法是Twitter开源的一种分布式ID生成算法,采用64位整数生成唯一ID。结构如下:

  • 1位符号位
  • 41位时间戳
  • 10位机器标识
  • 12位序列号

6.2 实现步骤

  1. 定义Snowflake算法:包括时间戳、机器标识和序列号的组合生成ID。
  2. 实现ID生成器:在代码中实现算法逻辑。

6.3 优缺点

优点:

  • 性能高,可生成大量唯一ID。
  • 具备时间排序特性。

缺点:

  • 时间回拨问题(服务器时间变化)需要处理。
  • 机器ID需要分配和管理。

示例代码

public class SnowflakeIdWorker {
    private final long twepoch = 1288834974657L;
    private final long workerIdBits = 5L;
    private final long datacenterIdBits = 5L;
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    private final long sequenceBits = 12L;
    private final long workerIdShift = sequenceBits;
    private final long datacenterIdShift = sequenceBits + workerIdBits;
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
    private long workerId;
    private long datacenterId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    public SnowflakeIdWorker(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    protected long timeGen() {
        return System.currentTimeMillis();
    }
}

7. 百度 UID Generator

7.1 实现原理

UID Generator是百度开源的一种分布式ID生成方案,它结合了时间戳、工作机器ID和序列号

7.2 实现步骤

  1. 定义UID生成结构:例如41位时间戳、10位工作机器ID和12位序列号。
  2. 实现生成逻辑:在代码中实现UID生成规则。

7.3 优缺点

优点:

  • 性能高。
  • 具有时间排序特性。

缺点:

  • 需自行维护机器ID的分配和管理。
  • 时间回拨问题需处理。



相关推荐

Java面试宝典之问答系列(java面试回答)

以下内容,由兆隆IT云学院就业部根据多年成功就业服务经验提供:1.写出从数据库表Custom中查询No、Name、Num1、Num2并将Name以姓名显示、计算出的和以总和显示的SQL。SELECT...

ADG (Active Data Guard) 数据容灾架构下,如何配置 Druid 连接池?

如上图的数据容灾架构下,上层应用如果使用Druid连接池,应该如何配置,才能在数据库集群节点切换甚至主备数据中心站点切换的情况下,上层应用不需要变动(无需修改配置也无需重启);即数据库节点宕机/...

SpringBoot多数据源dynamic-datasource快速入门

一、简介dynamic-datasourc是一个基于SpringBoot的快速集成多数据源的启动器,其主要特性如下:支持数据源分组,适用于多种场景纯粹多库读写分离一主多从混合模式。支持...

SpringBoot项目快速开发框架JeecgBoot——项目简介及系统架构!

项目简介及系统架构JeecgBoot是一款基于SpringBoot的开发平台,它采用前后端分离架构,集成的框架有SpringBoot2.x、SpringCloud、AntDesignof...

常见文件系统格式有哪些(文件系统类型有哪几种)

PART.01常见文件系统格式有哪些常见的文件系统格式有很多,通常根据使用场景(Windows、Linux、macOS、移动设备、U盘、硬盘等)有所不同。以下是一些主流和常见的文件系统格式及其特点:一...

Oracle MySQL Operator部署集群(oracle mysql group by)

以下是使用OracleMySQLOperator部署MySQL集群的完整流程及关键注意事项:一、部署前准备安装MySQLOperator通过Helm安装Operator到Ku...

LibreOffice加入&#34;转向Linux&#34;运动

LibreOffice项目正准备削减部分Windows支持,并鼓励用户切换到Linux系统。自Oracle放弃OpenOffice后,支持和指导LibreOffice开发的文档基金会对未来有着明确的观...

Oracle Linux 10发布:UEK 8.1、后量子加密、增强开发工具等

IT之家6月28日消息,科技媒体linuxiac昨日(6月27日)发布博文,报道称OracleLinux10正式发布,完全二进制兼容(binarycompatibility...

【mykit-data】 数据库同步工具(数据库同步工具 开源)

项目介绍支持插件化、可视化的数据异构中间件,支持的数据异构方式如下MySQL<——>MySQL(增量、全量)MySQL<——>Oracle(增量、全量)Oracle...

oracle关于xml的解析(oracle读取xml节点的属性值)

有时需要在存储过程中处理xml,oracle提供了相应的函数来进行处理,xmltype以及相关的函数。废话少说,上代码:selectxmltype(SIConfirmOutput).extract...

如何利用DBSync实现数据库同步(通过dblink同步数据库)

DBSync是一款通用型的数据库同步软件,能侦测数据表之间的差异,能实时同步差异数据,从而使双方始终保持一致。支持各种数据库,支持异构同步、增量同步,且提供永久免费版。本文介绍其功能特点及大致用法,供...

MYSQL存储引擎InnoDB(八十):InnoDB静态数据加密

InnoDB支持独立表空间、通用表空间、mysql系统表空间、重做日志和撤消日志的静态数据加密。从MySQL8.0.16开始,还支持为模式和通用表空间设置加密默认值,这允许DBA控制在这些模...

JDK高版本特性总结与ZGC实践(jdk高版本兼容低版本吗)

美团信息安全技术团队核心服务升级JDK17后,性能与稳定性大幅提升,机器成本降低了10%。高版本JDK与ZGC技术令人惊艳,且JavaAISDK最低支持JDK17。本文总结了JDK17的主要...

4 种 MySQL 同步 ES 方案,yyds!(两个mysql数据库自动同步的方法)

本文会先讲述数据同步的4种方案,并给出常用数据迁移工具,干货满满!不BB,上文章目录:1.前言在实际项目开发中,我们经常将MySQL作为业务数据库,ES作为查询数据库,用来实现读写分离,...

计算机Java培训课程包含哪些内容?其实就这六大块

不知不觉秋天已至,如果你还处于就业迷茫期,不如来学习Java。对于非科班小白来说,Java培训会更适合你。提前了解下计算机Java培训课程内容,会有助于你后续学习。下面,我就从六个部分为大家详细介绍...

取消回复欢迎 发表评论: