哈希环的虚拟节点简单场景使用

关于哈希环的虚拟节点,可以考虑一个分布式缓存的场景。在这个场景中,我们使用Spring Boot搭建一个简单的分布式缓存系统,采用哈希环来分配缓存请求。

场景描述

假设我们有多个缓存服务器,需要均匀地分配缓存请求。使用哈希环和虚拟节点的方式,可以有效地处理服务器的动态增加或减少。

代码示例

  1. 引入依赖

    xml 复制代码
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  2. 哈希环实现

    java 复制代码
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import java.util.SortedMap;
    import java.util.TreeMap;
    
    public class ConsistentHashing {
        private final SortedMap<Integer, String> circle = new TreeMap<>();
        private final int VIRTUAL_NODES = 5;
    
        public void addNode(String node) {
            for (int i = 0; i < VIRTUAL_NODES; i++) {
                int hash = getHash(node + i);
                circle.put(hash, node);
            }
        }
    
        public void removeNode(String node) {
            for (int i = 0; i < VIRTUAL_NODES; i++) {
                int hash = getHash(node + i);
                circle.remove(hash);
            }
        }
    
        public String getNode(String key) {
            if (circle.isEmpty()) return null;
            int hash = getHash(key);
            SortedMap<Integer, String> tailMap = circle.tailMap(hash);
            Integer nodeHash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
            return circle.get(nodeHash);
        }
    
        private int getHash(String key) {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] digest = md.digest(key.getBytes(StandardCharsets.UTF_8));
                return Math.abs(java.util.Arrays.hashCode(digest));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
  3. 控制器示例

    java 复制代码
    import org.springframework.web.bind.annotation.*;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @RestController
    @RequestMapping("/cache")
    public class CacheController {
        private final ConsistentHashing consistentHashing = new ConsistentHashing();
        private final List<String> nodes = new ArrayList<>();
    
        @PostMapping("/addNode")
        public String addNode(@RequestParam String node) {
            consistentHashing.addNode(node);
            nodes.add(node);
            return "Node added: " + node;
        }
    
        @PostMapping("/removeNode")
        public String removeNode(@RequestParam String node) {
            consistentHashing.removeNode(node);
            nodes.remove(node);
            return "Node removed: " + node;
        }
    
        @GetMapping("/getNode")
        public String getNode(@RequestParam String key) {
            return "Key " + key + " is routed to node: " + consistentHashing.getNode(key);
        }
    }

使用说明

  • 启动Spring Boot应用后,可以通过POST请求添加或移除节点,并通过GET请求获取某个键对应的节点。

这个示例通过哈希环和虚拟节点实现了简单的负载均衡,接下来进一步扩展和优化。

我们可以扩展这个分布式缓存场景,加入以下复杂性:

  1. 多种数据类型支持:缓存支持字符串、对象等多种数据类型。
  2. 过期策略:实现缓存的过期机制。
  3. 集群节点状态监控:对节点状态进行健康检查,自动从哈希环中移除失效节点。
  4. 负载均衡算法:支持不同的负载均衡策略,比如轮询和随机。

代码示例扩展

  1. 缓存数据结构

    java 复制代码
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;
    
    public class Cache {
        private final ConcurrentMap<String, CacheItem> cache = new ConcurrentHashMap<>();
    
        public void put(String key, Object value, long ttl) {
            long expiryTime = System.currentTimeMillis() + ttl;
            cache.put(key, new CacheItem(value, expiryTime));
        }
    
        public Object get(String key) {
            CacheItem item = cache.get(key);
            if (item != null && System.currentTimeMillis() < item.expiryTime) {
                return item.value;
            }
            cache.remove(key);
            return null;
        }
    
        private static class CacheItem {
            Object value;
            long expiryTime;
    
            CacheItem(Object value, long expiryTime) {
                this.value = value;
                this.expiryTime = expiryTime;
            }
        }
    }
  2. 集群状态监控

    java 复制代码
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class NodeHealthMonitor {
        private final ConsistentHashing hashing;
        private final Timer timer = new Timer();
    
        public NodeHealthMonitor(ConsistentHashing hashing) {
            this.hashing = hashing;
            startMonitoring();
        }
    
        private void startMonitoring() {
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    // 健康检查逻辑,移除失效节点
                    for (String node : hashing.getNodes()) {
                        if (!isHealthy(node)) {
                            hashing.removeNode(node);
                        }
                    }
                }
            }, 0, 60000); // 每分钟检查一次
        }
    
        private boolean isHealthy(String node) {
            // 假设的健康检查逻辑
            return true; // 实际逻辑需实现
        }
    }
  3. 控制器更新

    java 复制代码
    @RestController
    @RequestMapping("/cache")
    public class CacheController {
        private final ConsistentHashing consistentHashing = new ConsistentHashing();
        private final Cache cache = new Cache();
        private final NodeHealthMonitor healthMonitor = new NodeHealthMonitor(consistentHashing);
    
        @PostMapping("/addNode")
        public String addNode(@RequestParam String node) {
            consistentHashing.addNode(node);
            return "Node added: " + node;
        }
    
        @PostMapping("/removeNode")
        public String removeNode(@RequestParam String node) {
            consistentHashing.removeNode(node);
            return "Node removed: " + node;
        }
    
        @PostMapping("/put")
        public String put(@RequestParam String key, @RequestParam String value, @RequestParam long ttl) {
            String node = consistentHashing.getNode(key);
            cache.put(key, value, ttl);
            return "Stored in node: " + node;
        }
    
        @GetMapping("/get")
        public String get(@RequestParam String key) {
            Object value = cache.get(key);
            return value != null ? "Value: " + value : "Value not found or expired";
        }
    }

使用说明

  • 添加节点 :使用 /cache/addNode
  • 存储缓存 :使用 /cache/put,并设置过期时间。
  • 获取缓存 :使用 /cache/get,获取值或确认过期。

这种设计让系统更复杂、更健壮。

相关推荐
java—大象7 分钟前
基于Java+Jsp+SpringMVC漫威手办商城系统设计和实现
java·数据库·spring boot·python·课程设计
A仔不会笑1 小时前
微服务配置管理——动态路由
微服务·云原生·架构
弥琉撒到我2 小时前
微服务MongoDB解析部署使用全流程
mongodb·spring cloud·微服务·架构
山语山2 小时前
网络安全的方方面面
网络·安全·架构·人机交互·安全架构
IT学长编程2 小时前
计算机毕业设计 校运会管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·校园会管理系统
无惧代码2 小时前
实现quartz定时任务控制是否启动 (生产环境 和 开发环境)
java·spring boot·spring
小旋风-java2 小时前
springboot整合dwr
java·spring boot·后端·dwr
听潮阁3 小时前
【SpringBoot详细教程】-05-整合Druid操作数据库【持续更新】
数据库·spring boot·后端
弥琉撒到我3 小时前
微服务SpringSession解析部署使用全流程
spring cloud·微服务·云原生·架构·springsession
gobeyye3 小时前
SpringBoot | Maven快速上手
spring boot·后端·maven