基于eureka和snowflake生成唯一id

基于在eureka上注册的信息,instanceId在eureka上是唯一的,是有ip+port组成的。

    @Value("${spring.cloud.client.ipAddress}")
    private String clientAddress;

    @Value("${server.port}")
    private String serverPort;

我们创建了一个表来记录这些信息

CREATE TABLE `t_medical_instance` (
  `id` int(4) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `instance_id` varchar(100) NOT NULL COMMENT '服务标示',
  `del_flag` tinyint(1) DEFAULT NULL COMMENT '删除标示',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `service_id_UNIQUE` (`instance_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='节点信息保存';

每次读取表信息

MedicalInstance medicalInstance = medicalInstanceService.selectMedicalInstanceByInstance(instanceId);
            if (medicalInstance == null) {
                medicalInstance = new MedicalInstance();
                medicalInstance.setInstanceId(instanceId);
                medicalInstanceService.addData(medicalInstance);
            }
            if (medicalInstance.getId() > maxWorkerId) {
                logger.info("workId不能大于最大机器码");
                throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
            }
            this.workerId = medicalInstance.getId();
            medicalSnowFlake = this;
        } catch (BizException e) {
            logger.error("获取id失败,展示不能生成id",e);
            throw new IllegalArgumentException("id生成初始化失败");
        }

完整代码如下

/**
 *@Author GUOSHAOHUA093
 *@Description snowFlakeid生成类
 *@Date 14:15 2019/1/11
 */
@Component
public class MedicalSnowFlake {

    static Logger logger = LoggerFactory.getLogger(MedicalSnowFlake.class);

    //其实时间戳   2017-01-01 00:00:00
    private final static long twepoch = 1288834974657L;

    //10bit(位)的工作机器id  中IP标识所占的位数 5bit(位)
    private final static long workerIdBits = 5L;

    //wordId标识最大值 31  即2的5次方减一。
    private final static long maxWorkerId = ~(-1L << workerIdBits);

    //10bit(位)的工作机器id  中数字标识id所占的位数 5bit(位)
    private final static long dataCenterIdBits = 5L;

    //数字标识id最大值 31  即2的5次方减一。
    private final static long maxDatacenterId = ~(-1L << dataCenterIdBits);

    //序列在id中占的位数 12bit
    private final static long sequenceBits = 12L;

    //序列最大值 4095 即2的12次方减一。
    private final static long sequenceMax = ~(-1L << sequenceBits);

    // 64位的数字:首位0  随后41位表示时间戳 随后10位工作机器id(5位IP标识 + 5位数字标识) 最后12位序列号
    private final static long workerIdShift = sequenceBits;
    private final static long datacenterIdShift = sequenceBits + workerIdBits;
    private final static long timeLeftShift = sequenceBits + workerIdBits + dataCenterIdBits;


    //机器码
    private long workerId;

    // 数据中心ID(0~3)
    private long datacenterId = 0;

    // 毫秒内序列(0~4095)
    private long sequence = 0L;

    // 上次生成ID的时间截
    private long lastTime = -1L;

    private static MedicalSnowFlake medicalSnowFlake;

    @Value("${spring.application.name}")
    private String applicationName;

    @Value("${spring.cloud.client.ipAddress}")
    private String clientAddress;

    @Value("${server.port}")
    private String serverPort;

    @Autowired
    @Qualifier("medicalInstanceService")
    private IMedicalInstanceBiz medicalInstanceService;

    @PostConstruct
    public void init() {
        try {
            //用instanceId来指定workerId
            String instanceId = clientAddress + ":" + serverPort;
            MedicalInstance medicalInstance = medicalInstanceService.selectMedicalInstanceByInstance(instanceId);
            if (medicalInstance == null) {
                medicalInstance = new MedicalInstance();
                medicalInstance.setInstanceId(instanceId);
                medicalInstanceService.addData(medicalInstance);
            }
            if (medicalInstance.getId() > maxWorkerId) {
                logger.info("workId不能大于最大机器码");
                throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
            }
            this.workerId = medicalInstance.getId();
            medicalSnowFlake = this;
        } catch (BizException e) {
            logger.error("获取id失败,展示不能生成id",e);
            throw new IllegalArgumentException("id生成初始化失败");
        }
    }

    public static MedicalSnowFlake getInstance() {
        return medicalSnowFlake;
    }

    public synchronized long nextId() {
        //获取当前时间
        long nowTime = currentTimeMillis();
        //如果当前时间小于最后一次时间
        if (nowTime < lastTime) {
            logger.info("当前时间前于上次操作时间,当前时间有误: " + nowTime);
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTime - nowTime));
        }
        if (nowTime == lastTime) {
            sequence = (sequence + 1) & sequenceMax;
            if (sequence == 0) {
                nowTime = getNextTimeStamp();
            }
        } else {
            sequence = 0L;
        }

        lastTime = nowTime;

        return ((nowTime - twepoch) << timeLeftShift)
                | (workerId << workerIdShift)
                | (datacenterId << datacenterIdShift)
                | sequence;
    }

    private long getNextTimeStamp() {
        long nowTime;
        do {
            nowTime = System.currentTimeMillis();
        } while (nowTime <= lastTime);
        return nowTime;
    }

    protected long currentTimeMillis() {
        return System.currentTimeMillis();
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 特性 无侵入:Mybatis-Plus 在 Mybatis 的基础上进行扩展,只做增强不做改变,引入 Mybatis-Plus 不会对您现有的 Mybatis 构架产生任何影响,而且 MP 支持所有 Mybatis 原生的特性 依赖少:仅仅依赖 Mybatis 以及 Mybatis-Spring 损耗小:启动即会自动注入基本CURD,性能基本无损耗,直接面向对象操作 预防Sql注入:内置Sql注入剥离器,有效预防Sql注入攻击 通用CRUD操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 多种主键策略:支持多达4种主键策略(内含分布式唯一ID生成器),可自由配置,完美解决主键问题 支持ActiveRecord:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可实现基本 CRUD 操作 支持代码生成:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用(P.S. 比 Mybatis 官方的 Generator 更加强大!) 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere ) 支持关键词自动转义:支持数据库关键词(order、key……)自动转义,还可自定义关键词 内置分页插件:基于Mybatis物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通List查询 内置性能分析插件:可输出Sql语句以及其执行时间,建议开发测试时启用该功能,能有效解决慢查询 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,预防误操作
SpringCloud可以集成Prometheus作为监控组件,通过Prometheus来收集各个微服务的指标数据,并通过Grafana进行展示和报警。 基于Eureka的SpringCloud应用,可以通过在每个微服务中添加Prometheus客户端来完成指标数据的采集。具体步骤如下: 1. 引入依赖 在每个微服务的pom.xml文件中添加如下依赖: ```xml <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-core</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> ``` 2. 配置Prometheus客户端 在每个微服务的配置文件中添加如下配置: ```yaml management: endpoints: web: exposure: include: prometheus metrics: tags: application: ${spring.application.name} ``` 3. 配置Prometheus 在Prometheus的配置文件中添加如下配置: ```yaml scrape_configs: - job_name: 'spring_cloud_eureka' scrape_interval: 5s static_configs: - targets: ['localhost:8761'] # Eureka注册中心地址 - job_name: 'spring_cloud_service' scrape_interval: 5s static_configs: - targets: ['localhost:8080', 'localhost:8081'] # 微服务地址列表 ``` 4. 配置Grafana 在Grafana中添加Prometheus数据源,并创建相应的仪表盘来展示微服务的指标数据。 以上就是基于Eureka的SpringCloud应用集成Prometheus监控的详细步骤。需要注意的是,以上配置只是一个示例,具体的配置需要根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值