ServerSim Core Concepts

This document is a Jupyter notebook. See http://jupyter.org/ for more information on Jupyter notebooks.

This is an overview of ServerSim, a framework for the creation of discrete event simulation models to analyze the performance, throughput, and scalability of services deployed on computer servers.

ServerSim is a small framework based on SimPy, a well-known discrete-event simulation framework written in the Python language.

The reader should have at least cursory familiarity with Python and SimPy in order to follow the technical details in this document.

Python is well-suited to this kind of application due to its rapid development dynamic language characteristics and the availability of powerful libraries relevant for this kind of work. In addition to SimPy, we will use portions of SciPy, a powerful set of libraries for efficient data analysis and visualization that includes Matplotlib, which will be used for plotting graphs in our tutorial.

ServerSim consists of a several classes and utilities. The main classes are described below.

class Server

Represents a server -- physical, VM, or container, with a predetermined computation capacity. A server can execute arbitrary service request types. The computation capacity of a server is represented in terms of a number of hardware threads and a total speed number (computation units processed per unit of time). The total speed is equally apportioned among the hardware threads, to give the speed per hardware thread. A server also has a number of associated software threads (which must be no smaller than the number of hardware threads). Software threads are relevant for blocking computations only.

The simulations in this document assume non-blocking services, so the software threads will not be of consequence in the tutorial example.

Attributes:

  • env: SimPy Environment, used to start and end simulations, and used internally by SimPy to control simulation events.
  • max_concurrency: The maximum of _hardware threads for the server.
  • num_threads: The maximum number of software threads for the server.
  • speed: Aggregate server speed across all _hardware threads.
  • name: The server's name.
  • hw_svc_req_log: If not None, a list where hardware service requests will be logged. Each log entry is a triple ("hw", name, svc_req), where name is this server's name and svc_req is the current service request asking for hardware resources.
  • sw_svc_req_log: If not None, a list where software thread service requests will be logged. Each log entry is a triple ("sw", name, svc_req), where name is this server's name and svc_req is the current service request asking for a software thread.

class SvcRequest

A request for execution of computation units on one or more servers.

A service request submission is implemented as a SimPy Process.

A service request can be a composite of sub-requests. A service request that is part of a composite has an attribute that is a reference to its parent service request. In addition, such a composition is implemented through the gen attribute of the service request, which is a generator. That generator can yield service request submissions for other service requests.

By default, a service request is non-blocking, i.e., a thread is held on the target server only while the service request itself is executing; the thread is relinquished when the request finishes executing and it passes control to its sub-requests. However, blocking service requests can be modeled as well (see the Blkg class).

Attributes:

  • env: The SimPy Environment.
  • parent: The immediately containing service request, in case this is part of a composite service request. None othersise.
  • svc_name: Name of the service this request is associated with.
  • gen: Generator which defines the behavior of this request. The generator produces an iterator which yields simpy.Event instances. The submit() method wratps the iterator in a simpy.Process object to schedule the request for execution by SimPy..
  • server: The target server. May be None for composite service requests, i.e., those not produced by CoreSvcRequester.
  • in_val: Optional input value of the request.
  • in_blocking_call: Indicates whether this request is in the scope of a blocking call. When this parameter is true, the service request will hold a software thread on the target server while the service request itself and any of its sub-requests (calls to other servers) are executing. Otherwise, the call is non-blocking, so a thread is held on the target server only while the service request itself is executing; the thread is relinquished when this request finishes executing and it passes control to its sub-requests.
  • out_val: Output value produced from in_val by the service execution. None by default.
  • id: The unique numerical ID of this request.
  • time_log: List of tag-time pairs representing significant occurrences for this request.
  • time_dict: Dictionary with contents of time_log, for easier access to information.

class SvcRequester

Base class of service requesters.

A service requester represents a service. In this framework, a service requester is a factory for service requests. "Deploying" a service on a server is modeled by having service requests produced by the service requester sent to the target server.

A service requester can be a composite of sub-requesters, thus representing a composite service.

Attributes:

  • env: The SimPy Environment.
  • svc_name: Name of the service.
  • log: Optional list to collect all service request objects produced by this service requester.

class UserGroup

Represents a set of identical users or clients that submit service requests.

Each user repeatedly submits service requests produced by service requesters randomly selected from the set of service requesters specified for the group.

