Distrings 1.0.0

dotnet add package Distrings --version 1.0.0
NuGet\Install-Package Distrings -Version 1.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Distrings" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Distrings --version 1.0.0
#r "nuget: Distrings, 1.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Distrings as a Cake Addin
#addin nuget:?package=Distrings&version=1.0.0

// Install Distrings as a Cake Tool
#tool nuget:?package=Distrings&version=1.0.0

Distrings Nuget

Distrings

<img src="https://raw.githubusercontent.com/krasin-ga/distrings/main/assets/distrings.svg" align="right" /> Distrings is a .NET library for constructing a hash ring based on a specified set of nodes. The primary use of hash ringing includes distributing workload among nodes in a distributed system and implementing algorithms for mapping keys to nodes (e.g., session affinity).

Key Features

  • Flexibility: All components are customizable, facilitating easy adaptation of the ring mechanism to the architecture and infrastructure of the target project.
  • Clarity: Each node is assigned key ranges, enabling the assessment of the resulting distribution against the desired one.
  • Weighted Nodes: Nodes can have individual weights, enabling fine-grained control over their impact on share distribution within the hash ring.
  • Multiple Node Selection: It is possible to select multiple unique nodes at once (e.g., for replication).

Core Building Blocks

INode: Node, consisting of an identifier and weight.

IRingConfiguration: Allows adjusting the size of the ring.

IHashAlgorithm: Hashing algorithm.

IPartitioningStrategy: Strategy that divides the given set of nodes into segments and assigns hash ranges to them.

Built-in Implementations

  • ConsistentHashing: A well-known consistent hashing algorithm. Node weight maps to the number of virtual nodes.
  • PingPong: Ensures even distribution and minimal redistribution but expects nodes to be added in increasing order.

ILookUpStrategy: Strategy for locating nodes on the ring.

Built-in Implementations

  • BinarySearch: Uses binary search and allows finding a node in O(log(N)).

  • MemoryLookup: Requires a constrained ring size and stores all slots in memory, enabling efficient node retrieval in O(1) time.

Getting Started

Installation

You can install the library in your project using the following command:

dotnet add package Distrings

Usage Example

In the example below, a ring of three nodes is created using the consistent hashing algorithm and employs binary search to locate nodes by hash. XXHash is used as the hashing algorithm, which is also used for calculating the hash of string and integer keys and selecting nodes based on this key.

using Distrings;
//...

public static class ExampleOfUsage
{
    public static void RunExample()
    {
        var nodes = new[]
        {
            new Node(Identity: "node_01", Weight: 10),
            new Node(Identity: "node_02", Weight: 10),
            new Node(Identity: "node_03", Weight: 30)
        };

        var hashAlgorithm = new XxHashAlgorithm();

        var ring = new HashRingBuilder<Node>(RingConfiguration.Default)
                    .PartitionWith(t => t.ConsistentHashing(hashAlgorithm))
                    .LookupWith(l => l.BinarySearch())
                    .CreateRing(nodes);

        Console.WriteLine(ring);

        var userNode = GetNodeByString(
            stringId: "user@example.com",
            hashAlgorithm,
            ring);

        Console.WriteLine(userNode);

        var idNode = GetNodeByULong(
            id: 10202UL,
            hashAlgorithm,
            ring);

        Console.WriteLine(idNode);
    }

    private static Node GetNodeByString(
        string stringId,
        IHashAlgorithm hashAlgorithm,
        HashRing<Node> ring)
    {
        var maxByteCount = Encoding.UTF8.GetMaxByteCount(stringId.Length);

        const int maxBytesOnStack = 128;
        var userIdBytes = maxByteCount <= maxBytesOnStack
        ? stackalloc byte[maxBytesOnStack]
        : new byte[maxByteCount];

        userIdBytes = userIdBytes[..Encoding.UTF8.GetBytes(stringId, userIdBytes)];
        var userIdHash = hashAlgorithm.CalculateHashCode(userIdBytes);

        return ring.GetNode(hashCode: userIdHash);
    }

    private static Node GetNodeByULong(
        ulong id,
        IHashAlgorithm hashAlgorithm,
        HashRing<Node> ring)
    {
        Span<byte> itemIdBytes = stackalloc byte[8];
        BitConverter.TryWriteBytes(itemIdBytes, id);
        var userIdHash = hashAlgorithm.CalculateHashCode(itemIdBytes);

        return ring.GetNode(hashCode: userIdHash);
    }
}


public class XxHashAlgorithm : IHashAlgorithm
{
    public ulong CalculateHashCode(ReadOnlySpan<byte> bytes)
    {
        Span<byte> destination = stackalloc byte[8];

        //from System.IO.Hashing NugetPackage 
        System.IO.Hashing.XxHash64.Hash(bytes, destination);

        return BitConverter.ToUInt64(destination);
    }
}

Notes:

  1. In practice, hashing algorithms for nodes and keys can be different
  2. It is not recommended to use plain auto-incrementing integer keys for node selection, as this would result in uneven node selection. Instead, it is suggested to use hashed values for key selection
  3. For consistency, all ring parameters should be the same across all application instances

License

This project is licensed under the MIT license.

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net5.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0 120 1/21/2024