SaaS 电商设计 (六) 实现 id 生成器本地化生产 (附源码)

一.背景

1.1 背景

  • 业务背景:

目前梳理 SaaS 系统中存在以下几种 Id 生成的场景.

财务系统: 财务在生产财务单的时候,获取财务单 Id ,满足分布式场景下能够获取全局Id即可.

支付系统:订单系统在进行外部提单过程中,需要将生成的订单号与外部的支付平台做对接.在具体开发调试过程中出现这种情况.客户需要支持私有化交付.我们在 SaaS 的开发环境部署联调时,已经与外部的支付平台进行了对接.完成联调结束后.在客户的私有化环境中再次进行测试回归出现了,出现了因为订单号重复导致了支付失败的场景.

商品系统: 商品系统在生产具体的Id形式上有几种业务侧的诉求.

场景具体逻辑示例
SPUIdSPUId生产支持固定位数(可配),起始值(可配)的自增流水Id
类目Id类目Id .支持固定前缀(可配).流水固定位数(可配)的流水自增固定前缀Ca.流水固定位数(6),Ca000001,Ca000002
  • 技术背景:

     现有 SaaS 的不同系统中存在不同的 Id 生产的逻辑和服务,大概可以分为两种方案.

在这里插入图片描述

  • 第一种:基于中心化的 Id 服务来获得.
  • 第二种:基于本地化的 Id 数据库来生产.
    结合目前的 SaaS系统 会有私有化部署的场景,那就是需要去考虑部署成本的因素.且目前的中心化方案可能带来的单点故障问题.基于以上的一个背景

1.2 目标

  • 支持分布式全局
  • 支持私有化部署独立部署
  • 支持自定义规则 Id 生产
  • 性能目标:单机4c8g下 1000 qps 目标

二.技术方案

2.1 技术调研对比

常见方案优势对比目标后的缺点
UUID使用简单,支持分布式场景,理论上存在碰撞可能(几率极低)分布式支持;独立部署支持;不支持自定义规则;最重要的原因是利用UUID作为分布式数据库业务Id的场景下,由于B+树作为底层的数据结构会带来大量的页分裂和反复的插入以及翻转,并以此带来的大量性能损耗
雪花算法支持分布式;性能优秀依赖物理机时钟,时钟回拨回带来碰撞问题;不支持自定义规则;
Redis支持分布式;性能优秀;额外的Redis服务成本,不支持自定义规则
ZK支持分布式;额外的ZK服务成本;不支持自定义规则

2.2 结合现有业务的最终选择

    抛开业务场景的下的技术方案设计都是刷流氓.基于目前咱们的技术目标.选用了一个基于数据库(不额外支出其他资源)的且支持自定义规则的设计方案.

- 支持分布式全局
- 支持私有化部署独立部署
- 支持自定义规则 **Id** 生产
- 性能目标:单机4c8g下 1000 **qps** 目标

三.详细设计

3.1 方案流程

3.1.1 配置初始化

3.1.2 生产 Id 流程

3.2 类图

在这里插入图片描述

  • IdAutoBootConfig

  • spring.factories 入口方法

  • 能力1:用以保证引入的业务方能够自动扫描本身的包体,扫描对应的bean到spring container

  • 能力2:用以扫描对应的 mybatis mapper 注入动态代理

  • IdGenerator 用以外漏 id 的生产接口.
    方法1:生成全局id generatorGlobalId(String name) tenantId =9527
    方法2:生成租户级别全局唯一generatorGlobalId(long tenantId,String name);

  • IdGeneratorImpl 具体方法生成的实现类.
    内部持有持有上下文中具体的Sequence name 与 SequenceValue 的映射的读写操作.

核心读写锁分离处理具体流程(方便理解可能与上图部分有重复).

在这里插入图片描述

  • InitSequenceConfigWare& SequenceStepContextHolder
    InitSequenceConfigWare 通过实现 InitializingBean扩展点 完成容器启动后(本质是利用容器启动完成,数据源完成注入)来实现数据库Sequence 读取得到 SequenceConfigModel .通过 SequenceStepContextHolder 维护 sequenceName 与 SequenceValue的映射关系.为了减少 内存占用.将SequenceConfigModel简化一部分得到 SequenceValue 进而维护到 SequenceStepContextHolder 持有的 ALL_SEQUENCE_CONTEXT 中.

