跳到正文
产品桌面工具TASTECAD图纸查看TASTEFILES文件管理TASTEFTP文件传输TASTESSH远程工作空间TASTEZIP压缩与解压开发工具TASTECODERust 集成开发环境TASTESTUDIO集成开发与测试环境TASTEETL数据整合(ETL)服务器TASTEREMOTE远程桌面服务器TASTEGEO空间信息服务器TASTEMAIL邮件工作空间开始使用下载文档购买全部产品
市场
资讯
技术资讯今日开发资讯开发文档编程语言RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDartWeb 前端框架Next.jsReactVue.js · NuxtSvelteKitAngular服务端框架Spring BootDjangoFastAPIASP.NET CoreNestJS · Express应用与桌面框架TauriFlutterReact NativeElectron算法算法基础核心算法进阶算法实用算法
社区项目开发日志提示词AI 工具问题作品展示社区指南
合作技术传授网站构建桌面应用构建发布与支付流水线销售合作伙伴联系我们
服务远程桌面安装包定制
TASTEDEV
产品

桌面工具

TASTECAD复杂图纸,轻松打开TASTEFILES只要需要的文件,最快送达TASTEFTP让文件往来,干净利落TASTESSH你与服务器之间,连接更牢靠TASTEZIP压得更快,解得更稳

开发工具

TASTECODE在一个窗口中完成 Rust 应用的编辑、构建、调试和测试TASTESTUDIO从编辑到远程测试,再到经批准的 AI 修复TASTEETL边看数值,边搬数据

服务器

TASTEREMOTE在自己的服务器上运行的远程桌面TASTEGEO用 Rust 重新构建兼容 GeoServer 的空间信息服务器TASTEMAIL把邮件的主导权拿回自己手中

开始使用

下载所有产品的最新版本文档各产品使用方法购买订阅与永久许可全部产品一览全部产品
全部产品
市场资讯
技术

资讯

今日开发资讯语言、框架、GitHub 与 AI 官方发布开发文档语言、框架与算法指南

编程语言

RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart

框架

Web 前端框架Next.jsReactVue.js · NuxtSvelteKitAngular
服务端框架Spring BootDjangoFastAPIASP.NET CoreNestJS · Express
应用与桌面框架TauriFlutterReact NativeElectron

算法

算法基础复杂度分析 · 排序 · 查找 · 基础数据结构 · 树与堆核心算法图遍历 · 最短路径与最小生成树 · 动态规划 · 贪心算法 · 分治法 · 回溯法进阶算法字符串算法 · 数学与数论 · 位运算 · 线段树 · 并查集实用算法编程面试解题策略 · LRU 缓存 · 限流 · 一致性哈希
查看全部开发文档
社区
项目发现开发者与作品开发日志决策与试错提示词可复用的指令AI 工具问题Claude、Codex、Gemini 的问题与变通办法作品展示已完成的成果社区指南我们如何公开构建
合作
技术传授用 Rust 和 egui 打造原生应用网站构建10 种语言、账户、文档与下载桌面应用构建Rust 和 egui,不用 WebView发布与支付流水线签名、MSI、deb、rpm、AppImage、哈希销售合作伙伴推荐即得 30%联系我们开发、合作与投资咨询
服务
远程桌面用浏览器连接你的电脑安装包定制只装需要的,设置预先放好
购买
ZH
한국어EnglishDeutschEspañolFrançaisItalianoPortuguês (Brasil)日本語简体中文繁體中文
登录
登录
TASTEDEV

从小工具到更好的开发。

support@tastedev.net支持 TASTEDEV
产品产品线购买文档下载市场客户支持
社区项目开发日志提示词AI 工具问题作品展示
政策隐私政策服务条款订阅条款退款政策社区规范
账户登录注册
访客
今天
012345678901234567890123456789012345678901234567890123456789
昨天
012345678901234567890123456789012345678901234567890123456789
累计浏览
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
公司名称
GXSOFT
法定代表人
CHOI YOUNG GU
营业执照号
853-44-00368
地址
9F V24, 351 Gyeongin-ro, Michuhol-gu, Incheon, Republic of Korea
电话
+82-10-4404-1523
电子邮件
whitecalvin@tastedev.net
个人信息保护负责人
CHOI YOUNG GU

© 2026 TASTEDEV产品信息以已验证的开发源码为准。已发布·持续改进

一致性哈希 文档
一致性哈希
Consistent hashing conceptsHow it worksImplementationComplexityPractice problemsReal-world use
讨论

一致性哈希 指南 · 3/6

Implementation

本章目前仅提供英文版。

A hash ring with virtual nodes on Python's bisect, ported to C++, Java and TypeScript. Sharing one hash, all four agree on every key.

Python

Avoid the built-in hash(): string hashing is randomized per process. We use 64-bit FNV-1a plus MurmurHash3's fmix64 finalizer to spread similar names like node#1.

import bisect

MASK = (1 << 64) - 1


def hash64(text: str) -> int:
    x = 0xCBF29CE484222325  # FNV-1a offset basis
    for b in text.encode("utf-8"):
        x = ((x ^ b) * 0x100000001B3) & MASK
    x ^= x >> 33  # fmix64 finalizer
    x = (x * 0xFF51AFD7ED558CCD) & MASK
    x ^= x >> 33
    x = (x * 0xC4CEB9FE1A85EC53) & MASK
    return x ^ (x >> 33)


