发号器的设计

数据库中的每条记录都需要一个ID,即使在分库分表后这个ID需要全局唯一性。因此,分库分表后不能使用Mysql自带的自增ID了。因为不通的库之间的ID可能是一样的。

我们以记录海量的用户信息为例,可能会想到身份证号、电话号码或者email。但是这些信息是会变的。如果用户要修改这些信息,那么ID就失效了。无异于新增一条记录,删掉原来的记录。

基于 Snowflake 算法搭建发号器

雪花算法可以提供全局唯一的ID。雪花算法生成的ID一般是分几段的,下图就是典型的ID组成:41位时间戳(一般是毫秒级?)+10位机器ID+12位序列号。

41位时间戳毫秒级的大概有69年,10位机器ID可以表示一个由1024台机器组成的发号器集群。12位序列号表示一毫秒每台机器可以提供4000个不通的ID,也就是一秒钟400W个。。。

为何不用UUID?

这是个好问题,我之前没考虑过。

确实,UUID是32个16进制组成的字符串,也具有全局唯一性。

那么为何不用呢。此处需要考虑业务ID需要哪些特性:1、全局唯一性(UUID符合)2、生成性能要好(UUID符合)3、写入性能要好 4、最好要有具体的业务含义,方便定位问题。

前两点UUID都符合,我们都知道Mysql对于随机写的TPS是很差的,对于顺序写性能很好。因为顺序写入节约了一次寻道时间。而写入是要按照ID排序的。UUID是随机的,不是递增的,所以如果用UUID作为mysql的ID是会严重影响写入性能的。

不用UUID作为mysql ID的另一个原因是UUID不具备业务解释性,比如我们之前设计的ID就是用类似于雪花算法生成的,时间戳+机器ID+其他一些业务信息,这样出现了badcase,第一时间拿到ID就知道是哪个方面出问题了。比如文章ID最后两位表示文章来源,那么如果badcase的ID都集中在某一个来源,那么直觉告诉我们某些特定业务出问题了,便于排查问题。

雪花算法如何落地?

大致有两种做法:

一、嵌入在代码里面,每台机器有自己的机器ID,这样就能生成唯一的ID了。这样做的好处是没有网络交互,性能好。不过如果机器众多或者机器重启,比较难保证每台机器ID是唯一的,这样就要引入ZK等组件来保证ID的一致性,这样就引入了新的zk问题。

二、第二种做法是,搭建一个发号器集群。这样做每次插入ID都会有一个额外的网络交互,但是对于内网来说,性能损失很小,这方面的损失是可以接受的。由于发号器性能很好,所以只需要少量机器就能提供大量的ID,QPS很高。这样可以减少机器数量,ID中用于表示机器ID的位数可以减少,提供的号就会变多。如果只有一台发号器,多个备份发号器,那么可以无需机器ID。一般情况下有少量的几台一起提供发号服务,此时由于机器较少,可以把机器ID写到配置文件中,也不会因为方法一带来的第三方组件问题。

可能引入的问题

雪花算法最大的问题就是他依赖于时间戳,如果时间不准了,那么就有可能导致产生重复的ID,此时需要调整时间,再发号。

还有一个可能引入的问题是如果QPS不高,那么以毫秒为粒度的ID可能分配不均匀,极端例子就是QPS为1,每秒的第一个毫秒产生一个ID,业务方拿到ID后根据时间戳去hash到每个库中,那么就会导致数据的不均匀。因此,很多实践过程中都是根据自己的需要进行变种的。可以把雪花算法前面的时间戳粒度变为秒,而不是毫秒。这样ID至于时间的分布就会相对均匀很多。

原文地址:https://www.cnblogs.com/howo/p/12147595.html

时间: 2024-10-07 15:40:26

发号器的设计的相关文章

FAQ系列 | 用MySQL实现发号器

问题:用MySQL实现发号器功能,确保每次取到的ID号都是唯一的实现:下面是一个大致的思路,抛个砖,欢迎回帖.根据号段大小,决定是否分成多个表,每个表事先填充各个不同的号段.每个应用端取号时,设置事务隔离级别为:REPEATABLE READ,并且采用下面的方式读取数据 SELECT `ID` FROM `ID_RANGE_XX` ORDER BY ID LIMIT 1 FOR UPDATE 在上述情境中,只要选择某个ID号,那么其他终端也在读取该号时,会产生锁等待,而不会发生ID号被重用的情况

