获取全局唯一标识的方法介绍
在一个IT系统中,获取一个对象的唯一标识符是一个普遍的需求。在以前的单体应用中,如果数据库是一个单数据库的结构。通常可以利用数据库的自增字段来获取这个唯一标识。
例如,在 Mysql 数据库中,我们可以通过 sql 语句创建一个自增长的 int 字段类型的表。如下所示
CREATE TABLE student
(
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(16),
PRIMARY KEY (id)
)
然后插入两条数据
INSERT INTO student(name) VALUE('yanggch');
INSERT INTO student(name) VALUE('grace');
通过 SQL 语句查看表数据
SELECT * FROM student;
得到如下的结果
可以看到,虽然我们在通过 SQL 插入数据的时候没有指定 id 字段的值,但是因为该字段的 AUTO_INCREMENT 自增长的特性,自动的给两条记录添加了1和2两个值。
这个方法有两个主要问题。一个是如果是一个分库分表的数据库结构,那么在分布在不同实例中的同一个表中的id是重复的。另一个问题是记录插入到数据库里后,我们在代码中并不能知道刚刚插入数据库的记录的主键的值到底是什么。如果我们的一个业务是要同时插入一条主表记录一节一系列以这条主表记录主键为外键的子表记录,我们在插入子表记录的时候,不知道对应的外键的值是多少。导致无法插入。例如如果我们有一个下单业务,要求在订单表中插入一条订单记录,同时在订单明细中插入多条在这个订单中购买的商品的详细信息的记录。订单数据插入成功后,我们不知道订单的主键的值,所以我们也就无法正确的插入商品详细信息记录了。
另外一个利用数据库自增字段属性获取唯一标识方式是在数据库中建立一个带一个自增字段的数据表。每次在表中插入一条记录,然后将这条记录的值取出来作为主键值。这个的问题是每次要另外在数据表中插入一条记录,同时在多用户使用的环境下,要严格保证你取到的记录就是你插入的记录。否则会导致主键重复。着会让获取唯一标识符的速度变得比较慢。同时,这个方式在分库分表的结构下,也不能让唯一标识在全局唯一。
还有一些其他的方式。例如用 uuid 算法可以保证全局唯一,也能保证高性能。但是他生成是一个字符串,不能保证顺序性,同时也太长了。
所以在分布式架构中,我们就需要一个满足如下条件的唯一标识符服务
-
全局唯一
-
高性能
-
具备顺序性
-
可以附加其他业务属性
这里我们可以用 redis 的 INCR 命令来作为生成全局的唯一标识符。INCR 命令的语法是
INCR key
根据 redis 的官网的 INCR 命令介绍,它是一个原子操作,效果是是将 redis 数据库中 key 的值加一并且返回这个结果。如果 key