[英]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.