class HashRing:
    def __init__(self, vnodes: int = 100):
        self.vnodes = vnodes
        self.points: list[int] = []  # sorted positions
        self.owner: dict[int, str] = {}  # position -> node

    def add(self, node: str) -> None:
        for i in range(self.vnodes):
            p = hash64(f"{node}#{i}")
            bisect.insort(self.points, p)
            self.owner[p] = node

    def remove(self, node: str) -> None:
        for i in range(self.vnodes):
            p = hash64(f"{node}#{i}")
            del self.owner[p]
            self.points.pop(bisect.bisect_left(self.points, p))

    def get(self, key: str) -> str:
        if not self.points:
            raise LookupError("ring is empty")
        i = bisect.bisect_left(self.points, hash64(key))
        if i == len(self.points):  # wrap around
            i = 0
        return self.owner[self.points[i]]
  • hash64: XOR each byte, multiply by the FNV prime, keep 64 bits with & MASK.
  • points, owner: sorted positions and a position-to-node map.
  • add: derives vnode positions from node#i and keeps them sorted via insort.
  • remove: recomputes the same positions, so nothing per node is stored. (64-bit collisions are negligible and ignored.)
  • get: bisect_left finds the first point at or after the key; past the end, wrap.

C++

std::map is sorted, so lower_bound is the clockwise search.

#include <cstdint>
#include <map>
#include <stdexcept>
#include <string>

std::uint64_t hash64(const std::string& text) {
    std::uint64_t x = 0xCBF29CE484222325ULL;
    for (unsigned char b : text) x = (x ^ b) * 0x100000001B3ULL;
    x ^= x >> 33; x *= 0xFF51AFD7ED558CCDULL;
    x ^= x >> 33; x *= 0xC4CEB9FE1A85EC53ULL;
    return x ^ (x >> 33);
}

class HashRing {
public:
    explicit HashRing(int vnodes = 100) : vnodes_(vnodes) {}
    void add(const std::string& node) {
        for (int i = 0; i < vnodes_; ++i) ring_[hash64(node + "#" + std::to_string(i))] = node;
    }
    void remove(const std::string& node) {
        for (int i = 0; i < vnodes_; ++i) ring_.erase(hash64(node + "#" + std::to_string(i)));
    }
    const std::string& get(const std::string& key) const {
        if (ring_.empty()) throw std::runtime_error("ring is empty");
        auto it = ring_.lower_bound(hash64(key));
        return (it == ring_.end() ? ring_.begin() : it)->second;
    }
private:
    int vnodes_;
    std::map<std::uint64_t, std::string> ring_;
};
对本章有疑问?
上一章How it works下一章Complexity

Java

No unsigned long, so the TreeMap uses Long::compareUnsigned; ceilingEntry does the search.

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;

public class HashRing {
    private final int vnodes;
    private final TreeMap<Long, String> ring = new TreeMap<>(Long::compareUnsigned);

    public HashRing(int vnodes) { this.vnodes = vnodes; }

    static long hash64(String text) {
        long x = 0xCBF29CE484222325L;
        for (byte b : text.getBytes(StandardCharsets.UTF_8)) x = (x ^ (b & 0xFF)) * 0x100000001B3L;
        x ^= x >>> 33; x *= 0xFF51AFD7ED558CCDL;
        x ^= x >>> 33; x *= 0xC4CEB9FE1A85EC53L;
        return x ^ (x >>> 33);
    }

    public void add(String node) {
        for (int i = 0; i < vnodes; i++) ring.put(hash64(node + "#" + i), node);
    }

    public void remove(String node) {
        for (int i = 0; i < vnodes; i++) ring.remove(hash64(node + "#" + i));
    }

    public String get(String key) {
        if (ring.isEmpty()) throw new IllegalStateException("ring is empty");
        Map.Entry<Long, String> e = ring.ceilingEntry(hash64(key));
        return (e != null ? e : ring.firstEntry()).getValue();
    }
}

TypeScript

bigint covers 64-bit math; the binary search is hand-written.

const MASK = (1n << 64n) - 1n;

function hash64(text: string): bigint {
  let x = 0xcbf29ce484222325n;
  for (const b of new TextEncoder().encode(text)) x = ((x ^ BigInt(b)) * 0x100000001b3n) & MASK;
  x ^= x >> 33n; x = (x * 0xff51afd7ed558ccdn) & MASK;
  x ^= x >> 33n; x = (x * 0xc4ceb9fe1a85ec53n) & MASK;
  return x ^ (x >> 33n);
}

class HashRing {
  private points: bigint[] = [];
  private owner = new Map<bigint, string>();
  constructor(private readonly vnodes = 100) {}

  private lowerBound(h: bigint): number {
    let lo = 0, hi = this.points.length;
    while (lo < hi) {
      const mid = (lo + hi) >> 1;
      if (this.points[mid] < h) lo = mid + 1; else hi = mid;
    }
    return lo;
  }
  add(node: string): void {
    for (let i = 0; i < this.vnodes; i++) {
      const p = hash64(`${node}#${i}`);
      this.points.splice(this.lowerBound(p), 0, p);
      this.owner.set(p, node);
    }
  }
  remove(node: string): void {
    for (let i = 0; i < this.vnodes; i++) {
      const p = hash64(`${node}#${i}`);
      if (this.owner.delete(p)) this.points.splice(this.lowerBound(p), 1);
    }
  }
  get(key: string): string {
    if (this.points.length === 0) throw new Error("ring is empty");
    const i = this.lowerBound(hash64(key));
    return this.owner.get(this.points[i === this.points.length ? 0 : i])!;
  }
}

Summary

  • A ring is sorted positions plus owners.
  • Lookup: first position at or after the key, wrapping at the end.
  • Sorted trees make point insertion and deletion O(log n).

0 条评论

热门评论最新优先

登录 · 登录后即可发表评论。