一次压测经历认识了雪花

前言

这周同事把我拉进一个压测群,让我配合压测服务,主要是排查日志配合测试、运维人员压测。之后给了我项目资料,服务器信息,vpn等。等我拿到这些项目资料的时候,同事已经协助运维已经把这一套系统部署好了,测试人员已经准备开始压测了。

该项目拓扑图大致如下:

nginx负载均衡,每一组nginx对应两个门户集群,每个门户对应三个服务集群

log4j2.xml设置

之前测试人员在群里发了错误需要排查,我大概晚些进入群和测试人员有一个"时间差",之后同事转发测试人员在群里发的信息让我排查。我确定好nginx组以及对应的具体三个服务ip,开始去查看错误日志。尴尬的是我没有找到测试人员说的那个错误日志。

我反馈之后,测试人员复现了一波操作,我查看了error日志看到了。之后过了一会发现又没了?其实这些日志都以每10M rolling,为了方便排查更改了log4j2的设置,每100M rolling。

雪花生成的主键产生了冲突

"org.springframework.dao.DuplicateKeyException Error updateing database"

"Duplicate entry 'XXXXXX' for key 'PRIMARY' "

主键冲突了,我查看了数据库对应的表,搜索'XXXXXX'还真的存在,查看代码了解该主键是利用雪花工具类生成的。

该类初始化的时候根据获取系统读取SF_WORK_ID和SF_DATACENTER_ID,然后调用hutool包初始化雪花类。之后实现调用生成。

网上了解了一些雪花原理,分布式系统中使用全局唯一ID的场景(一组集群3台服务,有多组都是连同一个数据库),通常这样我们会使用雪花。workerId要设置不同,否则高并发的情况下会出现主键ID重复。

解决

" cat ehcServer-info*.log | grep "雪花算法配置" "

系统初始化的时候会初始化话雪花类,到每台服务查看日志配置之后发现每台都是1,之后同事让运维人员配置相关SF_WORK_ID,每台Linux的SF_WORK_ID都不同

解决之后,测试再压测就不会有这个错误了

雪花ID

为什么使用雪花ID

可以阅读这篇文章 juejin.cn/post/696551…

最常见的两种主键类型是自增Id和UUID,自增id容易导致主键重复,UUID会有无序的问题。

雪花ID就是一种会具有唯一ID,有序的。

雪花ID介绍

SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图:

  • 1位,不用。二进制中最高位为1的都是负数,但是我们生成的id一般都使用整数,所以这个最高位固定是0

  • 41位,用来记录时间戳(毫秒)。

    • 41位可以表示 2^{41}-1 个数字,
    • 如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 2^{41}-1,减1是因为可表示的数值范围是从0开始算的,而不是1。
    • 也就是说41位可以表示 2^{41}-1 个毫秒的值,转化成单位年则是 (2^{41}-1) / (1000 * 60 * 60 * 24 * 365) = 69 年
  • 10位,用来记录工作机器id。

    • 可以部署在 2^{10} = 1024 个节点,包括 5位 datacenterId 和 5位 workerId
    • 5位(bit)可以表示的最大正整数是 2^{5}-1 = 31 ,即可以用 0、1、2、3、....31 这 32 个数字,来表示不同的 datecenterId 或 workerId
  • 12位,序列号,用来记录同毫秒内产生的不同id。

    • 12位(bit)可以表示的最大正整数是 2^{12}-1 = 4095 ,即可以用 0、1、2、3、....4094 这 4095 个数字,来表示同一机器同一时间截(毫秒)内产生的 4095 个 ID 序号。

创建雪花

像前面提到的,系统启动的时候会自动初始化雪花,而创建雪花依赖的就是

datacenterId(终端ID) 和 workerId(终端ID),设置不能超过32(2的5次方)

static {    String sfWorkId = getEnvValue("SF_WORK_ID", "1");    String sfDataCenterId = getEnvValue("SF_DATACENTER_ID", "1");    log.info("雪花算法配置SF_WORK_ID:{}, SF_DATACENTER_ID:{}", sfWorkId, sfDataCenterId);    snowFlakeWorkId = Long.parseLong(sfWorkId);    snowFlakeDataCenterId = Long.parseLong(sfDataCenterId);    s = new Snowflake(snowFlakeWorkId, snowFlakeDataCenterId);}
复制代码

雪花优点

同一台服务器所有生成的id按时间趋势递增

整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)

雪花缺点

分布式部署的时候会使用相同的配置datacenterId和workerId,任然有ID重复的风险。(针对相同配置的情况本文也有提到,保证配置不一样即可。生产的集群加起来总共15台(小于32))

强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。(这点在正常情况下是不会发生的)

雪花util

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值