Golang HRW implementation
Evgenii Stratonikov
213c105ac1
Specifically, this line became possible, because of noescape annotations for assembly. ``` ./hrw.go:307:14: make([]byte, 8) does not escape ``` ``` goos: linux goarch: amd64 pkg: git.frostfs.info/TrueCloudLab/hrw cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz │ 1 │ 2 │ │ sec/op │ sec/op vs base │ SortHashersByValue_Typed_fnv_10-8 580.1n ± 1% 368.5n ± 2% -36.47% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 4.215µ ± 2% 2.411µ ± 4% -42.79% (p=0.000 n=10) SortHashersByValue_Typed_fnv_1000-8 39.40µ ± 1% 22.19µ ± 2% -43.68% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_10-8 599.6n ± 2% 364.3n ± 2% -39.25% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 4.337µ ± 5% 2.541µ ± 3% -41.41% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_1000-8 4.344µ ± 3% 2.483µ ± 1% -42.84% (p=0.000 n=10) geomean 4.400µ 1.888µ -41.13% ¹ ¹ benchmark set differs from baseline; geomeans may not be comparable │ 1 │ 2 │ │ B/op │ B/op vs base │ SortHashersByValue_Typed_fnv_10-8 472.0 ± 0% 312.0 ± 0% -33.90% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 3.461Ki ± 0% 1.898Ki ± 0% -45.15% (p=0.000 n=10) SortHashersByValue_Typed_fnv_1000-8 31.77Ki ± 0% 16.15Ki ± 0% -49.18% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_10-8 472.0 ± 0% 312.0 ± 0% -33.90% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 3.461Ki ± 0% 1.898Ki ± 0% -45.15% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_1000-8 3.461Ki ± 0% 1.898Ki ± 0% -45.15% (p=0.000 n=10) geomean 3.070Ki 1.474Ki -42.37% ¹ ¹ benchmark set differs from baseline; geomeans may not be comparable │ 1 │ 2 │ │ allocs/op │ allocs/op vs base │ SortHashersByValue_Typed_fnv_10-8 16.000 ± 0% 6.000 ± 0% -62.50% (p=0.000 n=10) SortHashersByValue_Typed_fnv_100-8 106.000 ± 0% 6.000 ± 0% -94.34% (p=0.000 n=10) SortHashersByValue_Typed_fnv_1000-8 1006.000 ± 0% 6.000 ± 0% -99.40% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_10-8 16.000 ± 0% 6.000 ± 0% -62.50% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_100-8 106.000 ± 0% 6.000 ± 0% -94.34% (p=0.000 n=10) SortHashersByWeightValueTyped_fnv_1000-8 106.000 ± 0% 6.000 ± 0% -94.34% (p=0.000 n=10) geomean 113.0 6.000 -92.69% ¹ ¹ benchmark set differs from baseline; geomeans may not be comparable ``` Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com> |
||
---|---|---|
.gitignore | ||
.gitlint | ||
.pre-commit-config.yaml | ||
go.mod | ||
go.sum | ||
hrw.go | ||
hrw_test.go | ||
LICENSE | ||
README.md |
Golang HRW implementation
Rendezvous or highest random weight (HRW) hashing is an algorithm that allows clients to achieve distributed agreement on a set of k options out of a possible set of n options. A typical application is when clients need to agree on which sites (or proxies) objects are assigned to. When k is 1, it subsumes the goals of consistent hashing, using an entirely different method.
Install
go get github.com/nspcc-dev/hrw
Benchmark:
BenchmarkSort_fnv_10-8 4812801 240.9 ns/op 216 B/op 4 allocs/op
BenchmarkSort_fnv_100-8 434767 2600 ns/op 1848 B/op 4 allocs/op
BenchmarkSort_fnv_1000-8 20428 66116 ns/op 16440 B/op 4 allocs/op
BenchmarkSortByIndex_fnv_10-8 2505410 486.5 ns/op 352 B/op 7 allocs/op
BenchmarkSortByIndex_fnv_100-8 254556 4697 ns/op 1984 B/op 7 allocs/op
BenchmarkSortByIndex_fnv_1000-8 13581 88334 ns/op 16576 B/op 7 allocs/op
BenchmarkSortByValue_fnv_10-8 1761030 682.1 ns/op 592 B/op 18 allocs/op
BenchmarkSortByValue_fnv_100-8 258838 4675 ns/op 4480 B/op 108 allocs/op
BenchmarkSortByValue_fnv_1000-8 27027 44649 ns/op 40768 B/op 1008 allocs/op
BenchmarkSortHashersByValue_Reflection_fnv_10-8 1013560 1249 ns/op 768 B/op 29 allocs/op
BenchmarkSortHashersByValue_Reflection_fnv_100-8 106029 11414 ns/op 6096 B/op 209 allocs/op
BenchmarkSortHashersByValue_Reflection_fnv_1000-8 10000 108977 ns/op 56784 B/op 2009 allocs/op
BenchmarkSortHashersByValue_Typed_fnv_10-8 1577814 700.3 ns/op 584 B/op 17 allocs/op
BenchmarkSortHashersByValue_Typed_fnv_100-8 215938 5024 ns/op 4472 B/op 107 allocs/op
BenchmarkSortHashersByValue_Typed_fnv_1000-8 24447 46889 ns/op 40760 B/op 1007 allocs/op
BenchmarkSortByWeight_fnv_10-8 2924833 370.6 ns/op 448 B/op 8 allocs/op
BenchmarkSortByWeight_fnv_100-8 816069 1516 ns/op 2896 B/op 8 allocs/op
BenchmarkSortByWeight_fnv_1000-8 80391 17478 ns/op 24784 B/op 8 allocs/op
BenchmarkSortByWeightIndex_fnv_10-8 1945612 550.3 ns/op 368 B/op 7 allocs/op
BenchmarkSortByWeightIndex_fnv_100-8 140473 8084 ns/op 2000 B/op 7 allocs/op
BenchmarkSortByWeightIndex_fnv_1000-8 5518 200949 ns/op 16592 B/op 7 allocs/op
BenchmarkSortByWeightValue_fnv_10-8 1305580 909.8 ns/op 608 B/op 18 allocs/op
BenchmarkSortByWeightValue_fnv_100-8 165410 6796 ns/op 4496 B/op 108 allocs/op
BenchmarkSortByWeightValue_fnv_1000-8 17922 78555 ns/op 40784 B/op 1008 allocs/op
BenchmarkSortHashersByWeightValueReflection_fnv_10-8 454976 2229 ns/op 784 B/op 29 allocs/op
BenchmarkSortHashersByWeightValueReflection_fnv_100-8 76264 15332 ns/op 6112 B/op 209 allocs/op
BenchmarkSortHashersByWeightValueReflection_fnv_1000-8 80288 13192 ns/op 6112 B/op 209 allocs/op
BenchmarkSortHashersByWeightValueTyped_fnv_10-8 1433113 901.4 ns/op 600 B/op 17 allocs/op
BenchmarkSortHashersByWeightValueTyped_fnv_100-8 188626 5896 ns/op 4488 B/op 107 allocs/op
BenchmarkSortHashersByWeightValueTyped_fnv_1000-8 178131 6518 ns/op 4488 B/op 107 allocs/op
Example
package main
import (
"fmt"
"git.frostfs.info/TrueCloudLab/hrw"
)
func main() {
// given a set of servers
servers := []string{
"one.example.com",
"two.example.com",
"three.example.com",
"four.example.com",
"five.example.com",
"six.example.com",
}
// HRW can consistently select a uniformly-distributed set of servers for
// any given key
var (
key = []byte("/examples/object-key")
h = hrw.Hash(key)
)
hrw.SortSliceByValue(servers, h)
for id := range servers {
fmt.Printf("trying GET %s%s\n", servers[id], key)
}
// Output:
// trying GET three.example.com/examples/object-key
// trying GET two.example.com/examples/object-key
// trying GET five.example.com/examples/object-key
// trying GET six.example.com/examples/object-key
// trying GET one.example.com/examples/object-key
// trying GET four.example.com/examples/object-key
}