Modeling a Server Farm

The main purpose of this project is to use our Queue structure to model job division in a multi-server (or processor) setting. Typically, the model has jobs arriving over time and upon arrival must immediately be assigned to a server for processing. Each server maintains its own queue of jobs for processing and operates under the rule that it must process jobs in the order of their arrival.


Tasks

Testing

As you proceed through this project, maintain testing files to exercise the functionality of your code that you have written. Use previous testing files provided to you as templates for the structure.

Wrapping up the Job class

Let's complete the Job class:

What fields seem necessary in order to implement these methods? One annoyance is that the Job class doesn't have a way of telling itself what time it finishes, so we'll have to make a mental note of that and return to that when we are writing the Server class.

The Server class

Now that we have our Job class finished, we want to create a Server class. An individual Server needs to manage a Queue of Jobs, allowing for jobs to be offered into the system in a FIFO setting. Additionally, it needs to give some functionality for processing those jobs in that order for a set amount of time. A Server will also track the system time (stored as a double), which the Server can assume is 0 at its instantiation. Finally, we will also have our server class track some summary statistics of the jobs it has processed that we will use to analyze our different server methods--the total number of jobs processed (an int) and the total waiting time for each job processed (a float). Both of these can be assumed to start at zero. Specifically, for this class we will implement the following methods:

Picking the "Right" Server for the Job

