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

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

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

相关推荐
L.EscaRC3 小时前
Spring Security的解析与应用
spring boot·spring
Lei活在当下7 小时前
【现代 Android APP 架构】09. 聊一聊依赖注入在 Android 开发中的应用
java·架构·android jetpack
一尘之中8 小时前
【架构人生】一种“低耦合、高内聚”的处世哲学
架构·ai写作
小雨的光8 小时前
QuickEsView
spring boot·elasticsearch·es可视化
韩立学长9 小时前
基于Springboot的旧物公益捐赠管理系统3726v22v(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
Dyan_csdn9 小时前
springboot系统设计选题3
java·spring boot·后端
小雨的光11 小时前
QuickActuator
spring boot·actuator·实例监控
chxii11 小时前
Spring Boot 中,内嵌的 Servlet 容器(也称为嵌入式 Web 服务器)
spring boot·servlet
李白的粉13 小时前
基于springboot的新闻资讯系统
java·spring boot·毕业设计·课程设计·源代码·新闻资讯系统
摆烂工程师13 小时前
(2025年11月)开发了 ChatGPT 导出聊天记录的插件,ChatGPT Free、Plus、Business、Team 等用户都可用
前端·后端·程序员