Lisheng Xie - Blog - 未分类 2026-05-14T09:23:00+08:00 Typecho https://www.lishengxie.top/index.php/feed/atom/category/uncategorized/ <![CDATA[分布式ID生成方案全解析:从数据库到雪花算法]]> https://www.lishengxie.top/index.php/archives/211/ 2026-05-14T09:23:00+08:00 2026-05-14T09:23:00+08:00 lishengxie https://www.lishengxie.top/

分布式ID生成方案全解析:从数据库到雪花算法

在分布式系统中,全局唯一ID是一个常见的需求。无论是分库分表后的主键冲突,还是订单号、用户ID等需要唯一标识的场景,都离不开一个可靠的分布式ID生成器。本文将带你了解分布式ID的基本要求,并梳理多种实现方案,从简单的数据库自增到高性能的雪花算法,最后介绍各大厂的开源组件。

一、什么是分布式ID?

分布式ID是指在分布式环境下生成的全局唯一标识符。典型应用场景包括:

  • 分库分表:数据量增长导致单库单表出现性能瓶颈时,分库分表后无法继续依赖数据库自增ID(会产生主键冲突),此时需要分布式ID保证全局唯一。
  • 业务标识:订单号、用户ID、消息ID等需要全局唯一的场景。

二、分布式ID的基本要求

一个合格的分布式ID生成器通常需要满足以下几点:

  1. 全局唯一:这是最基本的要求,ID必须在整个分布式系统中不重复。
  2. 独立部署、高性能、高可用:ID生成服务应独立部署,具备高并发下的低延迟响应能力(接近100%可用性),不能成为业务系统的瓶颈。
  3. 安全:ID中不应包含敏感信息,避免信息泄露。
  4. 趋势递增:尽可能保证ID趋势递增,这有利于数据库的索引插入和排序性能。

三、实现方案

分布式ID方案

1. 数据库方案

1.1 基于数据库自增ID

使用MySQL的自增主键来充当分布式ID。创建一张专门用于生成ID的表,每次插入一条记录后获取返回的主键ID。

CREATE DATABASE `SEQ_ID`;
CREATE TABLE SEQID.SEQUENCE_ID (
    id bigint(20) unsigned NOT NULL auto_increment, 
    value char(10) NOT NULL default '',
    PRIMARY KEY (id)
) ENGINE=MyISAM;

INSERT INTO SEQUENCE_ID(value) VALUES ('values');

优点:简单、天然有序。
缺点:单点故障风险、并发性能差、数据库写入压力大,且ID可反推出订单数量等敏感信息。

1.2 基于数据库集群模式

为解决单点故障,可以采用多主模式,部署多个MySQL实例独立生成自增ID。通过设置不同的起始值和步长避免重复(以两个节点为例):

-- MySQL实例1
set @@auto_increment_offset = 1;     -- 起始值
set @@auto_increment_increment = 2;  -- 步长

-- MySQL实例2
set @@auto_increment_offset = 2;     -- 起始值
set @@auto_increment_increment = 2;  -- 步长

优点:缓解单点并发压力。
缺点:不利于动态扩容,新增节点时需处理起始值冲突,甚至可能停机调整。

1.3 基于数据库号段模式

号段模式的核心思想是批量获取自增ID:每次从数据库取出一个ID范围(如(1,1000]),然后在内存中递增分配,用完后再去数据库获取新的号段。

表结构示例:

CREATE TABLE id_generator (
  id int(10) NOT NULL,
  max_id bigint(20) NOT NULL COMMENT '当前最大id',
  step int(20) NOT NULL COMMENT '号段的步长',
  biz_type int(20) NOT NULL COMMENT '业务类型',
  version int(20) NOT NULL COMMENT '版本号',
  PRIMARY KEY (`id`)
);

INSERT INTO `id_generator` (`id`, `max_id`, `step`, `version`, `biz_type`)
VALUES (1, 0, 100, 0, 101);

获取号段的操作:

-- 查询当前号段
SELECT `max_id`, `step`, `version` FROM `id_generator` WHERE `biz_type` = 101;

-- 更新并获取新号段(乐观锁)
UPDATE id_generator 
SET max_id = max_id + step, version = version + 1 
WHERE version = 0 AND `biz_type` = 101;

优点:相比每次获取都访问数据库,大幅减小数据库压力;即使数据库短暂故障,服务仍可使用已缓存的号段继续运行。
缺点:服务器重启或故障可能导致ID不连续。

优化扩展:可以将多主模式与号段模式结合,先为每个节点分配大区间(如节点1以10开头,节点2以11开头),再在每个节点内部使用号段批量获取。此外,引入双缓存机制(预加载下一个号段)可进一步提升性能。

2. 算法方案

2.1 UUID(通用唯一识别码)

Java中可通过UUID.randomUUID()生成,去掉连字符后得到一个32位随机字符串。

public static void main(String[] args) {
    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    System.out.println(uuid);
}

