当前位置:首页 > 文章列表 > 数据库 > Redis > redis分布式ID解决方案示例详解

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

来源:脚本之家 2023-05-12 19:27:23 0浏览 收藏

小伙伴们对数据库编程感兴趣吗?是否正在学习相关知识点?如果是,那么本文《redis分布式ID解决方案示例详解》,就很适合你,本篇文章讲解的知识点主要包括解决方案、redis分布式ID。在之后的文章中也会多多分享相关知识点,希望对大家的知识积累有所帮助!

常用的分布式ID解决方案

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

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

UUID

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

javaCopy code
import 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 code
public 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  MAX_DATACENTER_NUM || datacenterId  MAX_MACHINE_NUM || machineId 

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

Leaf

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

Leaf算法的Java代码:

javaCopy code
public 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  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 

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 code
public 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 code
import java.util.UUID;
public class IdGenerator {
    public String generateId() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}

基于Redis生成

javaCopy code
import 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 code
import 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解决方案示例详解》的详细内容,更多关于redis的资料请关注golang学习网公众号!

版本声明
本文转载于:脚本之家 如有侵犯,请联系study_golang@163.com删除
利用ChatGPT编写一个Golang图像压缩函数利用ChatGPT编写一个Golang图像压缩函数
上一篇
利用ChatGPT编写一个Golang图像压缩函数
一文详解如何使用Golang处理文件
下一篇
一文详解如何使用Golang处理文件
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • 笔灵AI生成答辩PPT:高效制作学术与职场PPT的利器
    笔灵AI生成答辩PPT
    探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
    8次使用
  • 知网AIGC检测服务系统:精准识别学术文本中的AI生成内容
    知网AIGC检测服务系统
    知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
    19次使用
  • AIGC检测服务:AIbiye助力确保论文原创性
    AIGC检测-Aibiye
    AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
    27次使用
  • 易笔AI论文平台:快速生成高质量学术论文的利器
    易笔AI论文
    易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
    36次使用
  • 笔启AI论文写作平台:多类型论文生成与多语言支持
    笔启AI论文写作平台
    笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
    33次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码