Skip to content

maxbarsukov/radish-db

RadishDB logo

RadishDB

Yet Another Key–Value Database

GitHub Release GitHub License GitHub repo size
Elixir Markdown Coverage Status

What is RadishDB?

RadishDB is an in-memory distributed key-value data store that chooses Consistency over Availability using own implementation of Raft Consensus Algorithm.

Table of contents

  1. Updates
  2. Getting Started
    1. Pre-reqs
    2. Building and Running
  3. Testing
  4. Linting
  5. Contributing
  6. Code of Conduct
  7. Get in touch!
  8. Security
  9. Useful Links
  10. License

Updates

🎉 v0.1.0 has been released!

🔔 Dec. 28, 2024 (v0.1.0)

🚀 Getting Started

Pre-reqs

  • Make sure you have git installed.
  • Erlang and Elixir (we recommend using asdf to manage versions).

Building and Running

Clone the repository:

git clone git@github.com:maxbarsukov/radish-db.git
cd radish-db

Install dependencies:

mix deps.get

Compile the project:

mix compile

Start the application:

$ iex --sname 1 -S mix
iex(1@laptop)>

Example

Let's assume we have a 4-node Erlang cluster:

$ iex --sname 1 -S mix
iex(1@laptop)>

$ iex --sname 2 -S mix
iex(2@laptop)> Node.connect(:"1@laptop")

$ iex --sname 3 -S mix
iex(3@laptop)> Node.connect(:"1@laptop")

$ iex --sname 4 -S mix
iex(4@laptop)> Node.connect(:"1@laptop")

Load the following module, which implements the RadishDB.Raft.StateMachine.Statable behavior on all cluster nodes:

  defmodule JustAnInt do
    @behaviour RadishDB.Raft.StateMachine.Statable
    def new, do: 0
    def command(i, {:set, j}), do: {i, j}
    def command(i, :inc), do: {i, i + 1}
    def query(i, :get), do: i
  end

Call RadishDB.ConsensusGroups.GroupApplication.activate/1 on all nodes:

iex(1@laptop)> RadishDB.ConsensusGroups.GroupApplication.activate("zone1")

iex(2@laptop)> RadishDB.ConsensusGroups.GroupApplication.activate("zone2")

iex(3@laptop)> RadishDB.ConsensusGroups.GroupApplication.activate("zone1")

iex(4@laptop)> RadishDB.ConsensusGroups.GroupApplication.activate("zone2")

Than create 5 consensus groups, each of which replicates an integer and has 3 consensus members:

iex(1@laptop)> config = RadishDB.Raft.Node.make_config(JustAnInt)
iex(1@laptop)> RadishDB.ConsensusGroups.GroupApplication.add_consensus_group(:consensus1, 3, config)
iex(1@laptop)> RadishDB.ConsensusGroups.GroupApplication.add_consensus_group(:consensus2, 3, config)
iex(1@laptop)> RadishDB.ConsensusGroups.GroupApplication.add_consensus_group(:consensus3, 3, config)
iex(1@laptop)> RadishDB.ConsensusGroups.GroupApplication.add_consensus_group(:consensus4, 3, config)
iex(1@laptop)> RadishDB.ConsensusGroups.GroupApplication.add_consensus_group(:consensus5, 3, config)

Now we can execute a query/command from any cluster node:

iex(1@laptop)> RadishDB.ConsensusGroups.GroupApplication.query(:consensus1, :get)
{:ok, 0}

iex(2@laptop)> RadishDB.ConsensusGroups.GroupApplication.command(:consensus1, :inc)
{:ok, 0}

iex(3@laptop)> RadishDB.ConsensusGroups.GroupApplication.query(:consensus1, :get)
{:ok, 1}

Activation/deactivation of a node in a cluster triggers a rebalancing of the consensus member processes.

A 3-nodes consensus group continues to operate if one of the members dies (even without deactivation):

iex(3@laptop)> :gen_statem.stop(:baz)
iex(1@laptop)> RadishDB.ConsensusGroups.GroupApplication.query(:consensus1, :get)
{:ok, 1}

✅ Testing

Run tests with:

mix test

For detailed test output:

mix test --trace

Test coverage is tracked via Coveralls and shown in the project badges.

🎨 Linting

We use multiple linting tools:

# Format code
mix format

# Run Credo for code analysis
mix credo

# Run Dialyzer for type checking
mix dialyzer

# Run all checks (format, credo, dialyzer)
mix check

Linting is also automatically run on every commit via GitHub Actions.


🤝 Contributing

Need help? See SUPPORT.md.

Hey! We're glad you're thinking about contributing to RadishDB! Feel free to pick an issue labeled as good first issue and ask any question you need. Some points might not be clear, and we are available to help you!

Bug reports and pull requests are welcome on GitHub at https://github.com/maxbarsukov/radish-db.

Before creating your PR, we strongly encourage you to read the repository's corresponding CONTRIBUTING.md or otherwise the "Contributing" section of the README.md.

⚖️ Code of Conduct

This project is intended to be a safe, welcoming space for collaboration, and everyone interacting in the RadishDB project's codebases, issue trackers, chat rooms and mailing lists is expected to adhere to the code of conduct.

📫 Get in touch!

💌 Want to make a suggestion or give feedback? Here are some of the channels where you can reach us:

  • Found a bug? Open an issue in the repository!
  • Want to be part of our Telegram community? We invite you to join our RadishDB Community Chat, where you can find support from our team and the community, but where you can also share your projects or just talk about random stuff with other members of the RadishDB community 😁!

🛡️ Security

RadishDB takes the security of our software products and services seriously. If you believe you have found a security vulnerability in any RadishDB-owned repository, please report it to us as described in our security policy.


🌐 Useful Links

Link Description
raft.github.io Raft Consensus Algorithm
raft.github.io/raft.pdf Original Paper: In Search of an Understandable Consensus Algorithm (Extended Version)
habr.com/ru/articles/469999/ How servers negotiate with each other: Raft distributed consensus algorithm
thesecretlivesofdata.com/raft/
deniz.co/raft-consensus/
Interactive Raft visualizations
erlang.org/doc/system/distributed.html About distributed Erlang systems

🪪 License

The project is available as open source under the terms of the MIT License.

Leave a star ⭐ if you find this project useful.


This project is published under MIT.
A maxbarsukov project.
- 🎉 -

About

🌱🍠 RadishDB is an in-memory distributed key-value data store

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project