Browse Source

segmentid

master
tangmingyou 4 years ago
parent
commit
616bdc6e4c
  1. 408
      doc/db/so-im.chnr.json
  2. 29
      im-common/src/main/java/net/sopod/soim/common/util/ObjectUtil.java
  3. 5
      im-das-api/im-das-user-api/pom.xml
  4. 4
      im-das/im-das-user/src/test/java/nets/sopod/soim/das/user/test/DasUserApplicationTest.java
  5. 16
      im-logic-api/im-segment-id-api/pom.xml
  6. 13
      im-logic-api/im-segment-id-api/src/main/java/net/sopod/soim/logic/segmentid/model/Segment.java
  7. 78
      im-logic/im-segment-id/pom.xml
  8. 21
      im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/SegmentIdApplication.java
  9. 28
      im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/config/SegmentConfig.java
  10. 14
      im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/mapper/SegmentIdMapper.java
  11. 20
      im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/model/dto/NextSegmentParam.java
  12. 20
      im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/model/dto/SegmentDTO.java
  13. 47
      im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/model/entity/SegmentId.java
  14. 139
      im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/service/SegmentIdService.java
  15. 120
      im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/util/RedisLockUtil.java
  16. 22
      im-logic/im-segment-id/src/main/resources/application.yml
  17. 5
      im-logic/im-segment-id/src/main/resources/mapper/SegmentIdMapper.xml
  18. 12
      pom.xml

408
doc/db/so-im.chnr.json