3.3 DB设计

code rule 表(非必选)本期没有实现后续可以持续在这个表进行扩展得到更加灵活的SequenceId表达.

CREATE TABLE `code_rule` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `tenant_id` bigint(20) NOT NULL COMMENT '租户id',
  `biz_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '业务:1-商品编码规则,2-类目编码规则,参见BizTypeEnum',
  `rule_key` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1-流水自增,2-租户自定义,3-类目编号和流水自增,参见RuleKeyEnum',
  `rule_value` varchar(256) NOT NULL COMMENT '编码规则描述json格式',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '数据中心抽数专用字段,无业务含义',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_tid_type` (`tenant_id`,`biz_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='编码规则表';

/**
* **sequence** 表。必选表。本期先实现需要业务方自行创建**ddl**维护到对应数据源中.
*/
CREATE TABLE `sequence` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '当前序列最大值',
  `tenant_id` bigint(20) NOT NULL COMMENT '租户id',
  `name` varchar(200) NOT NULL COMMENT '序列名称',
  `start` bigint(20) NOT NULL COMMENT '开始值',
  `end` bigint(20) NOT NULL COMMENT '结束值',
  `step_size` bigint(20) DEFAULT NULL COMMENT 'id号段数量',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='序列号表';

3.4 no more talking 一键开箱

详见:github https://github.com/Baixiu-code/id-generate-starter

3.5 多线程并发测试验证

本着面向TDD的原则,也开放了多线程版本的自测演示.

场景:
启动1000个线程同时并发请求获取生产Id

脚本准备:

insert into sequence (tenant_id,name,start,end,step_size,create_time,update_time) values ('9527','product','0','0','2',now(),now());

这里的 stepSize 设为2 ,尽量去触发临界值得到更新数据库的条件,来模拟现实场景的情况.实际场景中可能stepSize 可能非常大.大多数都是内存级别的读取行为,很少触动数据库的更新.

验证方案:

验证获取的Id是否重复,本方案通过 put IdConcurrentHashMap , map 能够自动去重. 最后通过countDownLatch阻塞主线程,获取 ConcurrentHashMapsize 是否为1000,来得到是否满足并发场景下的生产Id诉求.

在这里插入图片描述

https://github.com/Baixiu-code/id-generate-starter-test

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/310542.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

400μA低功率接地故障断路器控制芯片D4147,内置精密感应放大器与带隙基准,适用于GFCI和RCD

低功率接地故障断路器(GFI)控制芯片D4147主要用于三线制GFCI输出接口、GFCI芯片断路器、便携式GFCI线路等领域的产品,侦测并防护火线对地故障和零线对负载短路故障。 功能介绍 D4147为低功率接地故障断路器(GFI)控制…

Zookeeper 和 naocs的区别

Nacos 和 ZooKeeper 都是服务发现和配置管理的工具,它们的主要区别如下:功能特性:Nacos 比 ZooKeeper 更加强大,Nacos 支持服务发现、动态配置、流量管理、服务治理、分布式事务等功能,而 ZooKeeper 主要用于分布式协调…

RK3568驱动指南|第十篇 热插拔-第117章uevent_helper实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…

python json模块

json是JavaScript对象表示法的缩写,是一种轻量级的数据交换格式,经常被用于Web应用程序中。python中的json库是用于解析和生成json数据格式的库。 import jsondata {"name": "张三","age": 18,"hobbies": [&q…

Unity报错:[SteamVR] Not Initialized (109)的解决方法

问题描述 使用HTC vive 头像进行SteamVR插件的示例场景进行测试,发现头显场景无法跳转到运行场景(Unity 项目可以运行,仅出现警告)。 具体如下: [SteamVR] Not Initialized (109) [SteamVR] Initialization failed…

python 基础知识点(蓝桥杯python科目个人复习计划20)

今日复习内容:基础算法中的选择排序/插入排序/快速排序/归并排序/桶排序 一.选择排序 1.算法步骤 从左往右找到最小的元素,放在起始位置重复上述步骤,依次找到第二,第三小的元素 2.具体描述 给定一个长度为n的列表&#xff0…

[VisualStudioCode]_[VSCODE]_[C/C++开发环境配置-问题解决和补充]

场景 在使用VSCode配置C的开发环境时《VisualStudioCode_C/C开发环境配置[1]》,编译时会发现找不到标准库的std::mutex和std::thread的声明,而这两个的头文件已经引入,什么情况? 无论如何MinGW都是Windows上验证开发C特性比较新的…

Python从入门到网络爬虫(控制语句详解)

前言 做任何事情都要遵循一定的原则。例如,到图书馆去借书,就需要有借书证,并且借书证不能过期,这两个条件缺一不可。程序设计亦是如此,需要使用流程控制实现与用户的交流,并根据用户需求决定程序“做什么…

运用AI搭建中间服务层(一)

知识点 适用于 AI 的 Visual Studio 工具 微软认知服务(影像服务/实体搜索服务)的使用 商业应用软件的架构设计 ASP.NET 核心 Web 应用程序 休息 应用程序接口 服务端的测试技术 软件工程中的需求演进处理 不断演进的应用场景 下面我们会用讲故…

PR-视频去水印

文章目录 前言PR-视频去水印实现示例 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!! PR-视频…

Unity组件开发--短连接HTTP

1.网络请求管理器 using LitJson; using Cysharp.Threading.Tasks; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Events;using System.Web; using System.Text; using Sy…

企业的 Android 移动设备管理 (MDM) 解决方案

移动设备管理可帮助您在不影响最终用户体验的情况下,通过无线方式管理和保护组织的移动设备群,现代 MDM 解决方案还可以控制 App、内容和安全性,因此员工可以毫无顾虑地在托管设备上工作。移动设备管理软件可有效管理个人设备上的公司空间。M…

刷题第十五天-存在重复元素Ⅲ

存在重复元素Ⅲ 题目要求 解题思路 主要使用滑动窗口方法,让滑动窗口代销固定为t。 本题最大的难点在于快速地找到滑动窗口内的最大值和最小值,以及删除指定元素。 如果遍历求滑动窗口内的最大值和最小值,时间复杂度是O(K&#…

自动化测试框架搭建全过程

前段时间写了一系列自动化测试相关的文章,当然更多的是方法和解决问题的思路角度去阐述我的一些观点。这篇文章来聊聊新手如何从零到一落地实践接口自动化测试。 为什么要做接口测试 测试理念的演变 早些时候,软件研发交付流程大多遵循V型或W型的瀑布模…

vue 公众号开发,调用jssdk封装

vue 公众号开发,经常会使用到 转发朋友,朋友圈,调用扫一扫等功能,这时就要使用微信的 jssdk 微信jssdk传送门 1. 安装jssdk 插件 (jweixin-module) npm install jweixin-module --save 2. 封装方法 utils/jwx.js let jweixin…

Hello,World!

“Hello, world”的由来可以追溯到 The C Programming Language 。在这门编程语言中,它被用作第一个演示程序,向人们展示了在计算机屏幕上输出“Hello world”这行字符串的计算机程序。由于这个演示程序的简洁性和直观性,它成为了许多初学者学…

qt图形化界面开发DAY3

作业: 1> 思维导图 2> 完善对话框,点击登录对话框,如果账号和密码匹配,则弹出信息对话框,给出提示”登录成功“,提供一个Ok按钮,用户点击Ok后,关闭登录界面,跳转…

Android 输入系统介绍

文章目录 一、目的二、环境三、相关概念3.1 输入设备3.2 UEVENT机制3.3 JNI3.4 EPOLL机制3.5 INotify 四、详细设计4.1 结构图4.2 代码结构4.3 InputManagerService模块4.3.1 IMS服务入口4.3.2 IMS初始化4.3.3 IMS启动4.3.4 IMS消息监听 4.4 NativeInputManager模块4.4.1 nativ…

解决Windows 11/10共享打印机无法连接问题0x00000709错误

在解决共享打印机连接问题之前,请确保满足以下几个条件: 确保Windows 11设备和共享打印机的电脑连接到同一个网络。检查网络连接是否稳定。确保共享打印机所连接的计算机处于开机状态。检查共享设置,确保共享打印机在Windows 7计算机上正确设…

Docker安装Nacos2.2.3并鉴权、Prometheus监听Nacos、Grafana监控Nacos【亲测可用】

1、Docker 拉取镜像:docker pull nacos/nacos-server:v2.2.3 2、docker run --env MODEstandalone --name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 nacos/nacos-server:v2.2.3 3、复制镜像中的配置文件 mkdir -vp /home/nacos/logs mkdir -vp /home/n…