Implementation of Raft algorithm made with Go for fun and learning
- Start 2 nodes => the Leader should be elected
> docker-compose up node1 node2
...
> curl http://localhost:80/api/v1/state
{"term":1,"state":"FOLLOWER","log":[],"uncommitted":[]}
> curl http://localhost:81/api/v1/state
{"term":1,"state":"LEADER","log":[],"uncommitted":[]}
- Post
msg1
,msg2
=> messages should be replicated and committed
> curl -X POST http://localhost:81/api/v1/append -H "Content-Type: application/json" -d '{"command":"msg1"}'
> curl -X POST http://localhost:81/api/v1/append -H "Content-Type: application/json" -d '{"command":"msg2"}'
> curl http://localhost:80/api/v1/state
{"term":1,"state":"FOLLOWER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"}],"uncommitted":[]}
> curl http://localhost:81/api/v1/state
{"term":1,"state":"LEADER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"}],"uncommitted":[]}
- Start 3-rd node => messages should be replicated on the 3-rd node
> docker-compose up node3
...
> curl http://localhost:82/api/v1/state
{"term":1,"state":"FOLLOWER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"}],"uncommitted":[]}
- Partition a Leader - (
OldLeader
) => aNewLeader
should be elected
> docker network disconnect deployment_isolated_network deployment_node2_1
> curl http://localhost:80/api/v1/state
{"term":2,"state":"LEADER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"}],"uncommitted":[]}
> curl http://localhost:82/api/v1/state
{"term":2,"state":"FOLLOWER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"}],"uncommitted":[]}
- Post
msg3
,msg4
viaNewLeader
=> messages should be replicated and committed
> curl -X POST http://localhost:80/api/v1/append -H "Content-Type: application/json" -d '{"command":"msg3"}'
> curl -X POST http://localhost:80/api/v1/append -H "Content-Type: application/json" -d '{"command":"msg4"}'
> curl http://localhost:80/api/v1/state
{"term":2,"state":"LEADER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"},{"term":2,"command":"msg3"},{"term":2,"command":"msg4"}],"uncommitted":[]}
> curl http://localhost:82/api/v1/state
{"term":2,"state":"FOLLOWER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"},{"term":2,"command":"msg3"},{"term":2,"command":"msg4"}],"uncommitted":[]}
- Post
msg5
viaOldLeader
=> message should not be committed
> docker exec -it deployment_node2_1 curl -X POST http://localhost:8000/api/v1/append -H "Content-Type: application/json" -d '{"command":"msg5"}' --max-time 2
curl: (28) Operation timed out after 2001 milliseconds with 0 bytes received
^^^ this means that message is not committed
> docker exec -it deployment_node2_1 curl http://localhost:8000/api/v1/state
{"term":1,"state":"LEADER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"}],"uncommitted":[{"term":1,"command":"msg5"}]}
- Join cluster =>
msg5
on theOldLeader
should be replaced by messages from theNewLeader
> docker network connect deployment_isolated_network --alias node2 deployment_node2_1
> curl http://localhost:81/api/v1/state
{"term":2,"state":"FOLLOWER","log":[{"term":1,"command":"msg1"},{"term":1,"command":"msg2"},{"term":2,"command":"msg3"},{"term":2,"command":"msg4"}],"uncommitted":[]}