@ -4,7 +4,7 @@
"avatar": "",
"version": "3.5.7",
"createdTime": "2022-3-7 15:11:08",
"updatedTime": "2022-4-1 17:26:44",
"updatedTime": "2022-4-2 15:02:54",
"profile": {
"default": {
"db": "8FE7C65E-40EB-41B6-B60E-79063AFF6273",
@ -153,7 +153,7 @@
"type": "appCode",
"applyFor": "1E385761-67B3-4B80-A194-E302E590E54E",
"isDefault": true,
"content": "\n$blankline\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport java.util.Date;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n$blankline\n{{\n var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n var hours=today.getHours();\n var minutes=today.getMinutes();\n}}\n /**\n * @author : CHINER\n * @date : {{=fullYear}}-{{=month}}-{{=days}} {{=hours}}:{{=minutes}}\n * @desc : {{=it.entity.defName}}{{? it.entity.comment}},{{=it.entity.comment}}{{?}}\n */\n@Data\n@EqualsAndHashCode(callSuper = true)\n@Accessors(chain = true)\n@ApiModel(value = \"{{=it.entity.defName}}\"{{? it.entity.comment}}, description = \"{{=it.entity.comment}}\"{{?}})\n@TableName(\"{{=it.entity.defKey}}\")\npublic class {{=it.func.camel(it.entity.defKey,true) }} extends Model<{{=it.func.camel(it.entity.defKey,true) }}> {\n{{~it.entity.fields:field:index}}\n $blankline\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n @ApiModelProperty(\"{{=field.defName}}\")\n {{? field.primaryKey }}\n @TableId(value = \"{{=field.defKey}}\"{{? field.autoIncrement}}, type=IdType.AUTO{{?}})\n {{??}}\n @TableField(value = \"{{=field.defKey}}\")\n {{?}}\n private {{=field.type}} {{=it.func.camel(field.defKey,false)}};\n{{~}}\n$blankline\n}\n$blankline"
"content": "\n$blankline\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport java.util.Date;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n$blankline\n{{\n var today=new Date();\n var fullYear=today.getFullYear();\n var month=today.getMonth() + 1;\n var days=today.getDate();\n var hours=today.getHours();\n var minutes=today.getMinutes();\n}}\n /**\n * @author : CHINER\n * @date : {{=fullYear}}-{{=month}}-{{=days}} {{=hours}}:{{=minutes}}\n * @desc : {{=it.entity.defName}}{{? it.entity.comment}},{{=it.entity.comment}}{{?}}\n */\n@Data\n@EqualsAndHashCode(callSuper = true)\n@Accessors(chain = true)\n@ApiModel(value = \"{{=it.entity.defName}}\"{{? it.entity.comment}}, description = \"{{=it.entity.comment}}\"{{?}})\n@TableName(\"{{=it.entity.defKey}}\")\npublic class {{=it.func.camel(it.entity.defKey,true) }} extends Model<{{=it.func.camel(it.entity.defKey,true) }}> {\n{{~it.entity.fields:field:index}}\n $blankline\n /** {{=it.func.join(field.defName,field.comment,';')}} */\n {{? field.primaryKey }}\n @TableId(value = \"{{=field.defKey}}\"{{? field.autoIncrement}}, type=IdType.AUTO{{?}})\n {{??}}\n @TableField(value = \"{{=field.defKey}}\")\n {{?}}\n private {{=field.type}} {{=it.func.camel(field.defKey,false)}};\n{{~}}\n$blankline\n}\n$blankline"
},
{
"type": "dbDDL",
@ -223,7 +223,7 @@
"id": "9965DCFB-54BE-4C5A-9518-DF09D4E58140"
}
],
"menuWidth": "280px"
"menuWidth": "244px"
},
"entities": [
{
@ -995,6 +995,408 @@
],
"correlations": [],
"indexes": []
},
{
"id": "E79C9C4C-FFC3-44BB-BD98-4F44F528B4B8",
"defKey": "im_segment_id",
"defName": "分段id",
"comment": "",
"properties": {},
"nameTemplate": "{defKey}[{defName}]",
"headers": [
{
"freeze": false,
"refKey": "hideInGraph",
"hideInGraph": true
},
{
"freeze": true,
"refKey": "defKey",
"hideInGraph": false
},
{
"freeze": true,
"refKey": "defName",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "primaryKey",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "notNull",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "autoIncrement",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "domain",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "type",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "len",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "scale",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "comment",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "refDict",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "defaultValue",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "isStandard",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "uiHint",
"hideInGraph": true
}
],
"fields": [
{
"defKey": "biz_tag",
"defName": "业务标签",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": true,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "BB0241B4-A9DB-46CB-AB7D-EA6DDA6A02D6",
"id": "F6D445F1-ADD3-4A28-AFDA-2606A912C007"
},
{
"defKey": "current_id",
"defName": "当前id值",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "1E5537DF-B204-49BC-AC1D-457BC6DEE707",
"id": "3E9E2CBB-B458-49D5-B6DC-454A11FB9633"
},
{
"defKey": "init_step",
"defName": "业务标签初始步长",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "1E5537DF-B204-49BC-AC1D-457BC6DEE707",
"id": "38C65486-2A4E-4862-9875-EFE113FFD627"
},
{
"defKey": "create_time",
"defName": "创建时间",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": false,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "4E3ADE61-41F4-4E74-8068-C1E543F9095C",
"id": "87279682-D6B5-4BA0-9BE5-03FC436313C9"
},
{
"defKey": "update_time",
"defName": "更新时间",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": false,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "4E3ADE61-41F4-4E74-8068-C1E543F9095C",
"id": "1F373AF6-4C60-4AC4-B75F-604B91AEC0C6"
},
{
"defKey": "version",
"defName": "版本号",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "1E5537DF-B204-49BC-AC1D-457BC6DEE707",
"id": "D376659D-0FFA-4D1A-AA3C-0C5CBA66B41B"
}
],
"correlations": [],
"indexes": []
},
{
"id": "A843E8FC-C8E8-4F0A-8EB0-C5C104BE241F",
"defKey": "im_segment_fragment",
"defName": "分段id碎片id段(id端回收)",
"comment": "",
"properties": {},
"nameTemplate": "{defKey}[{defName}]",
"headers": [
{
"freeze": false,
"refKey": "hideInGraph",
"hideInGraph": true
},
{
"freeze": true,
"refKey": "defKey",
"hideInGraph": false
},
{
"freeze": true,
"refKey": "defName",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "primaryKey",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "notNull",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "autoIncrement",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "domain",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "type",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "len",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "scale",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "comment",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "refDict",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "defaultValue",
"hideInGraph": true
},
{
"freeze": false,
"refKey": "isStandard",
"hideInGraph": false
},
{
"freeze": false,
"refKey": "uiHint",
"hideInGraph": true
}
],
"fields": [
{
"defKey": "id",
"defName": "主键id",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": true,
"notNull": true,
"autoIncrement": true,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "1E5537DF-B204-49BC-AC1D-457BC6DEE707",
"id": "32D9CFBB-3E32-4614-B576-E0E062E8FBF6"
},
{
"defKey": "biz_tag",
"defName": "业务标签",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "BB0241B4-A9DB-46CB-AB7D-EA6DDA6A02D6",
"id": "031DE904-D768-4F8B-958C-B97213421A46"
},
{
"defKey": "min_id",
"defName": "id段最小值",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "1E5537DF-B204-49BC-AC1D-457BC6DEE707",
"id": "BF29BB31-2AA3-4CF3-BD29-304DA6F60F97"
},
{
"defKey": "end_id",
"defName": "id段最大值",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "1E5537DF-B204-49BC-AC1D-457BC6DEE707",
"id": "27254611-5E86-4EAA-BADA-AE78CAD14528"
},
{
"defKey": "begin_id",
"defName": "id段当前值",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "1E5537DF-B204-49BC-AC1D-457BC6DEE707",
"id": "BEBCA2FF-01B5-4834-8218-7F7051250C3D"
},
{
"defKey": "create_time",
"defName": "创建时间",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": false,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "72DD10F8-60AE-4F2A-89E1-D69C51B30849",
"id": "4989C582-86B0-4011-A3D7-A2C43FFC3F76"
},
{
"defKey": "update_time",
"defName": "更新时间",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": false,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "72DD10F8-60AE-4F2A-89E1-D69C51B30849",
"id": "9DC77CD9-4006-42B2-9F63-13B309BC7BA1"
},
{
"defKey": "version",
"defName": "版本号",
"comment": "",
"type": "",
"len": "",
"scale": "",
"primaryKey": false,
"notNull": true,
"autoIncrement": false,
"defaultValue": "",
"hideInGraph": false,
"refDict": "",
"domain": "1E5537DF-B204-49BC-AC1D-457BC6DEE707",
"id": "C83AAC89-59CB-49E9-8C8F-2F5796BF65FE"
}
],
"correlations": [],
"indexes": []
}
],
"views": [],

