zoukankan      html  css  js  c++  java
  • Redis生成分布式系统全局唯一ID

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/13194027.html

    分布式系统全局唯一ID

    在互联网系统中,并发越大的系统,数据就越大,数据越大就越需要分布式,而大量的分布式数据就越需要唯一标识来识别它们。

    例如淘宝的商品系统有千亿级别商品,订单系统有万亿级别的订单数据,这些数据都是日渐增长,传统的单库单表是无法支撑这种级别的数据,必须对其进行分库分表;一旦分库分表,表的自增ID就失去了意义;故需要一个全局唯一的ID来标识每一条数据(商品、订单)。

    e.g: 一张表1亿条数据,被分库分表10张表,原先的ID就失去意义,所以需要全局唯一ID来标识10张表的数据。

    全局唯一的ID生成的技术方案有很多,业界比较有名的有 UUID、Redis、Twitter的snowflake算法、美团Leaf算法。 

    基于Redis INCR 命令生成分布式全局唯一ID

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

    1. Redis的INCR命令具备了“INCR AND GET”的原子操作
    2. Redis是单进程单线程架构,INCR命令不会出现ID重复

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

    采用Redis生成商品全局唯一ID

    Project Directory

    Maven Dependency

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.8.RELEASE</version>
            <relativePath/>
        </parent>
    
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.fool.redis</groupId>
        <artifactId>redis-string-id</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

    application.properties

    spring.application.name=redis-spring-id
    server.port=8888
    
    spring.redis.host=localhost
    spring.redis.port=6379
    spring.redis.database=0
    spring.redis.password=
    spring.redis.timeout=2000
    spring.redis.pool.max-active=10
    spring.redis.pool.max-wait=1000
    spring.redis.pool.max-idle=10
    spring.redis.pool.min-idle=5
    spring.redis.pool.num-tests-per-eviction-run=1024
    spring.redis.pool.time-between-eviction-runs-millis=30000
    spring.redis.pool.min-evictable-idle-time-millis=60000
    spring.redis.pool.soft-min-evictable-idle-time-millis=10000
    spring.redis.pool.test-on-borrow=true
    spring.redis.pool.test-while-idle=true
    spring.redis.pool.block-when-exhausted=false

    SRC

    Application.java

     1 package org.fool.redis;
     2 
     3 import org.springframework.boot.SpringApplication;
     4 import org.springframework.boot.autoconfigure.SpringBootApplication;
     5 
     6 @SpringBootApplication
     7 public class Application {
     8     public static void main(String[] args) {
     9         SpringApplication.run(Application.class, args);
    10     }
    11 }

    Product.java

     1 package org.fool.redis.model;
     2 
     3 import lombok.Data;
     4 
     5 import java.math.BigDecimal;
     6 
     7 @Data
     8 public class Product {
     9     private Long id;
    10     private String name;
    11     private BigDecimal price;
    12     private String detail;
    13 }

    IdGeneratorService.java

     1 package org.fool.redis.service;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.data.redis.core.StringRedisTemplate;
     5 import org.springframework.stereotype.Service;
     6 
     7 @Service
     8 public class IdGeneratorService {
     9     @Autowired
    10     private StringRedisTemplate stringRedisTemplate;
    11 
    12     private static final String ID_KEY = "id:generator:product";
    13 
    14     public Long incrementId() {
    15         return stringRedisTemplate.opsForValue().increment(ID_KEY);
    16     }
    17 }

    ProductController.java

     1 package org.fool.redis.controller;
     2 
     3 import lombok.extern.slf4j.Slf4j;
     4 import org.fool.redis.model.Product;
     5 import org.fool.redis.service.IdGeneratorService;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.web.bind.annotation.PostMapping;
     8 import org.springframework.web.bind.annotation.RequestBody;
     9 import org.springframework.web.bind.annotation.RequestMapping;
    10 import org.springframework.web.bind.annotation.RestController;
    11 
    12 @RestController
    13 @Slf4j
    14 @RequestMapping(value = "/product")
    15 public class ProductController {
    16     @Autowired
    17     private IdGeneratorService idGeneratorService;
    18 
    19     @PostMapping(value = "/create")
    20     public String create(@RequestBody Product obj) {
    21         //生成分布式id
    22         long id = idGeneratorService.incrementId();
    23 
    24         //使用全局id 代替数据库的自增id
    25         obj.setId(id);
    26 
    27         //取模(e.g: 这里分为8张表,海量数据可以分为1024张表),计算表名
    28         int table = (int) id % 8;
    29         String tableName = "product_" + table;
    30 
    31         log.info("insert to table: {}, with content: {}", tableName, obj);
    32 
    33         return "insert to table: " + tableName + " with content: " + obj;
    34     }
    35 }

    Test

    curl --location --request POST 'http://localhost:8888/product/create' 
    --header 'Content-Type: application/json' 
    --data-raw '{
        "name": "Car",
        "price": "300000.00",
        "detail": "Lexus Style"
    }'

    Console Output

  • 相关阅读:
    moss jscript
    CSS两端对准
    简单的日期格式验证
    .NET中使用Exchange 2007 Webservice来读取邮件
    张二狗
    spcontext
    Infopath表单用改控件值提交或作别的更改时一定要在控件属性浏览器表单的回发设置为始终.
    使用 Web 服务
    SharePoint 2010中开发模式的改进 COM 客户端对象模型
    Retrieve data from Separate Oracle System
  • 原文地址:https://www.cnblogs.com/agilestyle/p/13194027.html
Copyright © 2011-2022 走看看