亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Java分布式ID生成機制與實戰應用詳解

標簽:
雜七雜八
概述

文章探讨了分布式系统中ID生成的关键性,强调在多节点环境下确保数据一致性和追踪性的必要性。通过分析雪花算法和TikTok TimeId等机制,展示了如何在Java中实现高效、全局唯一且低延迟的分布式ID生成。文章还介绍了Snowflake和Curator等库在Java项目中的应用,以实现分布式ID生成。最后,通过一个在线投票系统的实战案例,直观演示了分布式ID在实际场景中的应用,以及在高可用和性能优化方面的考量。

引言

在分布式系统中,ID生成是关键的组件之一,它不仅影响着数据的一致性和可追踪性,还直接影响着系统的性能与扩展性。一个高效、可靠的分布式ID生成系统,能够确保在分布式环境下,每一笔交易或事件都能被唯一标识,这对于构建高性能、高可用的分布式系统至关重要。

分布式id的起源与基础概念

分布式系统的挑战

在分布式系统中,多个独立的节点通过网络进行通信和协作,解决单机系统无法解决的大量并发请求和数据存储问题。然而,这种架构也带来了新的挑战,如一致性问题、数据分片、网络延迟、故障恢复等。

为什么需要分布式id系统

在分布式系统中,由于节点间的网络延迟和失效,同一事件在网络的不同路径上可能会产生不同的ID。这可能导致数据的重复、不一致性和难以追踪的问题。因此,一个一致、全局唯一的ID生成机制是分布式系统不可或缺的一部分。

分布式id的基本工作原理

分布式ID的设计目标是提供全局唯一性、高性能、低延迟、在分布式环境下的一致性。它通常通过结合时间戳、序列号和节点标识符来生成一个全局唯一的ID。

分布式id生成算法与机制

雪花算法

雪花算法(Snowflake)是Twitter开源的分布式ID生成算法,它利用了8个字段来生成全局唯一的ID:

  • 时间戳:占41位,允许生成超过640年的ID。
  • 工作机器ID:占10位,可以标识2047个节点。
  • 序列号:占12位,用于同一毫秒内的微秒序号,能够生成4096个ID。

雪花算法的生成过程如下:

public class SnowflakeIdGenerator implements IDGenerator {
    private final long workerId;
    private final long dataCenterId;
    private final long sequenceBits = 12;
    private final long workerIdBits = 10;
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
    private final long timestampLeftShift = sequenceBits;
    private final long timestampLeftShiftBits = timestampLeftShift << sequenceBits;
    private final long workerIdShift = timestampLeftShiftBits << sequenceBits;
    private final long sequenceShift = workerIdShift << sequenceBits;
    private long lastTimestamp = -1L;

    private SnowflakeIdGenerator(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 > -1 || dataCenterId < 0) {
            throw new IllegalArgumentException("datacenter Id can't be negative");
        }
        this.workerId = workerId;
        this.dataCenterId = dataCenterId;
    }

    @Override
    public 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 << workerIdShift) | (workerId << sequenceShift) | sequence;
    }

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

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

    public static void main(String[] args) {
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
        for (int i = 0; i < 100; i++) {
            System.out.println(idGenerator.nextId());
        }
    }
}

TikTok TimeId

TikTok的TimeId算法则是另一种分布式ID生成方式,它使用了一个简单的公式 ID = Time * 1000000 + Seq,其中时间戳以毫秒为单位,Seq 是一个在给定时间戳范围内的序列号。

public class TimeIdGenerator implements IDGenerator {
    private static final long BASE = 1000000;
    private static final int SEQUENCE_LENGTH = 10;
    private static final int SEQ_MASK = (1 << SEQUENCE_LENGTH) - 1;
    private static final int BASE_MASK = (1 << SEQUENCE_LENGTH) - 1;
    private static final int TIMESTAMP_LENGTH = 16;
    private static final int TIMESTAMP_MASK = (1L << TIMESTAMP_LENGTH) - 1;
    private volatile long lastTimestamp = -1;

