微服务分片算法

过去的,未来的
2024-02-20 / 0 评论 / 0 点赞 / 81 阅读 / 335 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-02-20,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

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;
    }
}

0

评论区