먼저 전역 고유 ID가 정수인지 문자열인지 확인해야 합니다. 문자열인 경우 기존 UUID가 요구 사항을 완전히 충족하므로 추가 작업이 필요하지 않습니다. 단점은 문자열이 ID로 많은 공간을 차지하고, 인덱싱 효율성이 정수보다 낮다는 것입니다.
ID로 정수를 사용하는 경우 범위가 너무 작기 때문에 먼저 32비트 int 유형을 제외하고 64비트 long 유형을 사용해야 합니다. 정수를 ID로 사용할 때 자체 증가하고 전역적으로 고유하며 중복되지 않는 ID를 생성하는 방법은 무엇입니까? 옵션 1: 데이터베이스의 자체 증가 ID를 사용하면 1부터 시작하여 기본적으로 연속 증가를 달성할 수 있습니다. Oracle은SEQUENCE
를 사용할 수 있고, MySQL은 기본 키로 AUTO_INCREMENT
를 사용할 수 있지만 전역 고유성을 보장할 수는 없지만 각 테이블마다 고유하며 기본적으로 요구 사항을 충족합니다. 데이터베이스 자체 증가 ID의 단점은 데이터가 삽입되기 전에 ID를 얻을 수 없다는 것입니다. 데이터가 삽입된 후 획득한 ID는 고유하더라도 거래가 제출될 때까지 ID는 유효한 것으로 간주되지 않습니다. 일부 양방향 참조 데이터를 삽입한 후 업데이트해야 하는데 이는 번거로운 작업입니다. 두 번째 방법은 Redis 또는 ZooKeeper와 같은 중앙 집중식 ID 생성기를 사용하거나 데이터베이스 테이블을 사용하여 마지막으로 할당된 ID를 기록하는 것입니다. SEQUENCE
,MySQL可以用主键的AUTO_INCREMENT
,虽然不能保证全局唯一,但每个表唯一,也基本满足需求。
数据库自增ID的缺点是数据在插入前,无法获得ID。数据在插入后,获取的ID虽然是唯一的,但一定要等到事务提交后,ID才算是有效的。有些双向引用的数据,不得不插入后再做一次更新,比较麻烦。
第二种方式是采用一个集中式ID生成器,它可以是Redis,也可以是ZooKeeper,也可以利用数据库的表记录最后分配的ID。
这种方式最大的缺点是复杂性太高,需要严重依赖第三方服务,而且代码配置繁琐。一般来说,越是复杂的方案,越不可靠,并且测试越痛苦。
第三种方式是类似Twitter的Snowflake算法,它给每台机器分配一个唯一标识,然后通过时间戳+标识+自增实现全局唯一ID。这种方式好处在于ID生成算法完全是一个无状态机,无网络调用,高效可靠。缺点是如果唯一标识有重复,会造成ID冲突。
Snowflake算法采用41bit毫秒时间戳,加上10bit机器ID,加上12bit序列号,理论上最多支持1024台机器每秒生成4096000个序列号,对于Twitter的规模来说够用了。
但是对于绝大部分普通应用程序来说,根本不需要每秒超过400万的ID,机器数量也达不到1024台,所以,我们可以改进一下,使用更短的ID生成方式:
53bitID由32bit秒级时间戳+16bit自增+5bit机器标识组成,累积32台机器,每秒可以生成6.5万个序列号,核心代码:
private static synchronized long nextId(long epochSecond) { if (epochSecond < lastEpoch) { // warning: clock is turn back: logger.warn("clock is back: " + epochSecond + " from previous:" + lastEpoch); epochSecond = lastEpoch; } if (lastEpoch != epochSecond) { lastEpoch = epochSecond; reset(); } offset++; long next = offset & MAX_NEXT; if (next == 0) { logger.warn("maximum id reached in 1 second in epoch: " + epochSecond); return nextId(epochSecond + 1); } return generateId(epochSecond, next, SHARD_ID);}
时间戳减去一个固定值,此方案最高可支持到2106年。
如果每秒6.5万个序列号不够怎么办?没关系,可以继续递增时间戳,向前“借”下一秒的6.5万个序列号。
同时还解决了时间回拨的问题。
机器标识采用简单的主机名方案,只要主机名符合host-1
,host-2
就可以自动提取机器标识,无需配置。
最后,为什么采用最多53位整型,而不是64位整型?这是因为考虑到大部分应用程序是Web应用,如果要和JavaScript打交道,由于JavaScript支持的最大整型就是53位,超过这个位数,JavaScript将丢失精度。因此,使用53位整数可以直接由JavaScript读取,而超过53位时,就必须转换成字符串才能保证JavaScript处理正确,这会给API接口带来额外的复杂度。这也是为什么新浪微博的API接口会同时返回id
和idstr
이 방법의 가장 큰 단점은 너무 복잡하고 타사 서비스에 대한 의존도가 높으며 코드 구성이 번거롭다는 것입니다. 일반적으로 솔루션이 복잡할수록 신뢰성이 떨어지고 테스트하기가 더 어려워집니다.
세 번째 방법은 Twitter의 Snowflake 알고리즘과 유사합니다. 각 컴퓨터에 고유 ID를 할당한 다음 타임스탬프 + ID + 자동 증가를 통해 전역적으로 고유한 ID를 구현합니다. 이 방법의 장점은 ID 생성 알고리즘이 완전히 상태 비저장 시스템이고 네트워크 호출이 없으며 효율적이고 안정적이라는 것입니다. 단점은 중복된 고유 식별자가 있으면 ID 충돌이 발생한다는 것입니다. Snowflake 알고리즘은 41비트 밀리초 타임스탬프, 10비트 컴퓨터 ID, 12비트 일련 번호를 사용합니다. 이론적으로 최대 1024개의 컴퓨터를 지원하여 초당 4096000개의 일련 번호를 생성할 수 있으며 이는 Twitter 규모에 충분합니다. 그러나 대부분의 일반적인 애플리케이션의 경우 초당 400만 개 이상의 ID가 필요하지 않으며 머신 수가 1024개에 도달하지 않습니다. 따라서 이를 개선하고 더 짧은 ID 생성 방법을 사용할 수 있습니다:
🎜 53bitID 32비트 2단계 타임스탬프 + 16비트 자동 증가 + 5비트 기계 식별로 구성됩니다. 32개의 기계를 축적하고 초당 65,000개의 일련 번호를 생성할 수 있습니다. 핵심 코드: 🎜rrreee🎜타임스탬프에서 고정 값을 뺀 값을 생성할 수 있습니다. 2106년까지 지원됩니다. 🎜🎜초당 65,000개의 일련번호로는 충분하지 않다면 어떻게 되나요? 문제가 되지 않습니다. 계속해서 타임스탬프를 증가시키고 다음 초 동안 65,000개의 시퀀스 번호를 "빌려올" 수 있습니다. 🎜🎜동시에 시간 다이얼백 문제도 해결되었습니다. 🎜🎜시스템 식별은 간단한 호스트 이름 체계를 사용합니다. 호스트 이름이host-1
과 일치하는 한, host-2
는 구성 없이 자동으로 시스템 식별을 추출할 수 있습니다. 🎜🎜마지막으로 64비트 정수 대신 최대 53비트 정수를 사용하는 이유는 무엇입니까? 대부분의 애플리케이션이 웹 애플리케이션이라는 점을 고려하면 자바스크립트를 다루려고 할 때 자바스크립트가 지원하는 최대 정수는 53자리이기 때문이다. 이 숫자를 넘어서면 자바스크립트는 정밀도를 잃게 된다. 따라서 53비트 정수는 JavaScript에서 직접 읽을 수 있지만 53비트를 초과하는 경우 JavaScript에서 올바른 처리를 보장하기 위해 문자열로 변환해야 하므로 API 인터페이스가 더욱 복잡해집니다. 이는 Sina Weibo의 API 인터페이스가 id
와 idstr
를 모두 반환하는 이유이기도 합니다. 🎜🎜추천 튜토리얼: "🎜PHP🎜" "🎜Laravel Tutorial🎜"🎜위 내용은 Laravel 분산 고유 ID 생성기 사용법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!