1、初始化服务id
@Bean("serviceInstanceId")
public String serviceInstanceId() {
return UUID.randomUUID().toString() ;
}
2、编写分片逻辑
@Component
@Slf4j
public class ServiceRegister {
@Autowired
private String serviceInstanceId;
@Autowired
private RedisCache redisCache;
@Value("${ENVIRONMENT:dev}")
private String env;
public static final String REGISTER_KEY = "service:register:";
/**
* 每5秒设置一下过期时间,作为心跳处理
*/
@Scheduled(cron = "*/5 * * * * ?")
@Async
void extend() {
log.debug("进行服务实例{}的续约", serviceInstanceId);
if(Boolean.FALSE.equals(redisCache.hasKey(serviceInstanceId))){
log.warn("{}不存在重新注册", serviceInstanceId);
register();
}
redisCache.expire(serviceInstanceId, 10);
}
/**
* 获取分片信息
*
* @return
*/
public SharedInfo getSharedInfo() {
eliminateOffline();
int total = redisCache.zcard(ServiceRegister.REGISTER_KEY + env).intValue();
int index = redisCache.zRank(ServiceRegister.REGISTER_KEY + env, serviceInstanceId).intValue();
log.info("SharedInfo total is {}, index is {} ", total, index);
return new SharedInfo(total, index);
}
/**
* 服务实例的注册
*/
private void register() {
log.info("进行服务实例{}的注册", serviceInstanceId);
// 设置实例
redisCache.setex(serviceInstanceId, String.valueOf(System.currentTimeMillis()), 30);
// 增加到列表
redisCache.zadd(REGISTER_KEY + env, serviceInstanceId, System.currentTimeMillis());
}
/**
* 剔除下线实例
*/
private void eliminateOffline() {
Set<String> services = redisCache.zrevrange(REGISTER_KEY + env, 0, -1);
for (String service : services) {
if (Boolean.FALSE.equals(redisCache.hasKey(service))) {
log.warn("服务实例下线{}", service);
redisCache.zremove(REGISTER_KEY + env, service);
}
}
}
public boolean belongMyself(Long id, int total, int index) {
// 只有一个分片,全部处理
if (total <= 1) {
return true;
}
// 解决取模可能为负数的情况
int hash = id.hashCode() & Integer.MAX_VALUE;
return hash % total == index;
}
@Data
@AllArgsConstructor
public class SharedInfo {
/**
* 总分片数
*/
private int total;
/**
* 分片索引
*/
private int index;
}
}
评论区