Now we have a Server class that is ready to accept and process jobs for us. The next step in this project is to build a JobDispatcher class that will allow us to create a collection of K Servers and allocate incoming jobs to the most appropriate Server. But with K different Servers to choose from when a job comes, how should decide where to send it? There are multiple reasonable answers to this question and we will be implementing and comparing several of them. Specifically, we will implement a RandomDispatcher that chooses a Server at random; a RoundRobinDispatcher that cycles through the Servers in order; a ShortestQueueDispatcher that chooses the Server wth the fewest jobs in its Queue; and a LeastWorkDispatcher that picks the server with the least remaining processing time across the jobs in its Queue. However all of these types of JobDispatchers share common methods, so instead of rewriting these four times, we will make an abstract class to work as the framework for how each JobDispatcher will function.

  • The JobDispatcher class

    Since we have many different algorithms in mind for the task of dispensing jobs, let's make this class abstract: public abstract class JobDispatcher. A JobDispatcher should manage a collection of Servers--implemented as an ArrayList and track the system time. In order to let the Server collection be accessed by the subclasses of our abstract JobDispatcher class, it should probably be set to public (or better yet, protected). Your jobDispatcher class should have a boolean for whether or not to show the visualization we have provided. You'll want to run it for debugging, but not when processing the large files we give you for your experiments. Your JobDispatcher class should have a class field for a ServerFarmViz object and initialize it in the constructor if the show visualization boolean is true (otherwise set it to null). The constructor for ServerFarmViz requires you to pass in an instance of a JobDispatcher (consider using the this keyword). When jobs arrive, we'll advance the system time to their arrival, which requires all Servers process jobs in their respective queues up to the next arrival--use the Server.processTo method. Then, we pick the right Server to send them to and send them to that Server. However, the method of picking the right Server for the Job is not something that we know how to write without knowing which algorithm in particular we're talking about, so we'll leave that as abstract for now: public abstract Server pickServer(Job j). Below are all the required methods for the JobDispatcher class:

    Now that we've built the framework, we're ready to make a few different dispatchers. Each one will extend the JobDispatcher class, which means we'll inherit the methods we've defined so far for free and only need to implement the constructor and the pickServer method. N.B.: when you write the constructors for each class make sure to call the parent's constructor via the super method.

  • RandomDispatcher

    For our first dispatcher RandomDispatcher, let's just extend the JobDispatcher class and have the pickServer() method return a random Server.

    Visualize your random dispatcher! Once you've implemented your RandomDispatcher, you should download jobs.txt, a small collection of jobs to run your jobDispatcher with. Make sure you have also downloaded ServerFarmViz.java. You can then download and run the provided ServerFarmTester.java file we've provided. This will show a visualization of how the random dispatcher handles the queue of jobs. There shouldn't be any particular pattern in how it decides to send a job to a particular Server (each row is a server, and shows the number of jobs in the queue and the remaining processing time for all the jobs in its queue). Modify this tester file to visualize how each of the following dispatchers work after you have implemented them. Your program should take in a single string command line argument determining which of the 4 dispatchers should be used in the visualization (random, round, shortest or queue). These follow specific rules, so you can use this visualization to check if it's working correctly!

  • RoundRobinDispatcher

    For our next dispatcher RoundRobinDispatcher, we'll pick the Server in a round-robin process (so the first time pickServer() is called, it returns the first, then the next time the second, etc.)

    Add code to the ServerFarmTester file to visualize your RoundRobinDispatcher on the same set of jobs. The tester file should now visualize whichever of the two dispatchers based on a string command line parameter.

  • ShortestQueueDispatcher

    The next dispatcher ShortestQueueDispatcher picks whichever Server has the smallest-sized queue (the server currently assigned the fewest jobs), with ties handled arbitrarily.

    Add code to the ServerFarmTester file to visualize your ShortestQueueDispatcher.

  • LeastWorkDispatcher

    The final required dispatcher LeastWorkDispatcher picks the Server with the least remaining processing time in its queue, with ties handled arbitrarily.

    Add code to the ServerFarmTester file to visualize your LeastWorkDispatcher on the same set of jobs.

  • Required program: Modify ServerFarmTester to take in a string command line argument with valid options: random, round, shortest and least. Your program should run the corresponding dispatcher to the string passed in and visualize the output. We will use this program to check that your dispatchers are working as expected! Make sure to include a usage statement explaining your command line parameter to the user!


    Exploration

    Now that we have our dispatchers, we're ready to compare them! You will write a ServerFarmSimulation class that processes the same sequence of jobs using the 4 different dispatchers and compares them. While determining the 'best' dispatcher is situation dependent, we will start by comparing the average waiting time for the sequence of jobs across the 4 types of dispatchers.

    To run these simulations, we have given you lengthy job sequence files with varying parameters for you to experiment with your dispatchers on. Every file is generated programatcially, and every filename looks like JobSequence_x_y: the number x refers to the average arrival rate of Jobs and y refers to the average processing time of each job. In particular, the filename JobSequence_x_y denotes a job sequence where, on average, a job is arriving every x time units and requires y total units of processing time.

    You will use the following 3 files in your experiments:

    These are the previous longer versions:

    Your ServerFarmSimulation class should have a main method that takes in 2 command line parameters: the number of servers and the filename of the job sequence file. It should use each of the 4 types of dispatchers to process all of the jobs in the file, and print the average waiting time for each dispatcher type, making it clear in the print statements which dispatcher type each waiting time belongs to.

    Required result: In your report, you should include a nicely formatted table with a row for each job dispatcher type, and a column for each of the 3 job sequence files we have given you (JobSequence_7_30.txt, JobSequence_10_100.txt and JobSequence_3_100.txt). The table should include the average waiting time computed for each pairing of dispatcher type and job sequence when run with 30 servers.

    This table should include a title and caption. You should also interpret these results in the text of your results section. For example, which of the four dispatch methods seems best for this objective?


    Extensions

    The following are some suggested extensions. You should feel free to pursue your own custom extensions to your project that you find interesting. Please clearly identify your extensions in your report. In your code, make sure the baseline simulations run properly. Making a separate sub-folder for major extensions is recommended.

    1. Explore different dispatch methods. Can you beat whichever method you determined to be the 'best' in the exploration section?
    2. Explore different objectives. For example, instead of minimizing average time in the system, instead minimize the average ratio of job size to its wait time.
    3. In our project so far, all Servers have been the same. If some of my servers were faster than others, how should I use them?
    4. Given a job sequence where on average jobs arrive every x seconds and take y total units of processing time, what seems like a minimal number of Servers necessary to handle those jobs without falling uncontrollably far behind? Does your best dispatcher support this intuition?
    5. Optimize your code so that they work with the original long test files and describe what choices you made to get it to run within a reasonable amount of time (a few minutes).

    Report

    Your intended audience for your report are your peers not in the class, but who have taken a CS course. Your report should explain the core CS concept used, present the results of your program, and discuss the meaning of the results: what did you discover and does it make sense?

    Your project report should contain the following elements. Please include a header for each section.

    Handin

    Here's a checklist of everything you should do when you are finished with a project and are ready to turn it in.

    + Create a report and export to pdf


    + Organize your project folder


    + Submit your project on Google Drive