This project contains the following components:
fractals- the Julia Set fractals workloaddna- the DNA Genome matcher workloadgrayscott- the Gray-Scott reaction-diffusion workloadwebserver- the web server exposing the functionality of the workloads- Javassist-based instrumentation (
ICount) for runtime metrics collection - DynamoDB integration for centralized metric storage with asynchronous buffered batch flushing
- Java-based Load Balancer with cost-aware request scheduling
- Java-based AutoScaler and Supervisor for EC2 worker lifecycle management
- AWS Lambda integration for overflow handling and hybrid execution
- AWS scripts to launch and configure EC2 worker instances, build AMIs and deploy infrastructure
Refer to the README.md files of the sub-projects to get more details about each specific sub-project.
- Make sure your
JAVA_HOMEenvironment variable is set to Java 11+ distribution - Run:
mvn clean package
The final system uses a custom Java-based cloud orchestration layer composed of:
- Java Load Balancer
- Java AutoScaler
- Supervisor
- EC2 Worker instances
- AWS Lambda
- DynamoDB
Each worker exposes:
/fractals/dna/grayscott/health
- Client sends request to the Load Balancer.
- Load Balancer extracts workload parameters.
- A workload-specific cost estimate is computed.
- The Metrics Cache at Load Balancer is consulted for previously observed costs within a similar parameter range (buckets).
- The Supervisor selects the optimal EC2 worker according to current load.
- If all workers are overloaded and the request cost is below a configurable threshold, the request is redirected to AWS Lambda.
- Worker executes the workload.
- Javassist instrumentation collects runtime metrics.
- Metrics are buffered locally.
- Metrics are asynchronously flushed to DynamoDB, keyed by parameter buckets.
- Cache entries are periodically refreshed from DynamoDB to improve future scheduling decisions.
Every workload execution is instrumented through ICount to produce a complexity score.
The following metrics are collected:
- instruction count
- method invocations
- constructor invocations
- basic block count
- fragmentation metric
Some of these metrics are used to compute workload complexity and populate DynamoDB, others to infer workload properties.
The complexity score combines instruction count, structural characteristics, and fragmentation penalty to produce a multiplicative model:
Cost = (instructions / 1e6) × (1 + 0.05 × constructors)× (1 + log(1 + fragmentation))
The resulting complexity values are stored in DynamoDB and later used to train the scheduling layer. The report further explains how each property contributes to the final score.
The Load Balancer maintains a cache of historical workload costs.
Parameters:
iterationsresolution = width × height
Parameters:
seqLength
Empirically the only parameter that effectively contributed to complexity.
Parameters:
sizemaxIterations
Requests are bucketed and matched against historical executions.
If a cache hit exists, the stored complexity value is used.
If a cache miss occurs, an heuristic lightweight estimator is used until real measurements become available.
The system includes workload-specific estimators that are used only when no cached metrics are available. The coefficients associated with each parameter were calibrated using the collected metrics so that the estimated cost closely approximates the complexity values produced by the ICount-based model.
Current coefficients:
FRACTALS_COSTS = List.of(0.01, 0.01);DNA_COSTS = List.of(1);GRAYSCOTT_COSTS = List.of(10, 15);Estimated costs are rounded and clamped to a minimum value of 1 before scheduling.
The Load Balancer uses:
- historical complexity values when available
- estimator-based fallback when necessary
- worker load tracking
- CPU utilization monitoring
Worker selection is performed through a Supervisor component using a cost-aware scheduling strategy and worker load at selection. More on the worker selection method in the report.
The AutoScaler continuously monitors worker utilization and capacity.
Capabilities include:
- launching EC2 workers
- terminating idle workers
- synchronizing active worker state
- supporting dynamic workload changes
The Supervisor coordinates worker registration, health monitoring and request accounting.
Lambda is used as an overflow execution layer.
Requests may be redirected to Lambda when:
- all active EC2 workers are heavily loaded
- the estimated workload cost is below a configurable threshold
- no worker is immediately available
This enables burst handling without over-provisioning EC2 instances.
DynamoDB is used for centralized metric storage.
Tables:
CNV-Metrics-FractalsCNV-Metrics-DNACNV-Metrics-GrayScott
Stored information includes:
- workload type
- request parameters
- complexity
- instruction count
- fragmentation
- timestamps
Metrics are written asynchronously using buffered batch flushing.
Configuration values must be filled in config.sh.
# 1. Prepare configuration
cp config.sh.template config.sh
# 2. Build project
mvn clean package
# 3. Create security group
bash scripts/ami/create-sec-group.sh
# 4. Build worker AMI
bash scripts/ami/create-image.sh
# 5. Deploy worker infrastructure
bash scripts/deployment/launch-deployment-template.sh
# 6. Build and deploy load balancer
bash scripts/lb/create-lb-image.sh
# 7. Run workload tests
bash tests/stress-test.sh # optionally stress-fractals.sh or stress-grayscott.sh
# 8. Monitor Load Balancer
ssh -i $PATH_TO_KEYPAIR ec2-user@$LB_DNS 'tail -f loadbalancer.log'
# 9. Monitor Instance Worker
ssh -i $PATH_TO_KEYPAIR ec2-user@$INSTANCE_DNS 'tail -f /home/ec2-user/webserver.log'
# 9. Tear down deployment
bash scripts/deployment/terminate-deployment-template.sh
# 10. Remove generated AMIs
bash scripts/ami/deregister-image.sh