优点:实现简单、唯一性有保障。
缺点:不具备趋势递增(UUID v7版本已有所改善),导致数据库写入性能差、查询效率低;16字节的存储长度占用较大空间。

UUID的演进可以参考:UUID版本介绍

2.2 雪花算法(Snowflake)

Twitter开源的分布式ID生成算法,将64-bit(Java中用long类型存储)划分为多个部分:

1 bit(未使用)41 bit(毫秒时间戳)10 bit(机器ID)12 bit(序列号)

理论上一台机器在一个毫秒内可生成4096个不重复ID,且趋势递增。

优点:不依赖数据库等第三方系统,纯内存计算,性能极高;可根据业务需求灵活调整bit分配。
缺点强依赖机器时钟。若发生时钟回拨,可能产生重复ID或导致服务不可用(官方简单抛错处理,回拨期间服务暂停)。

更详细的介绍参考:雪花算法解析

2.3 薄雾算法

一种替代方案,详情可参考:薄雾算法介绍

3. 开源组件方案

3.1 Redis

利用Redis的INCR命令实现原子递增:

127.0.0.1:6379> set seq_id 1     # 初始化
OK
127.0.0.1:6379> incr seq_id      # 原子递增,返回新值
(integer) 2

需要注意持久化配置和极端情况下的ID重复问题。

3.2 Zookeeper

基于Zookeeper的znode数据版本号生成序列号(32位或64位),客户端可用作唯一ID。由于高度依赖Zookeeper且为同步API调用,高并发场景下性能不理想。

四、开源分布式ID组件推荐

组件公司地址
Tinyid滴滴https://github.com/didi/tinyid
UidGenerator百度https://github.com/baidu/uid-generator
Leaf美团https://github.com/Meituan-Dianping/Leaf
Seqsvr腾讯https://github.com/uidgen/seqsvr

延伸阅读

五、总结

选择分布式ID方案时,需要根据业务场景权衡性能、可用性、有序性、复杂度等因素:

  • 如果并发量不高且可接受单点风险,数据库自增或号段模式足够简单实用;
  • 追求高性能且能接受时钟回拨的小概率风险,雪花算法是经典选择;
  • 希望开箱即用并具备生产级高可用,大厂开源的Leaf、Tinyid等组件值得考虑。

没有完美的方案,只有最契合业务场景的选择。希望本文能帮助你理清分布式ID的设计思路,在实际项目中做出更合理的决策。

]]>
<![CDATA[站点迁移:腾讯云->阿里云]]> https://www.lishengxie.top/index.php/archives/180/ 2023-12-21T20:21:00+08:00 2023-12-21T20:21:00+08:00 lishengxie https://www.lishengxie.top/

站点迁移

之前使用的是云服务器是腾讯与的2核4G服务器,但是由于最开始购买时只买了一年,续费时价格太贵,因此转到阿里云,可以有四年每年99元的2核2G服务器可以白嫖~

迁移过程大概分为两步:站点数据迁移和站点备案迁移

数据迁移

博客迁移wordpress->typecho

原来的博客使用wordpress框架,但是wordpress框架功能齐全、有些臃肿,因此这里换成了更精简的typecho框架。

  1. typecho安装
    参考了知乎博客https://zhuanlan.zhihu.com/p/34211709
  2. 导出wordpress数据库并在新服务器中导入

  3. 数据迁移到typecho
    基于typecho插件:https://docs.typecho.org/plugins/wordpress-to-typecho
  4. 还原wordpress中的图片附件到typecho中

    • 将WordPress的wp-content/uploads目录下的附件全部移动到Typecho的usr/uploads目录下,保持目录结构不变。
    • 在mysql typecho对应数据库中执行以下代码以完成图片路径的替换:
     update typecho_contents set text=replace(text,'wp-content/uploads','usr/uploads')
     update typecho_contents set text=replace(text,'wordpree站点url','typecho站点url')
  5. typecho使用数学公式
    使用插件:https://github.com/yuzhongzhibi/typecho_mathjax_plugin
  6. typecho主题页面更改
    参考链接:https://www.skyqian.com/archives/typecho-pages.html
  7. typecho使用redis cache加速访问
    参考链接:https://www.shuyz.com/posts/use-typecho-redis-cache-to-speedup-typecho-blog/
    这里是使用了一个 php 的 redis 客户端,每次修改页面内容时要刷新 redis 缓存,通过在请求链接后添加如下参数实现:
  8. 清除页面缓存:?debug=true&userkey=&action=purgepage
  9. 清除整站缓存:?debug=true&userkey=&action=purgeall

docker容器迁移

做法是现在新服务器上安装docker,然后迁移旧服务器上的docker挂载文件夹到新服务器相同位置,最后在新服务器启动容器。参考链接:https://zhuanlan.zhihu.com/p/643367054
这里我主要使用了两个容器用于存储电子书和笔记

  1. Talebook:https://github.com/talebook/talebook
  2. leanote: https://www.bilibili.com/read/cv23693842/

站点备案迁移

