- integrate the capability to ensure continual operation of your KV-store despite replica failures
- implement Paxos to realize fault-tolerant consensus amongst your replicated servers
- must implement and integrate the Paxos roles we described in class, and as described in the Lamport papers
- including the Proposers, Acceptors, and Learners
- focus on the Paxos implementation and algorithmic steps involved in realizing consensus in event ordering
- Client threads may generate requests to any of the replicas at any time
- To minimize the potential for live lock, you may choose to use leader election amongst the proposers
- acceptors must be configured to "fail" at random times
- Each of the roles within Paxos may be implemented at threads or processes
- at a minimum the acceptor threads should "fail" periodically
- could be done as simply as having a timeout that kills off the thread (or returns) after some random period of time
- A new acceptor thread could then be restarted after another delay which should resume the functions of the previous acceptor thread
- even though it clearly won't have the same state as the previously killed thread
- you may earn extra credit for the project if all roles are constructed to randomly fail and restart
- Replicate your Key-Value Store Server across 5 distinct servers.
- to increase Server bandwidth and ensure availability, you need to replicate your key-value store at each of 5 different instances of your servers.
- Note that your client code should not have to change radically
- Clients should be able to contact any of the five KV replica servers instead of a single server and get consistent data back from any of the replicas (in the case of GETs).
- You client should also be able to issue PUT operations and DELETE operations to any of the five replicas.
- On PUT or DELETE operations you need to ensure each of the replicated KV stores at each replica is consistent.
- To do this, you need to implement a two-phase protocol for updates.
- We will assume no servers will fail such that 2 Phase Commit will not stall
- Although you may want to defensively code your 2PC protocol with timeouts to be sure.
- Consequently, whenever a client issues a PUT or a DELETE to any server replica, that receiving replica will ensure the updates have been received (via ACKs) and commited (via Go messages with accompanying ACKs).
- You need to enable your client and server to communicate using Remote Procedure Calls (RPC) instead of sockets
- If you’ve implemented Project #1 in Java, you may want to look into and leverage Java RMI for RPC communication
- You need to make your server multi-threaded such that you can handle multiple outstanding client requests at once.
- The key result is that your servers should be able to handle requests from multiple running instances of you client doing concurrent PUT, GET, and DELETE operations.
- Due to the addition of multi-threading, you will need to handle mutual exclusion.
- Make the client interactive
- Docker is optional, but not required
- Follow directory structure from guidelines
- Create a run_client.sh file
- Your implementation may be written in Java
- Your source code should be well-factored and well-commented.
- The client must take the following command line arguments hostname/IP and Port and protocol
- if it does not receive a response to a particular request, you should note it in a client log and send the remaining requests
- You will have to design a simple protocol to communicate packet contents
- Three request types along with data passed along as part of the requests
- The client must be robust to malformed or unrequested datagram packets
- If it receives such a datagram packet, it should report it in a human-readable way
- Every line the client prints to the client log should be time-stamped with the current system time
- You may format the time any way you like as long as your output maintains millisecond precision
- The server should run forever (until forcibly killed by an external signal, such as a Control-C
- The server must display the requests received, and its responses, both in a human readable
- The server must be robust to malformed datagram packets
- If it receives a malformed datagram packet, it should report it in a human-readable way (length + address:port)
- Every line the server prints to standard output or standard error must be time-stamped with the current system time (i.e., System.currentTimeMillis()).
- You may format the time any way you like as long as your output maintains millisecond precision
- You should use your client to pre-populate the Key-Value store with data and a set of keys.
- Once the key-value store is populated, your client must do at least five of each operation: 5 PUTs, 5 GETs, 5 DELETEs.
- Create an executive summary comprising “Assignment overview”, “technical impression”, and three use cases to apply this in practice.
- “Assignment overview” (1 paragraph, up to about 250 words) explaining what you understand to be the purpose and scope of the assignment
- “technical impression” (1–2 paragraphs, about 200–500 words) describing your experiences while carrying out the assignment.
- Provide a use case (application) 3 where you would apply this in practice.
- Attach screenshots of your testing done on your local environment.
There are two methods to run the code for your convenience. The first is the command line. The second is a script that will provision everything. Five separate servers are provisioned per the specification. The client will interact with the servers randomly and dynamically, mimicking a real world scenario. Interactions are RPC-based, and the client will populate the KV store will preliminary data. This offers consistency since any interaction will be with a server at random, per the TAs recommendation. A two phase protocol is implemented, with timeouts just in case. Everything is eventually logged and persisted in the logs directory. A class diagram is provided to showcase the architecture. If running multiple times, please delete the logs directory (I did not automate this on purpose) to have a fresh start.
Compile the Java code:
cd src
server/*.java utils/*.java main/ServerMain.java coordinator/*.java
client/*.java utils/*.java main/ClientMain.java
Run the Server:
cd src
java main.ServerMain
Run the Client:
cd src
java main.ClientMain
Alternatively, you can run the .sh files instead:
chmod +x run_server_no_docker.sh
./run_server_no_docker.sh
chmod +x run_client_no_docker.sh
./run_client_no_docker.sh