簡體   English   中英

如何在Java中實現ketama算法?

[英]How to implement the ketama algorithm in java?

我們將nginx用作負載平衡器,並根據URL的第一部分和一致的哈希來分配負載。 這很好。 對/ abc /的請求始終會轉到同一節點。

在我的節點上,我也想實現此算法。 (需要讓一些作業在這些節點上運行並使用一些預加載的緩存元素)

所以我需要Nginx ketama算法的Java實現。

我發現了一些:

這些算法均無法產生與nginx相同的結果。 這可能是由於Nginx文檔中描述的一些ketama點或哈希算法的某些差異。

我在這里找到了nginx哈希算法: https : //github.com/nginx/nginx/blob/53d655f89407af017cd193fd4d8d82118c9c2c80/src/stream/ngx_stream_upstream_hash_module.c#L279

當我比較兩者時,除了很多其他區別外,我看到java使用的是md5,nginx使用的是crc32。

Java中是否有兼容的實現? 還是有關於ketama算法的定義明確的文檔?

該代碼對我有用。 它不是防彈的,因為它沒有考慮重量或其他因素(例如刪除節點)。 如果您喜歡使用它,則代碼是公共域。

package org.kicktipp.ketama;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.zip.CRC32;

public class NginxKetamaConsistentHash
{
    private final int                       KETAMA_POINTS   = 160;
    private final SortedMap<Long, String>   circle          = new TreeMap<>();

    public NginxKetamaConsistentHash ( List<String> nodes )
    {
        for (String node : nodes)
        {
            addNode(node);
        }
    }

    public String get ( String key )
    {
        if (circle.isEmpty())
        {
            return null;
        }
        long hash = getCrc32(key);
        if (!circle.containsKey(hash))
        {
            SortedMap<Long, String> tailMap = circle.tailMap(hash);
            hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
        }
        return circle.get(hash);
    }

    private void addNode ( String node )
    {
        String server = node;
        String port = "";
        if (node.contains(":"))
        {
            String[] split = node.split(":", 2);
            server = split[0];
            port = split[1];
        }
        byte[] prevHash = new byte[4];
        for (int i = 0; i < KETAMA_POINTS; i++)
        {
            CRC32 hash = getBaseHash(server, port);
            hash.update(prevHash);
            long value = hash.getValue();
            circle.put(value, node);
            prevHash = getPrevHash(value);
        }
    }

    private byte[] getPrevHash ( long value )
    {
        byte[] array = Arrays.copyOfRange(longToBytes(value), 4, 8);
        for (int i = 0; i < array.length / 2; i++)
        {
            byte temp = array[i];
            array[i] = array[array.length - i - 1];
            array[array.length - i - 1] = temp;
        }
        return array;
    }

    private CRC32 getBaseHash ( String server, String port )
    {
        CRC32 baseHash = new CRC32();
        baseHash.update(server.getBytes(StandardCharsets.US_ASCII));
        baseHash.update("\0".getBytes(StandardCharsets.US_ASCII));
        baseHash.update(port.getBytes(StandardCharsets.US_ASCII));
        return baseHash;
    }

    private byte[] longToBytes ( long x )
    {
        ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
        buffer.putLong(x);
        return buffer.array();
    }

    private long getCrc32 ( final String k )
    {
        CRC32 hash = new CRC32();
        hash.update(k.getBytes());
        return hash.getValue();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM