上一篇文章我们讲了几种常见的分布式唯一ID生成方案,今天我们再来讲一下由美团开源的Leaf框架,这个框架集成了两种最适合生产环境使用的方式
第一种方式是:Leaf Segment
这种方式其实跟我们之前讲过的flickr高并发方案类似,都是使用数据库来生成分布式唯一ID,同时生成的唯一ID代表了一整个号段,保证了数据库的高并发使用,同时里面还进行了一个双Buffer的优化,这个我们在后面的源码分析里面详细讲
我先把Leaf中的号段格式展示出来,这一段在Leaf官网中也有
+-------------+--------------+------+-----+-------------------+-----------------------------+
| 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 |
+-------------+--------------+------+-----+-------------------+-----------------------------+
里面核心的字段是biz_tag(业务标记),不同的业务使用Leaf的时候会有不同的标志,防止各个业务使用分布式唯一ID的时候错乱,大家各用各的唯一ID,这样的话一张表就可以维护多个不同业务的唯一ID了
max_id(最大唯一ID),上面我们提了一下生成的唯一ID代表了一整个号段,所以这个字段就表示了最大的唯一ID是多少
step(步长),通过步长和最大ID,我们就能得到最小ID,同时我们就能得到一整个号段了
Leaf Segment的核心实现在com.sankuai.inf.leaf.segment.SegmentIDGenImpl类中,我们详细分析一下里面的方法
@Override
public boolean init() {
logger.info("Init ...");
// 确保加载到kv后才初始化成功,具体解析在下面
updateCacheFromDb();
initOK = true;
// 通过方法名就可以理解,这里实际上通过一个定时的线程池每分钟去调用updateCacheFromDb方法
updateCacheFromDbAtEveryMinute();
return initOK;
}
private void updateCacheFromDb() {
logger.info("update cache from db");
StopWatch sw = new Slf4JStopWatch();
try {
// 从数据库表(上面文中提到的表)中获取所有的biz_tag
List<String> dbTags = dao.getAllTags();
if (dbTags == null || dbTags.isEmpty()) {