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

关于哈希环的虚拟节点,可以考虑一个分布式缓存的场景。在这个场景中,我们使用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,获取值或确认过期。

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

相关推荐
AI大模型9 小时前
GitHub 狂飙 72k Star,这本大模型书凭啥能圈粉无数?
程序员·llm·agent
考虑考虑11 小时前
Jpa使用union all
java·spring boot·后端
大模型教程13 小时前
小白学大模型:从零搭建LLaMA
程序员·llm·llama
AI大模型13 小时前
一篇文章看懂RAG + 实战,看不懂来揍我
程序员·llm·agent
稻草人222214 小时前
java Excel 导出 ,如何实现八倍效率优化,以及代码分层,方法封装
后端·架构
数据智能老司机15 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机16 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
程序员鱼皮19 小时前
刚刚 Java 25 炸裂发布!让 Java 再次伟大
java·javascript·计算机·程序员·编程·开发·代码
SimonKing19 小时前
接口调用总失败?试试Spring官方重试框架Spring-Retry
java·后端·程序员