何为分布式 ID?
分布式 ID 是分布式系统下的 ID。分布式 ID 不存在与现实生活中,属于计算机系统中的一个概念。
在分库分表的情况下就会产生分布式ID问题!
分库分表有水平和垂直两种情况。
在分库之后, 数据遍布在不同服务器上的数据库,数据库的自增主键已经没办法满足生成的主键唯一了。我们如何为不同的数据节点生成全局唯一主键呢?
分布式 ID 需要满足哪些要求?
一个最基本的分布式 ID 需要满足下面这些要求:
- 全局唯一 :ID 的全局唯一性肯定是首先要满足的!
- 高性能 : 分布式 ID 的生成速度要快,对本地资源消耗要小。
- 高可用 :生成分布式 ID 的服务要保证可用性无限接近于 100%。
- 方便易用 :拿来即用,使用方便,快速接入!
除了这些之外,一个比较好的分布式 ID 还应保证:
- 安全 :ID 中不包含敏感信息。
- 有序递增 :如果要把 ID 存放在数据库的话,ID 的有序性可以提升数据库写入速度。并且,很多时候 ,我们还很有可能会直接通过 ID 来进行排序。
- 有具体的业务含义 :生成的 ID 如果能有具体的业务含义,可以让定位问题以及开发更透明化(通过 ID 就能确定是哪个业务)。
- 独立部署 :也就是分布式系统单独有一个发号器服务,专门用来生成分布式 ID。这样就生成 ID 的服务可以和业务相关的服务解耦。不过,这样同样带来了网络调用消耗增加的问题。总的来说,如果需要用到分布式 ID 的场景比较多的话,独立部署的发号器服务还是很有必要的。
生成分布式ID
方式一
直接使用关系型数据库,如MySQL 主键自增的方式来产生,创建是挺方便的,但会带来一些问题:
支持的并发量不大、存在数据库单点问题(可以使用数据库集群解决,不过增加了复杂度)、ID 没有具体业务含义、安全问题(比如根据订单 ID 的递增规律就能推算出每天的订单量,商业机密啊! )、每次获取 ID 都要访问一次数据库(增加了对数据库的压力,获取速度也慢)
方式二
数据库号段模式
数据库主键自增这种模式,每次获取 ID 都要访问一次数据库,ID 需求比较大的时候,肯定是不行的。
如果我们可以批量获取,然后存在在内存里面,需要用到的时候,直接从内存里面拿就舒服了!这也就是我们说的 基于数据库的号段模式来生成分布式 ID。
数据库的号段模式也是目前比较主流的一种分布式 ID 生成方式。像滴滴开源的Tinyidopen in new window 就是基于这种方式来做的。不过,TinyId 使用了双号段缓存、增加多 db 支持等方式来进一步优化。
数据库号段模式的优缺点:
- 优点 :ID 有序递增、存储消耗空间小
- 缺点 :存在数据库单点问题(可以使用数据库集群解决,不过增加了复杂度)、ID 没有具体业务含义、安全问题(比如根据订单 ID 的递增规律就能推算出每天的订单量,商业机密啊! )
非结构型数据库
Redis
一般情况下,NoSQL 方案使用 Redis 多一些。我们通过 Redis 的 incr
命令即可实现对 id 原子顺序递增。
127.0.0.1:6379> set sequence_id_biz_type 1
127.0.0.1:6379> incr sequence_id_biz_type
(integer) 2
127.0.0.1:6379> get sequence_id_biz_type
"2"
为了提高可用性和并发,我们可以使用 Redis Cluster。Redis Cluster 是 Redis 官方提供的 Redis 集群解决方案(3.0+版本)。
除了 Redis Cluster 之外,你也可以使用开源的 Redis 集群方案Codisopen in new window (大规模集群比如上百个节点的时候比较推荐)。
除了高可用和并发之外,我们知道 Redis 基于内存,我们需要持久化数据,避免重启机器或者机器故障后数据丢失。Redis 支持两种不同的持久化方式:快照(snapshotting,RDB)、只追加文件(append-only file, AOF)。 并且,Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble
开启)。
关于 Redis 持久化,我这里就不过多介绍。不了解这部分内容的小伙伴,可以看看 JavaGuide 对于 Redis 知识点的总结open in new window。
Redis 方案的优缺点:
- 优点 : 性能不错并且生成的 ID 是有序递增的
- 缺点 : 和数据库主键自增方案的缺点类似
除了 Redis 之外,MongoDB ObjectId 经常也会被拿来当做分布式 ID 的解决方案。
MongoDB ObjectId 一共需要 12 个字节存储:
- 0~3:时间戳
- 3~6: 代表机器 ID
- 7~8:机器进程 ID
- 9~11 :自增值
MongoDB 方案的优缺点:
- 优点 : 性能不错并且生成的 ID 是有序递增的
- 缺点 : 需要解决重复 ID 问题(当机器时间不对的情况下,可能导致会产生重复 ID) 、有安全性问题(ID 生成有规律性)
JavaGuide 阅读笔记