Go开源项目分布式唯一ID生成系统

作者:yongxinz 时间:2024-02-14 22:08:15 

前言

今天跟大家介绍一个开源项目:id-maker,主要功能是用来在分布式环境下生成唯一 ID。上周停更了一周,也是用来开发和测试这个项目的相关代码。

美团有一个开源项目叫 Leaf,使用 Java 开发。本项目就是在此思路的基础上,使用 Go 开发实现的。

项目整体代码量并不多,不管是想要在实际生产环境中使用,还是想找个项目练手,我觉得都是一个不错的选择。

项目背景

在大部分系统中,全局唯一 ID 都是一个强需求。比如快递,外卖,电影等,都需要生成唯一 ID 来保证单号唯一。

那业务系统对 ID 号的要求有哪些呢?

  • 全局唯一性:不能出现重复的 ID 号,既然是唯一标识,这是最基本的要求。

  • 趋势递增:在 MySQL InnoDB 引擎中使用的是聚集索引,由于多数 RDBMS 使用 B-tree 的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。

  • 单调递增:保证下一个 ID 一定大于上一个 ID,例如事务版本号、IM 增量消息、排序等特殊需求。

  • 信息安全:如果 ID 是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定 URL 即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要 ID 无规则、不规则。

在此背景下,有一个高可用的唯一 ID 生成系统就很重要了。

项目使用

生成 ID 分两种方式:

  • 根据数据库生成 ID。

  • 根据雪花算法生成 ID。

使用上提供两种方式来调用接口:

  • HTTP 方式

  • gRPC 方式

HTTP 方式

1、健康检查:

curl http://127.0.0.1:8080/ping

2、获取 ID:

获取 tag 是 test 的 ID:

curl http://127.0.0.1:8080/v1/id/test

3、获取雪花 ID:

curl http://127.0.0.1:8080/v1/snowid

gRPC 方式

1、获取 ID:

grpcurl -plaintext -d '{"tag":"test"}' -import-path $HOME/src/id-maker/internal/controller/rpc/proto -proto segment.proto localhost:50051 proto.Gid/GetId

2、获取雪花 ID:

grpcurl -plaintext -import-path $HOME/src/id-maker/internal/controller/rpc/proto -proto segment.proto localhost:50051 proto.Gid/GetSnowId

本地开发

# Run MySQL
$ make compose-up

# Run app with migrations
$ make run

项目架构

项目使用 go-clean-template 架构模板开发,目录结构如下:

Go开源项目分布式唯一ID生成系统

下面对各目录做一个简要说明:

  • cmd:程序入口

  • config:配置文件

  • docs:生成的项目文档

  • integration-test:整合测试

  • internal:业务代码

  • pkg:一些调用的包

借用官方的两张图:

Go开源项目分布式唯一ID生成系统

整体的层次关系是这样的,最里面是 models,定义我们的表结构,然后中间是业务逻辑层,业务逻辑层会提供接口,给最外层的 API 来调用,最外层就是一些工具和调用入口。

这样做的最大好处就是解耦,不管最外层如何变化,只要在业务逻辑层实现对应接口即可,核心代码可能根本不需要改变。

所以,它们之间的调用关系看起来是这样的:

Go开源项目分布式唯一ID生成系统

HTTP > usecase
       usecase > repository (Postgres)
       usecase < repository (Postgres)
HTTP < usecase

项目地址:https://github.com/yongxinz/id-maker

往期文章:

听说,99% 的 Go 程序员都被 defer 坑过

测试小姐姐问我 gRPC 怎么用,我直接把这篇文章甩给了她

gRPC,爆赞

使用 grpcurl 通过命令行访问 gRPC 服务

推荐三个实用的 Go 开发工具

标签:Go,分布式,唯一ID,生成
0
投稿

猜你喜欢

  • 监控 url fragment变化的js代码

    2023-08-25 10:20:58
  • php从文件夹随机读取文件的方法

    2023-11-21 16:38:35
  • pandas 实现某一列分组,其他列合并成list

    2022-06-12 13:49:21
  • OpenCV目标检测Meanshif和Camshift算法解析

    2022-06-15 21:30:35
  • Python中用pyinstaller打包时的图标问题及解决方法

    2021-11-10 01:41:33
  • python-docx 页面设置详解

    2021-12-06 03:42:02
  • MySQL百万级数据量分页查询方法及其优化建议

    2024-01-17 20:56:11
  • 解决Pycharm运行时找不到文件的问题

    2023-06-15 00:26:39
  • 每个程序员都应该学习使用Python或Ruby

    2023-09-05 06:03:52
  • MySQL安全问题的一点心得

    2009-01-07 16:13:00
  • Entity Framework Core生成数据库表

    2024-01-15 18:09:29
  • Python3.4学习笔记之列表、数组操作示例

    2021-04-10 10:56:11
  • 详解webpack编译速度提升之DllPlugin

    2024-02-23 20:57:10
  • Python字符串hashlib加密模块使用案例

    2023-08-02 12:06:24
  • python爬取淘宝商品详情页数据

    2021-05-28 14:38:08
  • Golang空结构体struct{}用途,你知道吗

    2024-04-26 17:36:56
  • asp如何写入超长的字符串?

    2010-06-09 18:53:00
  • MySQL中UNION与UNION ALL的基本使用方法

    2024-01-25 21:34:03
  • GoLang channel关闭状态相关操作详解

    2024-04-26 17:26:52
  • 结合Python的SimpleHTTPServer源码来解析socket通信

    2021-09-05 23:30:27
  • asp之家 网络编程 m.aspxhome.com