当前位置: 首页 > 科技观察

关于主键,除了自增,还可以这样做

时间:2023-03-23 10:23:27 科技观察

目前各大关系型数据库都提供了自增主键生成策略,比如Mysql的AUTO_INCREMENT,SqlServer的IDENTITY,Oracle使用SEQUENCE实现主键自增-增量。使用自增主键比较简单,占用空间小;主键顺序存储,不会造成分页;同时也存在一些不足,比如在多个系统之间整合数据时,容易出现主键冲突;数据库单表压力大,不适合高并发、分布式场景。自增主键便于检测系统业务量等,可见在系统业务量较小、并发量不大的情况下,使用自增主键是较好的选择,但当面临高并发和分布式需求,使用自增主键会有很大的瓶颈。下面介绍一些目前业界比较流行的主键生成策略。1、UUID模式通用唯一标识符(UniversallyUniqueIdentifier),按照标准方法生成,不依赖中央权威机构的注册和分配,UUID唯一,UUID码重复概率接近于零,可以被忽略。UUID有多个版本:基于时间的UUID、DCE安全的UUID、基于名称的UUID(MD5)(UUID.nameUUIDFromBytes())、随机UUID(UUID.randomUUID().toString())、基于名称的UUID(SHA1),Version1/2适用于分布式计算环境,具有高度的独特性;3/5版本适用于需要相同内容生成相同UUID的业务场景;版本4不推荐(随机数可能会出现Repeat,但重复的概率极低,设计时需要考虑到这一点)。UUID虽然解决了依赖数据库生成主键的策略,但也有一些缺点:占用存储空间大;随机生成,不连续,用作主键时性能较差;不能根据主键排序来确定插入记录的顺序。;对开发者不友好;如果在生成过程中使用本机的MAC地址,存在一定的安全隐患。2.步长方式是Flickr的sharding主键生成方案。使用多个数据库服务器,通过设置不同的初始值和一致的自增步长,使每个数据库中的每个表的主键保持唯一。如图:步长方式在一定程度上解决了高并发的问题,但是仍然存在一些问题如:扩展困难,设置步长后,会很难扩展;ID在顺序上并不是严格单调的,增量特征只是递增的趋势;每次获取ID,还是需要读写一次数据库,还是有瓶颈的。3、数段方式是指每次从数据库中获取id,从数据库中获取当前id的最大值,然后返回max+step。当应用程序用完这个号码段时,从数据库部分获取下一个长度为step的号码。为此,需要设计一个表来记录id。当应用服务为集群,主键服务器为单点时,多个应用服务节点同时获取id时,会发生冲突。您可以添加版本字段以使用乐观锁定进行并发访问控制。数段模式将主键缓存在应用服务器上,从而降低访问数据库的频率;当数据库数据库不可用时,应用服务仍然可以运行一段时间,直到当前号段用完;但是在应用服务重启的时候可能会丢失部分id,导致id不连续增长。有一些基于号段模型的成熟方案,并经过实践验证:美团的Leaf-segment针对号段分配方式实现了双缓冲缓存和高可用容灾优化。使用双缓冲模式,当当前号码段消耗到一定程度时,异步加载下一个号码段到内存中。无需等到号码段用完再更新号码段,应用服务器向数据库请求id时,不会因为没有取到id号码段而阻塞线程。滴滴的TinyId参考了美团Leaf的实现,并对其进行了扩展,增加了multi-db支持和tinyid-client。4.雪花模式(SnowflakeAlgorithm)Twitter实现的分布式ID生成算法。结构如下:0-00000000000000000000000000000000000000000-00000-00000-0000000000001位:保留位,符号位,全0,表示生成的id都是正数。41bit:时间戳,单位毫秒,41位可以代表69年。10bit:machineid,10bit中5位代表机房id,5位代表machineid,可以代表32个机房,每个机房可以使用32台机器。12bit:12位序号,按顺序递增,记录1毫秒内每个节点产生的id,每毫秒可产生4096个id。雪花的优点:主键在单个节点上顺序递增,可以按照时间趋势递增。主键的生成不依赖于数据库,可以由应用程序生成。分布式集群中不会产生重复的id。bits可以根据业务需求进行调整。snowflake的缺点:对时间的依赖性强,如果时间往回拨,主键会重复。当集群规模较大时,workid配置会增加开销。美团Leaf-snowflake使用zk解决snowflake依赖时钟,时间回调产生重复主键的问题;百度的UidGenerator支持自定义时间戳、workerIds、序列号等。5.Redis模式是使用Redis原子操作INCR和INCRBY实现的。Redis集群用于提高并发性。它类似于步长模式,只是将id生成器从传统数据库替换为更高效的Redis数据库。但是当Redis重启或者崩溃时,记录的主键值会丢失,所以使用Redis生成主键时需要持久化当前的主键值。Redis支持两种持久化机制,RDB和AOF。RDB模式下,可能会丢失一些未镜像的数据,恢复快照后会产生一些重复的ID,所以RDB不适合实现持久化Redis数据的场景。AOF使用独立的日志记录每条写命令,重启时执行日志中的命令恢复数据。不会出现ID重复,但是由于备份命令太多,Redis恢复数据的时间会比较长。以上介绍了五种数据库主键生成策略。您可以根据自己的具体业务场景和实际系统情况选择最合适的主键策略,以提高数据库性能,保证高并发条件下的系统稳定性。

最新推荐
猜你喜欢