有点牛逼,滴滴开源的分布式id生成系统
阅读本文大概需要 7 分钟。
来自:网络
简介
tinyid系统架构图

- nextId和getNextSegmentId是tinyid-server对外提供的两个http接口 
- nextId是获取下一个id,当调用nextId时,会传入bizType,每个bizType的id数据是隔离的,生成id会使用该bizType类型生成的IdGenerator。 
- getNextSegmentId是获取下一个可用号段,tinyid-client会通过此接口来获取可用号段 
- IdGenerator是id生成的接口 
- IdGeneratorFactory是生产具体IdGenerator的工厂,每个biz_type生成一个IdGenerator实例。通过工厂,我们可以随时在db中新增biz_type,而不用重启服务 
- IdGeneratorFactory实际上有两个子类IdGeneratorFactoryServer和IdGeneratorFactoryClient,区别在于,getNextSegmentId的不同,一个是DbGet,一个是HttpGet 
- CachedIdGenerator则是具体的id生成器对象,持有currentSegmentId和nextSegmentId对象,负责nextId的核心流程。 - nextId最终通过AtomicLong.andAndGet(delta)方法产生。 
性能与可用性
性能
- http方式访问,性能取决于http server的能力,网络传输速度 
- java-client方式,id为本地生成,号段长度(step)越长,qps越大,如果将号段设置足够大,则qps可达1000w+ 
可用性
- 依赖db,当db不可用时,因为server有缓存,所以还可以使用一段时间,如果配置了多个db,则只要有1个db存活,则服务可用 
- 使用tiny-client,只要server有一台存活,则理论上可用,server全挂,因为client有缓存,也可以继续使用一段时间 
Tinyid的特性
- 全局唯一的long型id 
- 趋势递增的id,即不保证下一个id一定比上一个大 
- 非连续性 
- 提供http和java client方式接入 
- 支持批量获取id 
- 支持生成1,3,5,7,9…序列的id 
- 支持多个db的配置,无单点 
推荐使用方式
- tinyid-server推荐部署到多个机房的多台机器 
- 多机房部署可用性更高,http方式访问需使用方考虑延迟问题 
- 推荐使用tinyid-client来获取id,好处如下: 
- id为本地生成(调用AtomicLong.addAndGet方法),性能大大增加 
- client对server访问变的低频,减轻了server的压力 
- 因为低频,即便client使用方和server不在一个机房,也无须担心延迟 
- 即便所有server挂掉,因为client预加载了号段,依然可以继续使用一段时间 注:使用tinyid-client方式,如果client机器较多频繁重启,可能会浪费较多的id,这时可以考虑使用http方式 
- 推荐db配置两个或更多: 
- db配置多个时,只要有1个db存活,则服务可用 多db配置,如配置了两个db,则每次新增业务需在两个db中都写入相关数据 
tinyid的原理
Id生成系统要点
- 全局唯一的id:无论怎样都不能重复,这是最基本的要求了 
- 高性能:基础服务尽可能耗时少,如果能够本地生成最好 
- 高可用:虽说很难实现100%的可用性,但是也要无限接近于100%的可用性 
- 简单易用: 能够拿来即用,接入方便,同时在系统设计和实现上要尽可能的简单 
Tinyid的实现原理
DB号段算法描述

- 这里我们增加了biz_type,这个代表业务类型,不同的业务的id隔离 
- max_id则是上面的end_id了,代表当前最大的可用id 
- step代表号段的长度,可以根据每个业务的qps来设置一个合理的长度 
- version是一个乐观锁,每次更新都加上version,能够保证并发更新的正确性 那么我们可以通过如下几个步骤来获取一个可用的号段, 
- A.查询当前的max_id信息:select id, biz_type, max_id, step, version from tiny_id_info where biz_type='test'; 
- B.计算新的max_id: new_max_id = max_id + step 
- C.更新DB中的max_id:update tiny_id_info set max_id=#{new_max_id} , verison=version+1 where id=#{id} and max_id=#{max_id} and version=#{version} 
- D.如果更新成功,则可用号段获取成功,新的可用号段为(max_id, new_max_id] 
- E.如果更新失败,则号段可能被其他线程获取,回到步骤A,进行重试 
号段生成方案的简单架构

简单架构的问题
- 当id用完时需要访问db加载新的号段,db更新也可能存在version冲突,此时id生成耗时明显增加 
- db是一个单点,虽然db可以建设主从等高可用架构,但始终是一个单点 
- 使用http方式获取一个id,存在网络开销,性能和可用性都不太好 
优化办法如下:


- tinyid提供http和tinyid-client两种方式接入 
- tinyid-server内部缓存两个号段 
- 号段基于db生成,具有原子性 
- db支持多个 
- tinyid-server内置easy-router选择db 
项目地址
推荐阅读:
成都又一程序员跳楼!一首IT版的《成都》,听哭了所有IT人……
微信扫描二维码,关注我的公众号
朕已阅 