Attributes:

  • env: The Simpy Environment.
  • num_users: Number of users in group. This can be either a positive integer or a sequence of (float, int), where the floats are monotonically increasing. In this case, the sequence represents a step function of time, where each pair represents a step whose range of x values extend from the first component of the pair (inclusive) to the first component of the next pair (exclusive), and whose y value is the second component of the pair. The first pair in the sequence must have 0 as its first component. If the num_users argument is an int, it is transformed into the list [(0, num_users)].
  • name: This user group's name.
  • weighted_svcs: List of pairs of SvcRequester instances and positive numbers representing the different service request types issued by the users in the group and their weights. The weights are the relative frequencies with which the service requesters will be executed (the weights do not need to add up to 1, as they are normalized by this class).
  • min_think_time: The minimum think time between service requests from a user. Think time will be uniformly distributed between min_think_time and max_think_time.
  • max_think_time: The maximum think time between service requests from a user. Think time will be uniformly distributed between min_think_time and max_think_time.
  • quantiles: List of quantiles to be tallied. It defaults to [0.5, 0.95, 0.99] if not provided.
  • svc_req_log: If not None, a sequence where service requests will be logged. Each log entry is a pair (name, svc_req), where name is this group's name and svc_req is the current service request generated by this group.
  • svcs: The first components of weighted_svcs.

class CoreSvcRequester(SvcRequester)

This is the core service requester implementation that interacts with servers to utilize server resources.

All service requesters are either instances of this class or composites of such instances created using the various service requester combinators in this module

Attributes:

  • env: See base class.
  • svc_name: See base class.
  • fcompunits: A (possibly randodm) function that generates the number of compute units required to execute a service request instance produced by this object.
  • fserver: Function that produces a server (possibly round-robin, random, or based on server load information) when given a service request name. Models a load-balancer.
  • log: See base class.
  • f: An optional function that is applied to a service request's in_val to produce its out_val. If f is None, the constant function that always returns None is used.

Other service requester classes

Following are other service requester classes (subclasses of SvcRequester) in addition to CoreSvcRequester, that can be used to define more complex services, including blocking services, asynchronous fire-and-forget services, sequentially dependednt services, parallel service calls, and service continuations. These additional classes are not used in the simulations in this document.

class Async(SvcRequester)

Wraps a service requester to produce asynchronous fire-and-forget service requests.

An asynchronous service request completes and returns immediately to the parent request, while the underlying (child) service request is scheduled for execution on its target server.

Attributes:

  • env: See base class.
  • svc_requester: The underlying service requester that is wrapped by this one.
  • log: See base class.

class Blkg(SvcRequester)

Wraps a service requester to produce blocking service requests.

A blocking service request will hold a software thread on the target server until the service request itself and all of its non-asynchronous sub-requests complete.

Attributes:

  • env: See base class.
  • svc_requester: The underlying service requester that is wrapped by this one.
  • log: See base class.

class Seq(SvcRequester)

Combines a non-empty list of service requesters to yield a sequential composite service requester.

This service requester produces composite service requests.
A composite service request produced by this service requester consists of a service request from each of the provided service requesters. Each of the service requests is submitted in sequence, i.e., each service request is submitted when the previous one completes.

Attributes:

  • env: See base class.
  • svc_name: See base class.
  • svc_requesters: A composite service request produced by this service requester consists of a service request from each of the provided service requesters
  • cont: If true, the sequence executes as continuations of the first request, all on the same server. Otherwise, each request can execute on a different server.
  • log: See base class.

class Par(SvcRequester)

Combines a non-empty list of service requesters to yield a parallel composite service requester.

This service requester produces composite service requests.
A composite service request produced by this service requester consists of a service request from each of the provided service requesters. All of the service requests are submitted concurrently.

When the attribute cont is True, this represents multi-threaded execution of requests on the same server. Otherwise, each service request can execute on a different server.

Attributes:

  • env: See base class.
  • svc_name: See base class.
  • svc_requesters: See class docstring.
  • f: Optional function that takes the outputs of all the component service requests and produces the overall output for the composite. If None then the constant function that always produces None is used.
  • cont: If true, all the requests execute on the same server. Otherwise, each request can execute on a different server. When cont is True, the server is the container service request's server if not None, otherwise the server is picked from the first service request in the list of generated service requests.
  • log: See base class.