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

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

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

相关推荐
哎呦没22 分钟前
SpringBoot框架下的资产管理自动化
java·spring boot·后端
2401_8576009525 分钟前
SpringBoot框架的企业资产管理自动化
spring boot·后端·自动化
NiNg_1_2344 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
种树人202408194 小时前
如何在 Spring Boot 中启用定时任务
spring boot
苹果醋37 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
Wx-bishekaifayuan8 小时前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava
customer088 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
Yaml49 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
LuckyLay9 小时前
Spring学习笔记_27——@EnableLoadTimeWeaving
java·spring boot·spring
佳佳_10 小时前
Spring Boot 应用启动时打印配置类信息
spring boot·后端