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

ID:957 / 打印

小伙伴们对数据库编程感兴趣吗?是否正在学习相关知识点?如果是,那么本文《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的资料请关注the24.cn!

上一篇: 如何在SpringBoot中使用Redis实现分布式锁
下一篇: Redis使用ZSET实现消息队列使用小结

作者:admin @ 24资源网   2024-09-02

本站所有软件、源码、文章均有网友提供,如有侵权联系308410122@qq.com

与本文相关文章

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。