29
im-common/src/main/java/net/sopod/soim/common/util/ObjectUtil.java

@ -0,0 +1,29 @@
package net.sopod.soim.common.util;
import com.google.common.base.Preconditions;
/**
* ObjectUtil
*
* @author tmy
* @date 2022-04-02 16:54
*/
public class ObjectUtil {
public static <T> T defaultValue(T value, T...defaultValues) {
if (value != null) {
return value;
}
Preconditions.checkArgument(defaultValues != null && defaultValues.length > 0, "默认值不能为空");
T result = null;
for (T defaultValue : defaultValues) {
if (defaultValue != null) {
result = defaultValue;
break;
}
}
Preconditions.checkNotNull(result, "默认值至少一个不为空");
return result;
}
}

5
im-das-api/im-das-user-api/pom.xml

@ -17,11 +17,6 @@
<artifactId>mybatis-plus-annotation</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

4
im-das/im-das-user/src/test/java/nets/sopod/soim/das/user/test/DasUserApplicationTest.java

@ -26,8 +26,8 @@ public class DasUserApplicationTest {
@Test
public void test() {
ImUser user1 = new ImUser()
.setId(4L)
.setUsername("野孩子2")
.setId(5L)
.setUsername("野孩子5")
.setPassword("123456")
.setPhone("17882451908")
.setCreateTime(ImClock.date());

16
im-logic-api/im-segment-id-api/pom.xml

@ -0,0 +1,16 @@
<?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>
<artifactId>so-im</artifactId>
<groupId>net.sopod</groupId>
<version>1.0.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>im-segment-id-api</artifactId>
</project>

13
im-logic-api/im-segment-id-api/src/main/java/net/sopod/soim/logic/segmentid/model/Segment.java

@ -0,0 +1,13 @@
package net.sopod.soim.logic.segmentid.model;
/**
* Segment
*
* @author tmy
* @date 2022-04-02 11:58
*/
public class Segment {
}

78
im-logic/im-segment-id/pom.xml

@ -0,0 +1,78 @@
<?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>
<artifactId>im-logic</artifactId>
<groupId>net.sopod</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>im-segment-id</artifactId>
<dependencies>
<dependency>
<groupId>net.sopod</groupId>
<artifactId>im-segment-id-api</artifactId>
<version>${soim.version}</version>
</dependency>
<dependency>
<groupId>net.sopod</groupId>
<artifactId>im-common</artifactId>
<version>${soim.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions><!-- 去掉springboot默认logback日志配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
</dependencies>
</project>

21
im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/SegmentIdApplication.java

@ -0,0 +1,21 @@
package net.sopod.soim.logic.segmentid;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SegmentIdApplication
*
* @author tmy
* @date 2022-04-02 14:55
*/
@EnableDubbo(scanBasePackages = {"net.sopod.soim.logic.segmentid.service"})
@SpringBootApplication
public class SegmentIdApplication {
public static void main(String[] args) {
SpringApplication.run(SegmentIdApplication.class);
}
}

28
im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/config/SegmentConfig.java

@ -0,0 +1,28 @@
package net.sopod.soim.logic.segmentid.config;
import lombok.Data;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* SegmentConfigration
*
* @author tmy
* @date 2022-04-02 17:02
*/
@EnableConfigurationProperties
@Configuration()
@Component
@Data
public class SegmentConfig {
public static final String KEY_PREFIX_SEGMENT_ID_INSERT = "SEGMENT_ID_INSERT_";
private long initId = 10000L;
private long initStep = 1000L;
private int dbSegmentVersionRetryTimes = 3;
}

14
im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/mapper/SegmentIdMapper.java

@ -0,0 +1,14 @@
package net.sopod.soim.logic.segmentid.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.sopod.soim.logic.segmentid.model.entity.SegmentId;
/**
* SegmentIdMapper
*
* @author tmy
* @date 2022-04-02 15:00
*/
public interface SegmentIdMapper extends BaseMapper<SegmentId> {
}

20
im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/model/dto/NextSegmentParam.java

@ -0,0 +1,20 @@
package net.sopod.soim.logic.segmentid.model.dto;
import lombok.Data;
/**
* NextSegmentParam
*
* @author tmy
* @date 2022-04-02 16:51
*/
@Data
public class NextSegmentParam {
/** 业务标签 */
private String bizTag;
/** 步长,为空则使用数据库默认 */
private Long step;
}

20
im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/model/dto/SegmentDTO.java

@ -0,0 +1,20 @@
package net.sopod.soim.logic.segmentid.model.dto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* SegmentDTO
*
* @author tmy
* @date 2022-04-02 17:27
*/
@Data
@Accessors(chain = true)
public class SegmentDTO {
private long beginId;
private long endId;
}

47
im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/model/entity/SegmentId.java

@ -0,0 +1,47 @@
package net.sopod.soim.logic.segmentid.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* SegmentId
*
* @author tmy
* @date 2022-04-02 15:01
*/
@Data
@Accessors(chain = true)
@TableName("im_segment_id")
public class SegmentId {
/** 业务标签 */
@TableId(value = "biz_tag", type = IdType.INPUT)
private String bizTag;
/** 当前id值 */
@TableField(value = "current_id")
private Long currentId;
/** 业务标签初始步长 */
@TableField(value = "init_step")
private Long initStep;
/** 创建时间 */
@TableField(value = "create_time")
private Date createTime;
/** 更新时间 */
@TableField(value = "update_time")
private Date updateTime;
/** 版本号 */
@TableField(value = "version")
private Long version;
}

139
im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/service/SegmentIdService.java

@ -0,0 +1,139 @@
package net.sopod.soim.logic.segmentid.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.base.Preconditions;
import lombok.AllArgsConstructor;
import net.sopod.soim.common.util.ImClock;
import net.sopod.soim.common.util.ObjectUtil;
import net.sopod.soim.logic.segmentid.config.SegmentConfig;
import net.sopod.soim.logic.segmentid.mapper.SegmentIdMapper;
import net.sopod.soim.logic.segmentid.model.dto.NextSegmentParam;
import net.sopod.soim.logic.segmentid.model.dto.SegmentDTO;
import net.sopod.soim.logic.segmentid.model.entity.SegmentId;
import net.sopod.soim.logic.segmentid.util.RedisLockUtil;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.ThreadLocalRandom;
/**
* SegmentIdService
*
* @author tmy
* @date 2022-04-02 15:22
*/
@DubboService
@AllArgsConstructor
public class SegmentIdService {
private static final Logger logger = LoggerFactory.getLogger(SegmentIdService.class);
private final SegmentIdMapper segmentIdMapper;
private final RedisTemplate<String, String> redisTemplate;
private final SegmentConfig segmentConfig;
public SegmentDTO nextSegmentId(NextSegmentParam param) {
String bizTag = param.getBizTag();
SegmentId segmentId = segmentIdMapper.selectById(bizTag);
if (segmentId == null) {
String key = SegmentConfig.KEY_PREFIX_SEGMENT_ID_INSERT + bizTag;
String val = String.valueOf(ThreadLocalRandom.current().nextInt());
// 锁二十秒,创建数据
boolean locked = RedisLockUtil.acquireLock(redisTemplate, key, val, 20000L);
if (locked) {
try {
// 插入分段id数据
SegmentId newSegmentId = new SegmentId()
.setBizTag(bizTag)
.setCreateTime(ImClock.date())
.setCurrentId(segmentConfig.getInitId())
.setVersion(0L)
.setInitStep(segmentConfig.getInitStep());
segmentIdMapper.insert(newSegmentId);
segmentId = newSegmentId;
} finally {
// 释放锁
RedisLockUtil.releaseLock(redisTemplate, key, val);
}
} else {
// 等待锁释放
long timeout = 2000L;
boolean released = waitReleaseRedisLock(key, timeout);
if (!released) {
logger.warn("{} 插入数据超过 {} 未释放", bizTag, timeout);
}
segmentId = segmentIdMapper.selectById(bizTag);
}
if (segmentId == null) {
throw new RuntimeException(String.format("%s分段数据不存在,新增失败", bizTag));
}
}
int i = 0;
do {
SegmentDTO segment = getSegment(segmentId, param.getStep());
if (segment != null) {
return segment;
}
i++;
} while (i < segmentConfig.getDbSegmentVersionRetryTimes());
throw new RuntimeException("id分段获取失败");
}
private boolean waitReleaseRedisLock(String key, long timeout) {
long begin = ImClock.millis();
// while 阻塞等待
while (true) {
long current = ImClock.millis();
if (!RedisLockUtil.hasKey(redisTemplate, key)) {
return true;
}
if (current - begin > timeout) {
return false;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
logger.error("wait release redis lock interrupted!", e);
}
}
}
/**
* 获取id段
* @param dbSegmentId 当前DB segmentId
* @param step 步长
*/
private SegmentDTO getSegment(SegmentId dbSegmentId, Long step) {
step = ObjectUtil.defaultValue(step, dbSegmentId.getInitStep(), null);
Preconditions.checkState(step > 0, "步长需大于0");
// 开始id, 结束id
Long currentId = dbSegmentId.getCurrentId();
long endId = dbSegmentId.getCurrentId() + step;
// 版本号更新条件
LambdaQueryWrapper<SegmentId> segmentIdUpdate = new QueryWrapper<SegmentId>().lambda()
.eq(SegmentId::getBizTag, dbSegmentId.getBizTag())
.eq(SegmentId::getVersion, dbSegmentId.getVersion());
SegmentId newSegment = new SegmentId()
.setBizTag(dbSegmentId.getBizTag())
.setUpdateTime(ImClock.date())
.setCurrentId(endId + 1)
.setVersion(dbSegmentId.getVersion() + 1);
// 根据版本号条件尝试更新
int row = segmentIdMapper.update(newSegment, segmentIdUpdate);
if (row == 0) {
// 未更新成功,被其他连接并发更新
return null;
}
// 更新成功
return new SegmentDTO()
.setBeginId(currentId)
.setEndId(endId);
}
}

120
im-logic/im-segment-id/src/main/java/net/sopod/soim/logic/segmentid/util/RedisLockUtil.java

@ -0,0 +1,120 @@
package net.sopod.soim.logic.segmentid.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
* Redis分布式锁工具
*
* @author tangmingyou
* @date 2022-03-18 14:21
*/
public class RedisLockUtil {
private static final Logger logger = LoggerFactory.getLogger(RedisLockUtil.class);
private static final RedisScript<String> SCRIPT_LOCK = new DefaultRedisScript<>("return redis.call('set',KEYS[1],ARGV[1],'NX','PX',ARGV[2])", String.class);
private static final RedisScript<String> SCRIPT_UNLOCK = new DefaultRedisScript<>("if redis.call('get',KEYS[1]) == ARGV[1] then return tostring(redis.call('del', KEYS[1])==1) else return 'false' end", String.class);
private static final String LOCK_SUCCESS = "OK";
/**
* 加锁 redis 中设置值并设置过期时间
* @param lockKey
* @param lockValue
* @param acquireExpire 超期时间(毫秒)
* @return 是否获取成功
*/
public static boolean acquireLock(RedisTemplate<String, String> redisTemplate,
String lockKey, String lockValue, long acquireExpire) {
Object lockResult = redisTemplate.execute(SCRIPT_LOCK,
redisTemplate.getStringSerializer(),
redisTemplate.getStringSerializer(),
Collections.singletonList(lockKey),
lockValue, String.valueOf(acquireExpire));
// 加锁失败 lockResult 为 null
return LOCK_SUCCESS.equals(lockResult);
}
/**
* <pre>
* 为何解锁需要校验lockValue
* 客户端A加锁一段时间之后客户端A解锁在执行releaseLock之前锁突然过期了
* 此时客户端B尝试加锁成功然后客户端A再执行releaseLock方法则将客户端B的锁给解除了
* </pre>
* @param lockKey redis
* @param lockValue lock 的值
* @return 是否成功
*/
public static boolean releaseLock(RedisTemplate<String, String> redisTemplate,
String lockKey, String lockValue) {
Object releaseResult = redisTemplate.execute(SCRIPT_UNLOCK,
redisTemplate.getStringSerializer(),
redisTemplate.getStringSerializer(),
Collections.singletonList(lockKey),
lockValue);
return Boolean.parseBoolean(releaseResult.toString());
}
/**
* 指定缓存失效时间
* @param key
* @param time 时间()
* @return 是否成功
*/
public static boolean expire(RedisTemplate<String, String> redisTemplate,
String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
throw new RuntimeException("指定缓存失效时间异常");
}
}
/**
* 根据key 获取过期时间
* @param key 不能为null
* @return 时间() 返回0代表为永久有效
*/
public static long getExpire(RedisTemplate<String, String> redisTemplate, String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
* @param key
* @return true 存在 false不存在
*/
public static boolean hasKey(RedisTemplate<String, String> redisTemplate, String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return false;
}
}
/**
* 删除缓存
* @param keys 可以传一个值 或多个
*/
public static void del(RedisTemplate<String, String> redisTemplate, String... keys) {
if (keys != null && keys.length > 0) {
if (keys.length == 1) {
redisTemplate.delete(keys[0]);
} else {
redisTemplate.delete(Arrays.asList(keys));
}
}
}
}

22
im-logic/im-segment-id/src/main/resources/application.yml

@ -0,0 +1,22 @@
spring:
application:
name: segment-id
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://cd-cdb-mrz9fw80.sql.tencentcdb.com:61843/soim_db?serverTimezone=GMT%2B8
username: root
password: sopod@2347#
redis:
host: 124.222.131.236:3379
password: sopod@redis#
dubbo:
application:
name: ${spring.application.name}
registry:
address: nacos://124.222.131.236:3848
protocol:
port: 3001
mybatis-plus:
mapper-locations: classpath:mapper/*.xml

5
im-logic/im-segment-id/src/main/resources/mapper/SegmentIdMapper.xml

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="net.sopod.soim.logic.segmentid.mapper.SegmentIdMapper">
</mapper>

12
pom.xml

@ -19,6 +19,8 @@
<module>im-core</module>
<module>im-das</module>
<module>im-das-api</module>
<module>im-logic-api/im-segment-id-api</module>
<module>im-logic/im-segment-id</module>
</modules>
<properties>
@ -122,6 +124,11 @@
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
@ -208,6 +215,11 @@
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>

Loading…
Cancel
Save