    @Override
    public long nextId() {
        long timestamp = System.currentTimeMillis();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp));
        } else if (timestamp == lastTimestamp) {
            synchronized (this) {
                int seq = (int) (sequence & SEQ_MASK);
                if (seq == 0) {
                    timestamp = tilNextMillis(lastTimestamp);
                } else {
                    sequence = (sequence + 1) & SEQ_MASK;
                    return ((timestamp - lastTimestamp) * BASE) + seq;
                }
            }
        } else {
            lastTimestamp = timestamp;
            sequence = 0;
            return (timestamp - BASE) * BASE + 1;
        }
        return (timestamp - BASE) * BASE + (sequence & SEQ_MASK);
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    public static void main(String[] args) {
        TimeIdGenerator idGenerator = new TimeIdGenerator();
        for (int i = 0; i < 100; i++) {
            System.out.println(idGenerator.nextId());
        }
    }
}

JAVA中实现分布式id的常用库

Snowflake

Snowflake提供了Java客户端,允许在Java项目中轻松集成分布式ID生成。使用Snowflake可以简化ID生成逻辑,并确保系统的一致性和性能。

<dependency>
    <groupId>com.twitter</groupId>
    <artifactId>雪球</artifactId>
    <version>2.7.14</version>
</dependency>

Curator

Curator是一个Apache项目,提供了用于分布式协调的库,包括分布式锁、监视器和分布式ID生成功能。通过Curator,可以轻松地在分布式环境中实现ID生成。

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>5.1.0</version>
</dependency>

实战案例:JAVA分布式id生成与应用

项目设计

假设我们正在构建一个在线投票系统,需要为每一次投票事件生成唯一的ID,以确保投票的唯一性和可追踪性。

代码示例

在项目中引入Snowflake和Curator依赖后,可以如下实现分布式ID生成:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.x.discovery.ServiceDiscovery;
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.ServiceInstanceBuilder;
import org.apache.curator.x.discovery.ServiceInstanceListener;
import org.apache.curator.x.discovery.UriProvider;
import org.apache.curator.x.discovery.UriProviderBuilder;
import org.apache.curator.x.discovery.ServiceDiscoveryProvider;
import org.apache.curator.x.discovery.support.AnonymousInstance;
import org.apache.curator.x.discovery.support.ProviderType;
import org.apache.curator.x.discovery.support.ServiceInstanceBuilder;

import java.util.concurrent.CountDownLatch;

public class VotingSystem {
    private CuratorFramework client;
    private ServiceDiscovery<ServiceInstance> discovery;

    public VotingSystem() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        client = CuratorFrameworkFactory.newClient("localhost:2181", retryPolicy);
        client.start();

        // 初始化服务注册
        discovery = ServiceDiscovery.builder()
                .client(client)
                .provider(ProviderType.PUBLISH)
                .build();

        // 注册服务
        ServiceInstance serviceInstance = ServiceInstanceBuilder.builder(ServiceInstance.newBuilder()
                .serviceName("VotingService")
                .host("localhost")
                .port(8080)
                .build())
                .build();
        discovery.registerService(serviceInstance, new ServiceInstanceListener() {
            @Override
            public void stateChanged(ServiceDiscovery<ServiceInstance> serviceDiscovery, ServiceInstance oldServiceInstance, ServiceInstance newServiceInstance) {
                // 状态变更处理
            }
        });

        // 注册生成器
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
        this.discovery.registerIdGenerator("VotingService", idGenerator);
    }

    public long generateVoteId() {
        return idGenerator.nextId();
    }

    public static void main(String[] args) throws InterruptedException {
        VotingSystem votingSystem = new VotingSystem();
        ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
        CountDownLatch latch = new CountDownLatch(1);

        new Thread(() -> {
            try {
                while (true) {
                    long id = votingSystem.generateVoteId();
                    System.out.println("Generated ID: " + id);
                    latch.countDown();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        latch.await();
    }
}

部署流程与性能优化

在生产环境中,需要确保分布式系统的高可用性和容错性。这包括配置负载均衡器、监控和警报系统等。性能优化方面,可以关注ID生成的并发处理能力、网络延迟及ID生成的延迟时间等指标。

结语

分布式ID生成是构建可靠、高效分布式系统的关键组件。通过理解分布式ID生成的原理、选择合适的生成算法与工具,以及在实际项目中的应用,可以有效提升系统的性能与稳定性。随着技术的不断演进,分布式ID生成技术也在不断发展,未来将更加注重性能优化、安全性和可扩展性,以适应日益增长的分布式应用需求。

點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消