野谈系列之高性能可定制化分布式发号器

刘兵,花名玄靖,开源技术爱好者,高性能Redis中间件NRedis-Proxy作者,目前研究方向为java中间件,微服务等技术. 一.什么是分布式发号器 说起分布式发号器的前生今世,咱们应该感恩这个时代:随着互联网在中国越来越普及化,单机系统或者一个小系统已经无法满足需要,随着用户逐渐增多,数据量越来越大,单个应用或者单个数据库已经无法满足需求,在应用以至于微服务来临,在数据库存储方面分库分表来临,可以解决问题:但是新的问题产生,怎么样做到多个应用可以有唯一主键或者序号,防止数据重复呢?分布式发

redis实现发号器

通过mysql的auto increment自增id值可能会泄漏一些敏感的数据. 例如用户表的user_id是自增的,在url中显示的id值可能就泄露了网站真实的用户数. 下面代码通过php及redis的incrby实现简单的发号器,代码如下: function get_id($type, $server_ip, $server_port, $key) { $init_num = 0; $redis= new Redis(); $redis->connect($server_ip, $serve

关于snowflake发号器算法简单学习

概述 在分布式系统中,有一些需要使用全局唯一的ID编号,最常使用的方法是在每个系统间传递和保存一个统一唯一流水号,通过系统间两辆核对或者第三方核对唯一流水号来保证各个系统之间步伐一致,没有掉队的行为,也就是系统间状态一致,在互联网的世界里,产生唯一流水号的服务系统俗称发号器. 当前业务系统的ID使用数据库的自增字段,自增字段完全依赖于数据库,这在数据库移植,扩容,洗数据,分库分表等操作时带来了很多麻烦. 在数据库分库分表时,有一种办法是通过调整自增字段或者数据库sequence的步长来达到跨数据

分布式——分布式发号器

今天停电,所以springboot源码看不了,手头刚好有本书,学习了下分布式发号器 一.方案 1.UUID 2.数据库自增序列 3.Snowflake——雪花算法 二.自定义设计需求与实现 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12578508.html

lua学习笔记之-----5行代码完成ID发号器

版权归作者所有,任何形式转载请联系作者. --生成ID的位数比较合理长度为52个bit,然后可以时间上有序的,包含项目和实例信息 -- 在redis客户端执行: redis-cli -h 127.0.0.1 -p 6379 EVAL "$(cat ticketID.lua)" 2 01 02-- EVAL 后面的参数解释 "$(cat ticketID.lua)"是我们执行的lua脚本文件,-- "2"是代表传入lua脚本的参数有两个KEY,--

c# winform 面向对象设计体育彩票选号器

用到的知识很简单:产生随机数.保存数据到文本文件.定时器的使用等.主要体现c#面向对象设计的思想.界面效果如下: 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 体育彩票选号器 8 { 9 /// <summary> 10 /// 日历类 11 /// </s

Linux进程调度器的设计--Linux进程的管理与调度(十七)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度 前景回顾 进程调度 内存中保存了对每个进程的唯一描述, 并通过若干结构与其他进程连接起来. 调度器面对的情形就是这样, 其任务是在程序之间共享CPU时间, 创造并行执行的错觉, 该任务分为两个不同的部分, 其中一个涉及调度策略, 另外一个涉及上下文切换. 内核必须提供一种方法, 在各个进程之间尽可能公平地

[连载]《C#通讯(串口和网络)框架的设计与实现》-4.设备驱动管理器的设计

目       录 第四章           设备驱动管理器的设计... 2 4.1           接口定义... 2 4.2           设备容器... 7 4.3           生成设备ID.. 7 4.4           对设备容器操作的互斥... 8 4.5           获得设备列表... 8 4.6           设备计数器的特殊用处... 8 4.7           小结... 10 第四章     设备驱动管理器的设计 设备驱动管理器是对