This is a simple Twitter clone that implements its distributed SQLite database using Hashicorp's implmentation of Raft.
SQLite implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. SQLite is the most used database engine in the world. SQLite is built into all mobile phones and most computers and comes bundled inside countless other applications that people use every day.
But it isn't distributed! That's where Raft comes in...
- The client, which is in the
frontend
directory, is a React Application. It sends and receives HTTP requests to the web server. - The web server, found in the
api
directory and implemented using thegin
framework, receives HTTP requests from the React frontend. It then forwards the request, using an RPC, to the Raft node it is pointing to. Note: Leader forwarding has not been implemented, and therefore if the node is not the leader data can only be queried. - The Raft node accepts the requests from the webserver. If it is adding new data, it must reach a quorum, committ the logs, and replicate. The RPCs do not go through the Raft protocol for data queries (GET requests).
- Finally, the node reutrns the response to the server, which then forwards the data back to the client.
- Hashicorp's Raft implementation - hashicorp/raft
- The gin web server framework - gin-gonic/gin
- SQLite - rqlite/go-sqlite3
- gRPC - grpc/grpc-go
To begin, clone the repo.
cd frontend
npm install
npm run start
The default configuration is:
flag.StringVarP(&config.RaftAddress, "raft-address", "r",
"127.0.0.1", "IP Address on which to bind")
flag.IntVarP(&config.RaftPort, "raft-port", "b",
8000, "Port on which to bind Raft")
flag.IntVarP(&config.ServerPort, "server-port", "p",
8080, "Port on which to bind Server")
To run:
cd api
go build
./api
With nondefault options: ./api [--raft-address=?] [--raft-port=?] [server-port=?]
The default configuration is:
flag.StringVarP(&config.DataDir, "data-dir", "d",
defaultDataPath, "Path in which to store Raft data")
flag.StringVarP(&config.BindAddress, "bind-address", "a",
"127.0.0.1", "IP Address on which to bind")
flag.IntVarP(&config.RaftPort, "raft-port", "r",
7000, "Port on which to bind Raft")
flag.IntVarP(&config.HTTPPort, "http-port", "h",
8000, "Port on which to bind HTTP")
flag.StringVar(&config.JoinAddress, "join",
"", "Address of another node to join")
flag.BoolVar(&config.Bootstrap, "bootstrap",
true, "Bootstrap the cluster with this node")
To run a three node cluser:
cd backend
go build
- For the first node:
./backend --http-port=8000 --raft-port=7000 --bootstrap
- For second node:
./backend --http-port=8001 --raft-port=7001 --join="127.0.0.1:8000"
- For third node:
./backend --http-port=8002 --raft-port=7002 --join="127.0.0.1:8000"
For subsequent nodes and other options: backend [--data-dir=?] [--http-port=?] [--raft-port=?] [--join="?"]