前言
这周同事把我拉进一个压测群,让我配合压测服务,主要是排查日志配合测试、运维人员压测。之后给了我项目资料,服务器信息,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))
强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。(这点在正常情况下是不会发生的)