Redis生成分佈式系統全局惟一ID

原創轉載請註明出處:http://www.javashuo.com/article/p-gueovgml-np.htmlhtml

 

分佈式系統全局惟一ID

在互聯網系統中,併發越大的系統,數據就越大,數據越大就越須要分佈式,而大量的分佈式數據就越須要惟一標識來識別它們。java

例如淘寶的商品系統有千億級別商品,訂單系統有萬億級別的訂單數據,這些數據都是日漸增加,傳統的單庫單表是沒法支撐這種級別的數據,必須對其進行分庫分表;一旦分庫分表,表的自增ID就失去了意義;故須要一個全局惟一的ID來標識每一條數據(商品、訂單)。web

e.g: 一張表1億條數據,被分庫分表10張表,原先的ID就失去意義,因此須要全局惟一ID來標識10張表的數據。redis

全局惟一的ID生成的技術方案有不少,業界比較有名的有 UUID、Redis、Twitter的snowflake算法、美團Leaf算法。 算法

 

基於Redis INCR 命令生成分佈式全局惟一ID

INCR 命令主要有如下2個特徵:spring

  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.javaapache

 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.javajson

 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

相關文章
相關標籤/搜索