一致性 Hash 算法

1. 参考文章

  • 一致性 Hash 算法分析
  • 一致性 Hash 算法详解

2. 示例代码

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 一致性 Hash 实现
 */
class ConsistentHash {

    private final SortedMap hashNodesMap    = new TreeMap<>();
    private final Map        virtualNodesMap = new HashMap<>();

    /**
     * @param nodeKeys 节点 key 列表
     * @param virtualNodeCount 虚拟节点数量, 提升 Hash 均衡性
     */
    public ConsistentHash(List nodeKeys, int virtualNodeCount) {
        for (String nodeKey : nodeKeys) {
            addNode(nodeKey);
        }

        final int nodeCount = nodeKeys.size();
        for (int i = 0; i < virtualNodeCount; ++i) {
            String nodeKey = nodeKeys.get(i % nodeCount);
            String virtualNodeKey = String.format("VirtualNode_%s_%s", nodeKey, i);

            addNode(virtualNodeKey);
            virtualNodesMap.put(virtualNodeKey, nodeKey);
        }
    }

    /**
     * 获取对应的 key
     */
    public String getNodeKey(String accessKey) {
        int hash = bkdHash(accessKey);

        SortedMap tailMap = hashNodesMap.tailMap(hash);
        if (tailMap.isEmpty()) {
            tailMap = hashNodesMap;
        }

        String nodeKey = tailMap.get(tailMap.firstKey());
        String realNodeKey = virtualNodesMap.get(nodeKey);

        return realNodeKey != null ? realNodeKey : nodeKey;
    }

    /**
     * 添加节点
     */
    private void addNode(String nodeKey) {
        hashNodesMap.put(bkdHash(nodeKey), nodeKey);
    }

    /**
     * BKD hash 算法实现
     */
    private static int bkdHash(String value) {
        final int seed = 31;

        int hash = 0;
        value = md5(value);
        for (int i = 0; i != value.length(); ++i) {
            hash = seed * hash + value.charAt(i);
        }

        return hash;
    }

    /**
     * MD5 算法
     */
    private static String md5(String value) {
        byte[] bytes = value.getBytes();

        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            bytes = md5.digest(bytes);

            StringBuilder builder = new StringBuilder();
            for (byte b : bytes) {
                String temp = Integer.toHexString(b & 255);
                if (temp.length() == 1) {
                    builder.append('0');
                }

                builder.append(temp);
            }

            return builder.toString();
        } catch (NoSuchAlgorithmException var8) {
            var8.printStackTrace();
        }

        return "";
    }
}

/**
 * 一致性 Hash Demo
 */
public class ConsistentHashDemo {

    public static void main(String[] args) {
        List nodes = new ArrayList<>();
        nodes.add("10.234.23.135");
        nodes.add("10.234.23.136");
        nodes.add("10.234.23.137");
        nodes.add("10.234.23.138");

        ConsistentHash hash = new ConsistentHash(nodes, 8);

        printServerIp(hash, "0b91c015160325042515067851893");
        printServerIp(hash, "0b91c015160325042594167881893");
        printServerIp(hash, "0b91c015160325049004068161893");
        printServerIp(hash, "0b91c015160325064717068581893");
    }

    private static void printServerIp(ConsistentHash hash, String accessKey) {
        System.out.println(String.format("%s - %s", accessKey, hash.getNodeKey(accessKey)));
    }
}

运行结果:

0b91c015160325042515067851893 - 10.234.23.135
0b91c015160325042594167881893 - 10.234.23.136
0b91c015160325049004068161893 - 10.234.23.136
0b91c015160325064717068581893 - 10.234.23.137

你可能感兴趣的:(一致性 Hash 算法)