阅读 201

redis分布式缓存(七)一一 分布式全局id解决方案(String)

一、为什么需要分布式全局id?

在互联网系统发展进程中,我们经历过从单体项目逐渐转向分布式项目。分布式项目解决了单体项目的代码臃肿,功能职责不明确,维护困难,不易扩展等毛病。

当并发度越大,数据越大就越需要分布式架构,而大量的分布式数据就越需要唯一标识来识别它们。

image.png 例如:

  • 淘宝的商品系统有千亿级别商品,订单系统有万亿级别的订单数据,这些数据都是日渐增长,传统的单库单表是无法支撑这种级别的数据,必须对其进行分库分表;

  • 一但分库分表,表的自增id就失去了意义;故需要一个全局唯一的id来标识每一条数据。

image.png

二、全局唯一id特点?

  1. 全局唯一性:整个分布式服务系统中不能出现重复的ID。

  2. 单调递增:保证生成的下一个ID一定大于上一个ID,单调递增会顺序添加到数据索引的节点的后续位置,当一页写满,就会自动开辟一个新的页,不需要移动数据重构索引树,减少碎片。

  3. 趋势递增:在一段时间内,生成的ID是递增的趋势,提高写入性能。如:在一段时间内生成的ID在【0,1000】之间,过段时间生成的ID在【1000,2000】之间。但在【0-1000】区间内的时候,ID生成有可能第一次是12,第二次是10,第三次是14。

  4. 信息安全:如果 ID 是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞争对手可以直接知道我们一天的单量。所以在一些应用场景下,会需要无规则、不规则的 ID。

第2、4两个需求是互斥的,无法同时满足。 同时,在大型分布式网站架构中,除了需要满足ID生成自身的需求外,还需要ID生成系统可用性极高。因此,做一个全局唯一id生成系统必须满足以下特点:

  1. 高可用

  2. 高QPS。

三、分布式id实现技术有哪些

  1. UUID

  2. MySQL多实例主键自增

  3. snowflake雪花算法

  4. Redis生成方案

  5. MongoDB的ObjectId

  6. 利用zookeeper生成唯一ID

注:本文只讨论redis生成的方案

四、基于Redis实现分布式全局唯一id

INCR 命令主要有以下2个特征:

  1. Redis的INCR命令具备了“INCR AND GET”的原子操作,即增加并返回结果的原子操作。这个原子性很方便我们实现获取ID.

  2. Redis是单进程单线程架构,INCR命令不会出现id重复.

基于以上2个特性,我们可以采用INCR命令来实现分布式全局ID生成。

五、案例实战:采用redis生成全局id

技术思路:

  1. 采用redis的INCR的命令,从1自增生成ID。

  2. 由于海量数据,我们不能放到一张表中,故必须对其进行分库分表,每张表的id不能用自增,由redis的incr命令来自动生成。

  3. 海量数据需要分库分表,例如商品表 product_0,product_1,product_2......product_1023

步骤1:编写全局id封装类

@Service public class IdGenerator {     @Autowired     private StringRedisTemplate stringRedisTemplate;     private static final String ID_KEY = "id:generator:product";     /**      * 生成全局唯一id      */     public Long incrementId() {         long n=this.stringRedisTemplate.opsForValue().increment(ID_KEY);         return n;     } } 复制代码

步骤2:模拟创建商品

@RestController @Slf4j @RequestMapping(value = "/pruduct") public class ProductController {     @Autowired     private IdGenerator idGenerator;     @PostMapping(value = "/add")     public void add(Product product) {         //步骤1:生成分布式id         long id=this.idGenerator.incrementId();         //全局id,代替数据库的自增id         product.setId(id);         //步骤2:取模,计算表名         //类似于海量的数据,一般是分为1024张表。         int table=(int)id % 1024;         String tablename="product_"+table;         log.info("插入表名{},插入内容{}",tablename,obj);     } }


作者:小伙子vae
链接:https://juejin.cn/post/7026162811822669832


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