参考 https://tech.meituan.com/2017/04/21/mt-leaf.html
基本原理
begin;
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
commit;
注:mysql可以通过auto_increment_increment和auto_increment_offset两个全局参数来设置自增步长和起始ID
故mysql自增 ID = (N-1) * increment + offset ,N为第N条记录
参考 https://www.cnblogs.com/olinux/p/6518766.html
优点
简单,有序,不影响做ID做主键
缺点
分布式系统中存在单点瓶颈问题(配置多个代理节点获取批量ID解决),
单点可用性问题(配置主从解决,但又会引发数据一致性问题,即重号)
优化方案
1.单点读写瓶颈
通过集群部署,每设置自增步长和机器数相等,起始ID相差1,比如有3台机器ABC,则A产生ID(1,4,7,10...),B(2,5,8,11....),C(3,6,9,12...)
那么如果有N台机器,比如有N台机器ABCD...N,参考 ID = (N-1) * increment + offset = (N-1)*N+offset ,offset=(0,1,2,34,...) 生成间隔ID。
缺点:当集群数目到达一定数量,水平扩展变得非常复杂,另外,每次都需要读写数据库获取ID,造成数据库压力大。
Leaf-segment数据库方案
使用多个代理服务节点,每个服务节点一次性从数据库获取批量ID,即一个号段。
另外生成的ID格式还可以进一步优化(用一张表来存储ID),可以按 业务标识(biz_tag)+号段下界(max_id) 来标识某个业务的ID区间,则一个代理服务节点可批量获得这个区间的ID。
数据库表结构
+-------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+-------------------+-----------------------------+
| biz_tag | varchar(128) | NO | PRI | | |
| max_id | bigint(20) | NO | | 1 | |
| step | int(11) | NO | | NULL | |
| desc | varchar(256) | YES | | NULL | |
| update_time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
根据step参数来控制每次批量生成数目,比如step=1000,根据max_id+step来计算每种业务tag的号段区间,不同tag之间互不影响,即不同tag之间的ID可以重复。
优点:
ID为8字节64位,可以做主键
容易扩展,可按业务标志分库分表进行扩容
大大降低了数据库读写频率
批量获取ID提高了系统可用性,能容忍DB短暂宕机
缺点:
号码有较强连续性,可从中获取相关业务信息,一些商业数据(比如成交记录条数),因此不安全
还达不到高并发场景的可用性,以及性能指标
优化方案:
针对高并发场景,为提高请求线程响应速度,将主动请求改为被动推送,由数据库服务器节点主动按一定条件推送新生成的批量ID给代理节点。
针对生成ID在业务上不安全的问题,可采用snowflake算法
针对DB宕机导致数据丢失,号段不连续问题,可主从备份配置