基于Go实现的分布式主键系统

基于Go实现的分布式主键系统

摘要

随着互联网的发展,微服务得到了快速的发展,在微服务架构下,分布式主键开始变得越来越重要。目前分布式主键的实现方式颇多,有基于数据库自增的、基于UUID的、基于Redis自增的、基于数据库号段的。与此同时,越来越多的公司开始普及使用雪花算法,但是在使用的过程中,发现了雪花算法的一些问题:其一、雪花算法存在时间回拨问题;其二、雪花算法存在重复问题;其三、雪花算法不能覆盖所有的使用场景。基于现有的问题,本文开发了分布式主键系统,该系统可以解决以上问题。

1 各分布式主键介绍

1.1 雪花算法

在当前,最受欢迎的分布式主键生成算法是雪花算法,该算法由64位二进制数组成,如下图所示,它通过组合不同的二进制位来生成唯一的主键。

雪花算法生成64位的唯一ID,其中包括一个固定的符号位,41位时间戳(毫秒级),10位机器标识,以及12位序列号。这保证了ID的递增性和分布式环境下的无冲突性。然而,算法的局限性在于最多支持1024个节点,且时钟回拨可能造成ID重复,这些问题在大型分布式系统中尤为突出。因此,有需求去优化现有的算法,以适应更多节点并解决时钟同步和机器标识分配问题。

1.2 基于Redis的分布式主键

Redis的命令是单线程执行的,因此可以多个服务调用递增命令而不会产生重复主键的问题,通过这种方式,程序可以确保系统在分布式环境中生成全局唯一且连续的主键。

1.3 基于MySQL的分布式主键

采用MySQL数据库的号段模式可以满足生成主键的唯一性需求,该模式将数据段分配给特定节点,其他节点无法使用,因此,号段模式能够保证数据的唯一性,实现分布式环境下的主键生成。

1.4 基于新雪花算法的分布式主键

为克服雪花算法的时间回拨和机器号重复问题,新设计的分布式主键算法依然保持64位结构,但布局调整为:最高位废弃,47位用于自增确保递增性,后面16位分为两部分各8位,用于生成随机数以增加随机性。此设计放弃了机器标识,47位自增数字通过Redis或Etcd等中间件实现,并在本地缓存,确保全局唯一且提升系统稳定性与性能。

这种设计考虑了分布式环境的因素,因为在多台机器同时部署的情况下,可以借助第三方组件构建分布式系统,本文采用了与Redis的结合方式,并利用本地缓存,极大地提高了主键的生成速率。

2 分布式主键系统

2.1 涉及技术

HTTP服务端、GRPC、Protobuf、Redis操作、MySQL操作、分布式ID算法、多租户、Etcd操作

2.2 如何快速跑起来

2.2.1 配置相关
位置 内容
/conf/db/ddl.sql SQL脚本
/etc/*.yml 配置文件
2.2.2 项目入口
位置 内容
/guid.go 项目启动入口
/server/server.go 服务入口
/server/gin_server.go gin服务入口
/service/impl/db_serviceImpl.go 数据库分布式主键实现
/service/impl/redis_serviceImpl.go redis分布式主键实现
/service/impl/snow_serviceImpl.go 雪花算法分布式主键实现
/service/impl/new_show_serviceimpl.go 基于新雪花算法分布式主键实现
2.2.3 操作步骤

从gitlab拉下来项目

goland打开项目主目录 进入terminal

执行 go mod tidy

执行 go mod vendor

安装mysql,执行ddl

安装redis和etcd

执行go run guid.go

2.3 项目设计

2.3.1 总体设计

全局唯一键,主流的实现方式有四种:

1,基于数据库的号段模式;

2,基于redis的自增模式;

3,基于雪花算法的实现模式;

4,基于新雪花算法的实现模式;

本项目实现四种方式的全局唯一键,支持集群化部署,可扩展性高

想使用某种唯一键,只需要指定类型就行,唯一键按租户和应用维度隔离

2.3.2详细设计
  • 类图

  • grpc设计

protobuf 复制代码
syntax = "proto3";

option go_package = "gitee.com/liyouqing/guid/pb/guid;guid";

message Req{
  string namespace = 1;   // 命名空间
  TYPE type = 2;          // key的类别
  enum TYPE{              // 主键类型
    SNOW = 0;
    REDIS = 1;
    DB = 2;
    NEWSHOW = 3;
  }
}

message Res{
  bool  flag =1 ;    //成功失败标志
  string key = 2;    //返回的全局id实体
}


service PbGuid{
  rpc GetKey(Req) returns (Res);
}
  • 释义:

使用protobuf 定义两个message 一个请求,一个返回

使用grpc定义了一个服务,服务的中有一个方法,使用上述定义的请求和返回作为入参和出参

2.3.3 rpc远程调用

go项目需要该功能时,需要拿到该proto的文件

然后,通过命令生成相关结构体和grpc调用相关的东西

然后参考

/server/server_client_test.go

2.3.4 gin服务 restapi调用

通过 gin服务 添加http查询接口

url localhost:8080/gitee.com/liyouqing/guid/get-key?namespace=nihao&type=2 请求方式 Get

请求参数 type 0:雪花算法 1:redis分布式 2:数据库号段 3:新雪花算法

返回数据

json 复制代码
{
    "status":0,
    "msg":"success",
    "data": "70001"
}

3 对比试验结果

算法 耗时(十万条) 速度 重复次数 随机性 自增趋势
雪花算法 12.47秒 3
优化的雪花算法 12.46秒 0
基于Redis的主键生成算法 21.50秒 0
基于MySQL的主键生成算法 11.86秒 0
新雪花算法 12.22秒 0

4 总结

本人进行了大量工作,优化了雪花算法,解决了性能和可靠性问题,还实现了基于数据库和缓存的两种分布式主键生成算法。通过对比实验发现,这些算法都有各自的优势和适用领域。最后,基于这些算法开发了分布式主键系统,提升了数据写入能力和稳定性,避免了重复主键的产生,具有极高的现实价值。

5 附录

gitee项目地址

集成grpc的操作可以参考 go集成grpc

Mysql、Redis、Etcd的安装自行百度,在此不再赘述!!

相关推荐
极客先躯7 分钟前
高级java每日一道面试题-2024年10月3日-分布式篇-分布式系统中的容错策略都有哪些?
java·分布式·版本控制·共识算法·超时重试·心跳检测·容错策略
niu_sama37 分钟前
仿RabbitMQ实现消息队列三种主题的调试及源码
分布式·rabbitmq
鸡c43 分钟前
rabbitMq------客户端模块
分布式·rabbitmq·ruby
Dylanioucn2 小时前
【分布式微服务云原生】探索Redis:数据结构的艺术与科学
数据结构·redis·分布式·缓存·中间件
路上^_^2 小时前
00_概览_kafka
分布式·kafka
极客先躯9 小时前
Hadoop krb5.conf 配置详解
大数据·hadoop·分布式·kerberos·krb5.conf·认证系统
CopyLower10 小时前
Kafka 消费者状态及高水位(High Watermark)详解
分布式·kafka
__AtYou__10 小时前
Golang | Leetcode Golang题解之第448题找到所有数组中消失的数字
leetcode·golang·题解
2301_7869643611 小时前
3、练习常用的HBase Shell命令+HBase 常用的Java API 及应用实例
java·大数据·数据库·分布式·hbase
千年死缓12 小时前
go+redis基于tcp实现聊天室
redis·tcp/ip·golang