分布式全局唯一ID
1、什么是分布式全局唯一ID?为什么需要分布式全局唯一ID?
分布式全局唯一ID,主要体现在分布式微服务中或者是体现在分库分表的架构中。
分布式微服务表现:在整个的项目架构中,可能会存在多个模块,比如:多个订单模块、多个用户模块、多个支付模块,作为分布式微服务,各个模块都是存在不同的服务器上的,如何保证各个模块之间的数据是全局唯一的,就需要使用分布式全局唯一ID解决。
分库分表表现:主要体现在对于但数据库而言,数据量很大,需要对数据进行分库分表,如果进行分库分表的话,不同的库与不同的表之间的数据,如果使用自增实现唯一,那也只能保证在单个数据库中是唯一的,但是在多数据库中就是不唯一的,所以需要分布式唯一ID。
2、分布式唯一ID解决方案?
-
第一,使用数据库自增。
刚才已经说过了,在分库分表中使用数据库的主键自增是不能实现全局唯一ID的,但是,为什么还需要提到数据库自增呢?
如图,现在分库分表,形成了两个数据库,每一个数据库有两个表,一共形成四张表,那么,在添加数据库的时候,不管谁的先后顺序,对每一个数据库每一次自增递加所有数据表的数量,这样,就能保证全局唯一,即使有个别的数据库宕机,也能保证数据库数据唯一。
缺点:对于扩展数据库来说,是非常不友好的。
-
第二,使用UUID。
UUID是java中内置的产生随机数的一个方法,并且也是唯一的,但是不推荐使用这个方法,因为这个方法生成的随机数包含数据和字母,并且无序,用它来作为主键索引,对于数据库数据的查找没有有序的索引效率高,再加上,UUID对于空间的使用也是很大的。
-
第三,使用Redis自增。
Redis实现数据的递增,使用incr命令实现,对于Redis这种基于内存的NoSql数据库,效率是很高的,并且也是全局唯一的,但是,这个方法过于依赖Redis,并且,对于系统来说与Redis是需要交互获取这个全局唯一ID的,若出现网络不好,就会影响效率。
-
第四,使用雪花算法。
3、了解雪花算法
雪花算法,之所以叫雪花算法是因为,就像是天空下雪花一样,在同一秒中,可以下很多的雪花,也体现了他的效率。雪花算法,占用空间8个字节,一共64位。
-
第一部分,占一位。表示数据的正负。
-
第二部分,占41位。表示时间戳。
-
第三部分,占10位。表示最多可以部署多少台机器。1024台
-
第四部分,占12位。表示序列号。
雪花算法之所以能做到全局唯一是因为他的核心是使用当前的时间戳作为ID,时间戳是唯一的,并且在产生时间戳的时候,nextId()底层采用了synchronized关键字修饰表示其是一个同步方法。就更加保证了其唯一性。
4、雪花算法的基本使用
//引入工具类库 <!-- 分布式全局唯一ID 是哦也能够HuTool工具 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.13</version> </dependency>
public void HuTool_Simple_Use() { /** * 实现一:简单使用 * 分布式全局唯一ID,也能够IdUtil.getSnowflake()方法得到雪花算法 * 该方法内部使用了synchronized关键字修饰,保证了同步实现。 */ Snowflake snowflake = IdUtil.getSnowflake(); System.out.println(snowflake.nextId()); System.out.println(snowflake.nextId()); System.out.println(snowflake.nextId()); System.out.println(snowflake.nextId()); }
5、雪花算法结合Mybatis-Plus实现全局唯一
<!-- mysql driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.0</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> </dependency> <!-- web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>第二,数据库建表
CREATE TABLE `t_users` ( `userid` bigint(20) NOT NULL, `username` varchar(22) DEFAULT NULL, `userage` int(11) DEFAULT NULL, PRIMARY KEY (`userid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;第三,编写三层架构
//Controller层 @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @RequestMapping("/simple") public void HuTool_Simple_Use() { /** * 实现一:简单使用 * 分布式全局唯一ID,也能够IdUtil.getSnowflake()方法得到雪花算法 * 该方法内部使用了synchronized关键字修饰,保证了同步实现。 */ Snowflake snowflake = IdUtil.getSnowflake(); System.out.println(snowflake.nextId()); System.out.println(snowflake.nextId()); System.out.println(snowflake.nextId()); System.out.println(snowflake.nextId()); } @RequestMapping("/addUser") public String HuTool_Mybatis_Plus() { /** * 实现二:与mybatis-plus结合使用 * 需求:添加一个用户,用户的主键,开发人员不需要编写,有HuTool工具自动生成 */ Users users = new Users(); users.setUsername("惠豆"); users.setUserage(13); Integer integer = userService.addUser(users); return "添加用户成功!"; } }
//Service层 @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; // 添加用户 public Integer addUser(Users users) { return userMapper.insert(users); } }
//Mapper层 @Repository public interface UserMapper extends BaseMapper<Users> { }
//POJO层 @Data @TableName(value = "t_users") public class Users { /** * TableId注解表示其是一个主键 * ASSIGN_ID 表示的是雪花算法 */ @TableId(type = IdType.ASSIGN_ID) private Long userid; private String username; private Integer userage; }
application.yml配置文件 spring: datasource: url: jdbc:mysql://localhost:3306/school username: root password: root
//主启动类 /** * @Description: 分布式全局唯一ID 使用HuTool工具 * @Author: huidou 惠豆 * @CreateTime: 2022/6/10 14:45 */ @SpringBootApplication @MapperScan(value = "com.hui.mapper") @Slf4j public class UniqueID { public static void main(String[] args) { SpringApplication.run(UniqueID.class,args); log.info("############# 启动成功 #############"); } }在结合mybatis-plus中,在添加用户的时候,根本就不需要开发者自己编写用户ID,只需要在实体类上标注主键,并且标注主键的类型是使用雪花算法,如下:
@TableId(type = IdType.ASSIGN_ID) private Long userid;