为了方便使用,计划将域名和服务器都转移到阿里云。因为服务器需要在所在服务商处备案,因此还需要在阿里云备案,主要参考了这篇博客:https://www.zuozuovera.com/posts/1644/

]]>
<![CDATA[内网离线服务器使用]]> https://www.lishengxie.top/index.php/archives/149/ 2023-06-03T20:31:04+08:00 2023-06-03T20:31:04+08:00 lishengxie https://www.lishengxie.top/ 最近在跑实验时,自己的电脑出现内存不够用的问题,想到在实验室的一台闲置的服务器上运行程序。但是该服务器只能通过内网连接,无法使用外网,因此这里记录了内网离线服务器使用的一些经历。
可以考虑在服务器上安装docker,然后在自己电脑上配好环境后导出docker镜像到服务器上运行。这里没有使用docker环境,本地环境是WSL2-Ubuntu20.04。

程序运行环境配置

C++

针对C++程序,重新下载代码编译;

Python

重新配置Python环境主要经历了以下步骤:
1. 下载miniconda安装程序并安装;
2. WSL2环境迁移到服务器中,这里选择直接打包WSL2下面的虚拟环境目录并到服务器相应目录下解压,参考了教程https://blog.csdn.net/qq_45893319/article/details/122226053;
3. 直接打包的环境,无法使用pip的问题,可以通过修改pip文件解决,参考教程https://blog.csdn.net/qq_40933913/article/details/127907916
4. 环境迁移后发现在迁移的环境中无法使用clear命令,原因是迁移过来的环境中clear文件有问题。解决方案如下:

  • 在出错的环境下,输入which clear,然后将clear地址重命名,下次再clear时会生成新的。


    mv /home/xxx/.conda/envs/yolox/bin/clear /home/xxx/.conda/envs/yolox/bin/clear_old
    

vscode连接服务器开发

参考教程https://blog.csdn.net/ffriend/article/details/126680223
由于服务器离线,使用vscode连接时无法在远程服务器上下载vscode-server,这里需要手动下载一下。步骤如下
1. 查看本地vscode的commit id:帮助-关于,复制commit id
2. 本地下载vscode-server

wget https://update.code.visualstudio.com/commit:${commit_id}/server-linux-x64/stable
# 注意把:${commit_id}替换成对应的Commit ID
  1. 复制到服务器并安装
rm ~/.vscode-server/bin/* -rf  #把$HOME/.vscode-server/bin下的内容删干净,防止出错
cd ~/.vscode-server/bin
tar -zxf vscode-server-linux-x64.tar.gz
mv vscode-server-linux-x64 ${commit_id} # 注意把:${commit_id}替换成对应的Commit ID

服务器安装screen应用

参考教程https://blog.csdn.net/Demo_Null/article/details/110873673,主要是编译安装screen和ncurses两个可执行程序,这里需要管理员权限,负责无法安装到默认的安装位置。

screen常用命令如下

1、启动共享窗口:screen -S 名称
2、查看当前所有共享会话:screen -ls
3、进入共享会话:screen -r 名称
4、退出共享会话:ctrl +a +d

]]>
<![CDATA[Windows常见问题记录]]> https://www.lishengxie.top/index.php/archives/113/ 2023-04-03T17:19:10+08:00 2023-04-03T17:19:10+08:00 lishengxie https://www.lishengxie.top/

触摸板无法使用

在设置中选择“插入鼠标后禁用触摸板”选项后,将鼠标拔出后触摸板仍然无法使用,出现这种问题后
1. 关闭“插入鼠标后禁用触摸板”选项,插入鼠标观察触摸板是否可以使用,如果不能使用那么触摸板可能损坏,需要进一步排查;如果可以使用,那么可能是因为设备管理器中出现了虚拟鼠标;
2. 如果是第一步的第二种情况,需要在设备管理器中禁用第一个鼠标选项,如下图所示:

]]>
<![CDATA[建站过程]]> https://www.lishengxie.top/index.php/archives/19/ 2023-01-15T00:13:00+08:00 2023-01-15T00:13:00+08:00 lishengxie https://www.lishengxie.top/

购买腾讯云服务器

购买腾讯云清量2核4G服务器直达链接

启动镜像

这里选择了Ubuntu server 20.04,启动镜像后设置远程登录(远程登录->密码/密钥登录->重置密码),需要注意这里的用户需要系统中已经存在,默认已经存在一个用户ubuntu,这里我们直接使用该用户。
配置好后可以本地使用Mobaxterm登录云服务器,将云服务器当作Ubuntu虚拟机使用。

搭建wordpress网站

网站搭建参考了博客https://blog.csdn.net/weixin_36338224/article/details/109105047

主题替换

下载Kratos主题并上传替换原有主题,在外观里设置。

Markdown&Latex公式使用

用于Wordpress
安装WP Editor.md插件,在wordpress中使用markdown编辑。
安装Simple MathJax插件,实现对latex公示的支持,需要注意的是这里行内公式使用\(..\),例如$\sigma$,行间公式使用$$..$$,例如$$\sigma$$。

]]>