我的编程空间,编程开发者的网络收藏夹
学习永远不晚

redis分布式ID解决方法有哪些

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

redis分布式ID解决方法有哪些

这篇文章主要介绍“redis分布式ID解决方法有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“redis分布式ID解决方法有哪些”文章能帮助大家解决问题。

    常用的分布式ID解决方案

    在分布式系统中,生成全局唯一ID是非常重要的,因为在分布式系统中,多个节点同时生成ID可能会导致ID冲突。

    下面介绍几种常用的分布式ID解决方案。

    UUID

    UUID(通用唯一标识符)是由128位数字组成的标识符,它可以保证在全球范围内的唯一性,因为其生成算法基于时间戳、节点ID等因素。UUID可以使用Java自带的UUID类来生成,如下所示:

    javaCopy codeimport java.util.UUID;public class UuidGenerator {    public static void main(String[] args) {        UUID uuid = UUID.randomUUID();        System.out.println(uuid.toString());    }}

    UUID的优点是简单易用,无需额外的配置和管理,可以直接使用Java自带的UUID类生成。但是UUID长度较长(128位),不太适合作为数据库表的主键,且不易于排序和索引。

    Snowflake

    Snowflake是Twitter开源的一种分布式ID生成算法,它可以生成64位的唯一ID,其中包含了时间戳、数据中心ID和机器ID等信息。Snowflake算法的Java代码如下所示:

    Snowflake算法的Java代码:
    javaCopy codepublic class SnowflakeGenerator {    private final static long START_STMP = 1480166465631L;    private final static long SEQUENCE_BIT = 12;    private final static long MACHINE_BIT = 5;    private final static long DATACENTER_BIT = 5;    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);    private final static long MACHINE_LEFT = SEQUENCE_BIT;    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;    private long datacenterId;    private long machineId;    private long sequence = 0L;    private long lastStmp = -1L;    public SnowflakeGenerator(long datacenterId, long machineId) {        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");        }        if (machineId > MAX_MACHINE_NUM || machineId < 0) {            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");        }        this.datacenterId = datacenterId;        this.machineId = machineId;    }    public synchronized long nextId() {        long currStmp = getNewstmp();        if (currStmp < lastStmp) {            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");        }        if (currStmp == lastStmp) {            sequence = (sequence + 1) & MAX_SEQUENCE;            if (sequence == 0L) {                currStmp = getNextMill();            }        } else {            sequence = 0L;        }        lastStmp = currStmp;        return (currStmp - START_STMP) << TIMESTMP_LEFT                | datacenterId << DATACENTER_LEFT                | machineId << MACHINE_LEFT                | sequence;    }    private long getNextMill() {        long mill = getNewstmp();        while (mill <= lastStmp) {            mill = getNewstmp();        }        return mill;    }    private long getNewstmp() {        return System.currentTimeMillis();    }}

    Snowflake算法的优点是生成ID的性能高,且ID长度较短(64位),可以作为数据库表的主键,且便于排序和索引。但是需要注意,如果集群中的节点数超过了机器ID所占的位数,或者集群规模很大,时间戳位数不够用,那么就需要考虑其他的分布式ID生成算法。

    Leaf

    Leaf是美团点评开源的一种分布式ID生成算法,它可以生成全局唯一的64位ID。Leaf算法的Java代码如下所示:

    Leaf算法的Java代码:
    javaCopy codepublic class LeafGenerator {    private static final Logger logger = LoggerFactory.getLogger(LeafGenerator.class);    private static final String WORKER_ID_KEY = "leaf.worker.id";    private static final String PORT_KEY = "leaf.port";    private static final int DEFAULT_PORT = 8080;    private static final int DEFAULT_WORKER_ID = 0;    private static final int WORKER_ID_BITS = 10;    private static final int SEQUENCE_BITS = 12;    private static final int MAX_WORKER_ID = (1 << WORKER_ID_BITS) - 1;    private static final int MAX_SEQUENCE = (1 << SEQUENCE_BITS) - 1;    private static final long EPOCH = 1514736000000L;    private final SnowflakeIdWorker idWorker;    public LeafGenerator() {        int workerId = SystemPropertyUtil.getInt(WORKER_ID_KEY, DEFAULT_WORKER_ID);        int port = SystemPropertyUtil.getInt(PORT_KEY, DEFAULT_PORT);        this.idWorker = new SnowflakeIdWorker(workerId, port);        logger.info("Initialized LeafGenerator with workerId={}, port={}", workerId, port);    }    public long nextId() {        return idWorker.nextId();    }    private static class SnowflakeIdWorker {        private final long workerId;        private final long port;        private long sequence = 0L;        private long lastTimestamp = -1L;        SnowflakeIdWorker(long workerId, long port) {            if (workerId < 0 || workerId > MAX_WORKER_ID) {                throw new IllegalArgumentException(String.format("workerId must be between %d and %d", 0, MAX_WORKER_ID));            }            this.workerId = workerId;            this.port = port;        }        synchronized long nextId() {            long timestamp = System.currentTimeMillis();            if (timestamp < lastTimestamp) {                throw new RuntimeException("Clock moved backwards. Refusing to generate id");            }            if (timestamp == lastTimestamp) {                sequence = (sequence + 1) & MAX_SEQUENCE;                if (sequence == 0L) {                    timestamp = tilNextMillis(lastTimestamp);                }            } else {                sequence = 0L;            }            lastTimestamp = timestamp;            return ((timestamp - EPOCH) << (WORKER_ID_BITS + SEQUENCE_BITS))                    | (workerId << SEQUENCE_BITS)                    | sequence;        }        private long tilNextMillis(long lastTimestamp) {            long timestamp = System.currentTimeMillis();            while (timestamp <= lastTimestamp) {                timestamp = System.currentTimeMillis();            }            return timestamp;        }    }}

    Leaf算法的特点是生成ID的速度比Snowflake算法略慢,但是可以支持更多的Worker节点。Leaf算法生成的ID由三部分组成,分别是时间戳、Worker ID和序列号,其中时间戳占用42位、Worker ID占用10位、序列号占用12位,总共64位。

    以上是常见的分布式ID生成算法,当然还有其他的一些方案,如:MongoDB ID、UUID、Twitter Snowflake等。不同的方案适用于不同的业务场景,具体实现细节和性能表现也有所不同,需要根据实际情况选择合适的方案。

    除了上述介绍的分布式ID生成算法,还有一些新的分布式ID生成方案不断涌现,例如Flicker的分布式ID生成算法,它使用了类似于Snowflake的思想,但是采用了不同的位数分配方式,相比Snowflake更加灵活,并且可以根据需要动态调整每个部分占用的位数。此外,Facebook还推出了ID Generation Service (IGS)方案,该方案将ID的生成和存储分离,提供了更加灵活和可扩展的方案,但是需要进行更加复杂的架构设计和实现。

    针对不同的业务需求,可以设计多套分布式ID生成方案。下面是我个人的一些建议:

    • 基于数据库自增ID生成:使用数据库自增ID作为全局唯一ID,可以很好的保证ID的唯一性,并且实现简单,但是并发量较高时可能会导致性能瓶颈。因此,在高并发场景下不建议使用。

    • 基于UUID生成:使用UUID作为全局唯一ID,可以很好地保证ID的唯一性,但是ID长度较长(128位),不便于存储和传输,并且存在重复ID的概率非常小但不为0。因此,建议在分布式系统中使用时要考虑ID的长度和存储传输的成本。

    • 基于Redis生成:使用Redis的原子性操作,可以保证ID的唯一性,并且生成ID的速度非常快,可以适用于高并发场景。但是需要注意,如果Redis宕机或者性能不足,可能会影响ID的生成效率和可用性。

    • 基于ZooKeeper生成:使用ZooKeeper的序列号生成器,可以保证ID的唯一性,并且实现较为简单,但是需要引入额外的依赖和资源,并且可能会存在性能瓶颈。

    选择适合自己业务场景的分布式ID生成方案,需要综合考虑ID的唯一性、生成速度、长度、存储成本、可扩展性、可用性等多个因素。同时需要注意,不同方案的实现细节和性能表现也有所不同,需要根据实际情况进行权衡和选择。

    下面给出每种方案的详细代码demo:

    基于数据库自增ID生成

    javaCopy codepublic class IdGenerator {    private static final String JDBC_URL = "jdbc:mysql://localhost:3306/test";    private static final String JDBC_USER = "root";    private static final String JDBC_PASSWORD = "password";    public long generateId() {        Connection conn = null;        PreparedStatement pstmt = null;        ResultSet rs = null;        try {            Class.forName("com.mysql.jdbc.Driver");            conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);            pstmt = conn.prepareStatement("INSERT INTO id_generator (stub) VALUES (null)", Statement.RETURN_GENERATED_KEYS);            pstmt.executeUpdate();            rs = pstmt.getGeneratedKeys();            if (rs.next()) {                return rs.getLong(1);            }        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                if (rs != null) {                    rs.close();                }                if (pstmt != null) {                    pstmt.close();                }                if (conn != null) {                    conn.close();                }            } catch (Exception e) {                e.printStackTrace();            }        }        return 0L;    }}

    基于UUID生成

    javaCopy codeimport java.util.UUID;public class IdGenerator {    public String generateId() {        return UUID.randomUUID().toString().replace("-", "");    }}

    基于Redis生成

    javaCopy codeimport redis.clients.jedis.Jedis;public class IdGenerator {    private static final String REDIS_HOST = "localhost";    private static final int REDIS_PORT = 6379;    private static final String REDIS_PASSWORD = "password";    private static final int ID_GENERATOR_EXPIRE_SECONDS = 3600;    private static final String ID_GENERATOR_KEY = "id_generator";    public long generateId() {        Jedis jedis = null;        try {            jedis = new Jedis(REDIS_HOST, REDIS_PORT);            jedis.auth(REDIS_PASSWORD);            long id = jedis.incr(ID_GENERATOR_KEY);            jedis.expire(ID_GENERATOR_KEY, ID_GENERATOR_EXPIRE_SECONDS);            return id;        } catch (Exception e) {            e.printStackTrace();        } finally {            if (jedis != null) {                jedis.close();            }        }        return 0L;    }}

    基于ZooKeeper生成

    javaCopy codeimport java.util.concurrent.CountDownLatch;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class IdGenerator implements Watcher {    private static final String ZK_HOST = "localhost";    private static final int ZK_PORT = 2181;    private static final int SESSION_TIMEOUT = 5000;    private static final String ID_GENERATOR_NODE = "/id_generator";    private static final int ID_GENERATOR_EXPIRE_SECONDS = 3600;    private long workerId = 0;    public IdGenerator() {        try {            ZooKeeper zk = new ZooKeeper(ZK_HOST + ":" + ZK_PORT, SESSION_TIMEOUT, this);            CountDownLatch latch = new CountDownLatch(1);            latch.await();            if (zk.exists(ID_GENERATOR_NODE, false) == null) {                zk.create(ID_GENERATOR_NODE, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);            }            workerId = zk.getChildren(ID_GENERATOR_NODE, false).size();            zk.create(ID_GENERATOR_NODE + "/worker_" + workerId, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);        } catch (Exception e) {            e.printStackTrace();        }    }    public long generateId() {        ZooKeeper zk = null;        try {            zk = new ZooKeeper(ZK_HOST + ":" + ZK_PORT, SESSION_TIMEOUT, null);            CountDownLatch latch = new CountDownLatch(1);            latch.await();            zk.create(ID_GENERATOR_NODE + "/id_", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, (rc, path, ctx, name) -> {}, null);            byte[] data = zk.getData(ID_GENERATOR_NODE + "/worker_" + workerId, false, null);            long id = Long.parseLong(new String(data)) * 10000 + zk.getChildren(ID_GENERATOR_NODE, false).size();            return id;        } catch (Exception e) {            e.printStackTrace();        } finally {            if (zk != null) {                try {                    zk.close();                } catch (Exception e) {                    e.printStackTrace();                }            }        }        return 0L;    }    @Override    public void process(WatchedEvent event) {        if (event.getState() == Event.KeeperState.SyncConnected) {            System.out.println("Connected to ZooKeeper");            CountDownLatch latch = new CountDownLatch(1);            latch.countDown();        }    }}

    注意,这里使用了ZooKeeper的临时节点来协调各个工作节点,如果一个工作节点挂掉了,它的临时节点也会被删除,这样可以保证每个工作节点获得的ID是唯一的。

    关于“redis分布式ID解决方法有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    redis分布式ID解决方法有哪些

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    redis分布式ID解决方法有哪些

    这篇文章主要介绍“redis分布式ID解决方法有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“redis分布式ID解决方法有哪些”文章能帮助大家解决问题。常用的分布式ID解决方案在分布式系统中,
    2023-07-05

    redis分布式ID解决方案示例详解

    目录常用的分布式ID解决方案UUIDSnowflakeSnowflake算法的Java代码:LeafLeaf算法的Java代码:基于数据库自增ID生成基于UUID生成基于Redis生成基于ZooKeeper生成常用的分布式ID解决方案在分布
    2023-03-07

    Redis实现分布式锁的方法有哪些

    今天小编给大家分享一下Redis实现分布式锁的方法有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1. 单机数据一致性单
    2023-07-02

    redis分布式锁的坑有哪些

    这篇“redis分布式锁的坑有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“redis分布式锁的坑有哪些”文章吧。1 非
    2023-07-02

    redis分布式锁的作用有哪些

    防止多个客户端同时操作同一个资源,保证数据的一致性和完整性。避免资源的并发访问导致的竞态条件和错误。控制对共享资源的访问顺序,避免出现死锁等问题。提高系统的性能和稳定性,避免因为资源的并发访问而导致系统性能下降或宕机。
    redis分布式锁的作用有哪些
    2024-04-09

    Redis分布式技术面试题有哪些

    这篇文章主要介绍“Redis分布式技术面试题有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Redis分布式技术面试题有哪些”文章能帮助大家解决问题。1. 分布式缓存1.1. Redis 有什么
    2023-06-02

    redis中的分布式锁有哪些特点

    本篇内容主要讲解“redis中的分布式锁有哪些特点”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“redis中的分布式锁有哪些特点”吧!分布式锁的特点1.独占性不论在
    2023-04-14

    redis动态分页的方法有哪些

    Redis是一个内存数据库,不支持动态分页。它是一个键值存储系统,可以通过键获取对应的值,而不支持直接根据某个值进行分页操作。但是可以通过一些技巧来实现动态分页的效果,下面是一些常见的方法:1. 使用有序集合(Sorted Set):将需要
    2023-08-24

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录