{"id":37140110,"url":"https://github.com/ollelogdahl/concord","last_synced_at":"2026-01-14T16:25:04.534Z","repository":{"id":321246816,"uuid":"1085052151","full_name":"ollelogdahl/concord","owner":"ollelogdahl","description":"A resilient Chord implementation in Go","archived":false,"fork":false,"pushed_at":"2025-11-06T13:44:15.000Z","size":95,"stargazers_count":37,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-11-06T14:32:09.666Z","etag":null,"topics":["chord-protocol","distributed-systems","go"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ollelogdahl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-28T14:20:15.000Z","updated_at":"2025-11-06T13:59:05.000Z","dependencies_parsed_at":"2025-10-28T17:31:38.920Z","dependency_job_id":"a190877b-b244-4c2c-bbc6-f64aeaa18112","html_url":"https://github.com/ollelogdahl/concord","commit_stats":null,"previous_names":["ollelogdahl/concord"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ollelogdahl/concord","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ollelogdahl%2Fconcord","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ollelogdahl%2Fconcord/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ollelogdahl%2Fconcord/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ollelogdahl%2Fconcord/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ollelogdahl","download_url":"https://codeload.github.com/ollelogdahl/concord/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ollelogdahl%2Fconcord/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28425755,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T15:24:48.085Z","status":"ssl_error","status_checked_at":"2026-01-14T15:23:41.940Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chord-protocol","distributed-systems","go"],"created_at":"2026-01-14T16:25:03.858Z","updated_at":"2026-01-14T16:25:04.529Z","avatar_url":"https://github.com/ollelogdahl.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"assets/concord-dark.svg\"\u003e\n    \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"assets/concord-light.svg\"\u003e\n    \u003cimg alt=\"Concord Logo\" width=\"300\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eA resilient Chord implementation in Go\u003c/strong\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e •\n  \u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e •\n  \u003ca href=\"#quick-start\"\u003eQuick Start\u003c/a\u003e •\n  \u003ca href=\"#usage\"\u003eUsage\u003c/a\u003e •\n  \u003ca href=\"#development\"\u003eDevelopment\u003c/a\u003e •\n  \u003ca href=\"#license\"\u003eLicense\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pkg.go.dev/github.com/ollelogdahl/concord\"\u003e\u003cimg src=\"https://pkg.go.dev/badge/github.com/ollelogdahl/concord.svg\" alt=\"Go Reference\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/ollelogdahl/concord\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/ollelogdahl/concord\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/ollelogdahl/concord/actions\"\u003e\u003cimg src=\"https://github.com/ollelogdahl/concord/workflows/CI/badge.svg\" alt=\"CI Status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/ollelogdahl/concord\"\u003e\u003cimg alt=\"Codecov\" src=\"https://img.shields.io/codecov/c/gh/ollelogdahl/concord\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Overview\n\nConcord is a resilient implementation of the core [Chord protocol](https://en.wikipedia.org/wiki/Chord_(peer-to-peer)) in Go.\nThe protocol enables distributed key lookup in a peer-to-peer network using consistent hashing, a technique\nfor evenly distributing keys across multiple nodes while minimizing reassignments when nodes join and leave.\nChord allows nodes in this dynamic network to efficiently determine which node is responsible for a given key.\nWhile Chord is often conflated with its common use case, Distributed Hash Tables, this library\nimplements the more general lookup protocol, allowing you to build DHTs or other distributed\napplications on top of it.\n\nThis implementation closely follows Pamela Zave's formally verified Chord specification, thereby\nachieving resilience to node failures and maintaining consistency during crash faults.\n\n# Features\n\n* **Failure Resilient:** Built-in configurable resilience to node failures ($N$), ensuring the ring remains operational and consistent.\n* **Consistent Hashing Core:** Provides the basic primitives for consistent hashing in a distributed\n  environment.\n* **Range Change Callbacks:** Includes a callback function (`OnRangeChange`) that notifies the\n  application when a node becomes responsible for a new range of keys, essential for\n  building a DHT.\n* **Customizable Hashing:** Supports custom hash functions and configurable hash bit-widths (up to\n  64-bit keys).\n* **Structured Logging:** Uses Go's built-in `log/slog` for structured and customizable logging.\n* **gRPC Based:** Uses **gRPC** for internal node-to-node communication.\n\n# What is Chord?\n\nChord is a peer-to-peer protocol for distributed key lookup using consistent hashing. Consistent\nhashing is a technique for evenly distributing keys across multiple nodes, minimizing the number\nof keys that need to be moved when nodes join and leave the network. Chord allows nodes in this\ndynamic network to efficiently determine which node is responsible for a given key.\nWhile Chord is often conflated with its common use case, Distributed Hash Tables, this library\nimplements the more general lookup protocol, allowing you to build DHTs or other distributed\napplications on top of it.\n\n# Installation\n\n```sh\ngo get github.com/ollelogdahl/concord\n```\n\n# Quick Start\n\n## Creating a New Cluster\n\n```go\npackage main\n\nimport (\n    \"log\"\n    \"github.com/ollelogdahl/concord\"\n)\n\nfunc main() {\n    // Configure the node\n    config := concord.Config{\n        Name:     \"node1\",\n        BindAddr: \"0.0.0.0:7946\",\n        AdvAddr:  \"node1.example.com:7946\",\n        OnRangeChange: func(r concord.Range) {\n            log.Printf(\"Range changed: %d-%d\", r.Start, r.End)\n        },\n    }\n\n    // Create and start the node\n    node := concord.New(config)\n    if err := node.Start(); err != nil {\n        log.Fatal(err)\n    }\n    defer node.Stop()\n\n    // Create a new cluster\n    if err := node.Create(); err != nil {\n        log.Fatal(err)\n    }\n\n    log.Printf(\"Node %s (ID: %d) created cluster\", node.Name(), node.Id())\n}\n```\n\n## Joining an Existing Cluster\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"log\"\n    \"github.com/ollelogdahl/concord\"\n)\n\nfunc main() {\n    config := concord.Config{\n        Name:     \"node2\",\n        BindAddr: \"0.0.0.0:7947\",\n        AdvAddr:  \"node2.example.com:7947\",\n    }\n\n    node := concord.New(config)\n    if err := node.Start(); err != nil {\n        log.Fatal(err)\n    }\n    defer node.Stop()\n\n    // Join an existing cluster\n    ctx := context.Background()\n    if err := node.Join(ctx, \"node1.example.com:7946\"); err != nil {\n        log.Fatal(err)\n    }\n\n    log.Printf(\"Node %s joined cluster\", node.Name())\n}\n```\n\n# Usage\n\n## Looking Up Keys\n\n```go\n// Lookup which node is responsible for a key\nkey := []byte(\"my-key\")\nserver, err := node.Lookup(key)\nif err != nil {\n    log.Fatal(err)\n}\n\nlog.Printf(\"Key is managed by node %s (ID: %d) at %s\",\n    server.Name, server.Id, server.Address)\n```\n\n## Monitoring range changes\n\n```go\nconfig := concord.Config{\n    Name:     \"node1\",\n    BindAddr: \"0.0.0.0:7946\",\n    AdvAddr:  \"node1.example.com:7946\",\n    OnRangeChange: func(r concord.Range) {\n        log.Printf(\"Now responsible for range (%d, %d]\", r.Start, r.End)\n\n        // Migrate data, update local state, etc.\n        migrateData(r)\n    },\n}\n```\n\n## Hash Function\n\nBy default, sha256 truncated to 64-bits is used as the hash function. Currently, the system\nonly allows for max 64-bit keys.\n\nCustom hash functions can be used instead:\n\n```go\nimport \"hash/fnv\"\n\nfunc customHash(data []byte) uint64 {\n    h := fnv.New32a()\n    h.Write(data)\n    return uint64(h.Sum32())\n}\n\nconfig := concord.Config{\n    Name:     \"node1\",\n    BindAddr: \"0.0.0.0:7946\",\n    AdvAddr:  \"node1.example.com:7946\",\n    HashFunc: customHash,\n    HashBits:  32,\n}\n```\n\n## Structured Logging\n\n```go\nimport (\n    \"log/slog\"\n    \"os\"\n)\n\nconfig := concord.Config{\n    Name:       \"node1\",\n    BindAddr:   \"0.0.0.0:7946\",\n    AdvAddr:    \"node1.example.com:7946\",\n    LogHandler: slog.NewJSONHandler(os.Stdout, \u0026slog.HandlerOptions{\n        Level: slog.LevelDebug,\n    }),\n}\n```\n\n## Resilience\n\nBy default, the system supports up to 2 simultaneous failures of nodes. This is configurable\nby setting `SuccessorCount` to $N+1$, where $N$ is the amount of simultaneous fails.\n\n```go\nconfig := concord.Config{\n    Name:       \"node1\",\n    BindAddr:   \"0.0.0.0:7946\",\n    AdvAddr:    \"node1.example.com:7946\",\n    SuccessorCount: 5,\n}\n```\n\n## mTLS Encryption\n\nConcord supports secure communication between nodes using Mutual TLS (mTLS). When configured,\nmTLS provides encryption and authentication, allowing for a zero-trust model where only\nauthorized nodes can communicate. This feature is optional and must be explicitly configured.\nBelow, static certificates are used.\n\n```go\nimport (\n    \"crypto/tls\"\n    \"crypto/x509\"\n    \"os\"\n)\n\n// Load certificates and CA\ncert, err := tls.LoadX509KeyPair(\"node_1.pem\", \"node_1_key.pem\")\nif err != nil {\n    log.Fatal(err)\n}\n\ncaPool := x509.NewCertPool()\ncaPEM, err := os.ReadFile(\"ca_pool.pem\")\nif err != nil {\n    log.Fatal(err)\n}\ncaPool.AppendCertsFromPEM(caPEM)\n\nserverTLS := \u0026tls.Config{\n    Certificates: []tls.Certificate{cert},\n    ClientCAs:    caPool,\n    ClientAuth:   tls.RequireAndVerifyClientCert,\n    MinVersion:   tls.VersionTLS13,\n}\n\nclientTLS := \u0026tls.Config{\n    Certificates: []tls.Certificate{cert},\n    RootCAs:      caPool,\n    MinVersion:   tls.VersionTLS13,\n}\n\nconfig := concord.Config{\n    Name:     \"node1\",\n    BindAddr: \"0.0.0.0:7946\",\n    AdvAddr:  \"node1.example.com:7946\",\n    TLS: \u0026concord.TLSConfig{\n        Server: serverTLS,\n        Client: clientTLS,\n    },\n}\n```\n\n# Development\n\n## Prerequisites\n\n- Go 1.24.0 or higher\n- Protocol Buffers compiler and go generators (grpc, protobuf)\n\n## Building\n\n```sh\ngit clone https://github.com/ollelogdahl/concord.git\ncd concord\ngo generate ./...\ngo build\n```\n\n## Running tests\n\n```sh\n# Run all tests\ngo test ./...\n\n# Run tests with coverage\ngo test -cover ./...\n\n# Run tests with race detection\ngo test -race ./...\n```\n\n## Fuzzing\n\nConcord includes fuzz tests for checking eventual consistent invariants.\n\n```\ngo run -race ./test/fuzz/fuzz.go\n```\n\n## Test Nodes\n\nExample nodes are provided in the `examples/` directory.\n\n```sh\ngo run examples/node/node.go -name node1 -addr :7946\ngo run examples/node/node.go -name node2 -addr :7947 -join localhost:7946\ngo run examples/node/node.go -name node3 -addr :7948 -join localhost:7946\n```\n\n# Licence\n\nThis project is licenced under the [MIT License](github.com/ollelogdahl/concord/blob/master/LICENSE).\n\n# Acknowledgements\n\n- Original chord paper: [Chord: A Scalable Peer-to-Peer Lookup Service for Internet](https://pdos.csail.mit.edu/papers/chord:sigcomm01/chord_sigcomm.pdf)\n- Formally proven Chord: [Reasoning about Identifier Spaces: How to Make Chord Correct](https://www.pamelazave.com/TSE_Chord_final.pdf)\n\n\u003cp align=\"center\"\u003eMade with ☕ by Olle\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Follelogdahl%2Fconcord","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Follelogdahl%2Fconcord","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Follelogdahl%2Fconcord/lists"}