Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Add 1M ops/sec demo with Terraform #143

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions stress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# 1 million ops/sec demo
This demo showcases how ScyllaDB can handle 1 million operations per second. Follow the instructions below and see it yourself!

## Infrastructure elements
* ScyllaDB Cloud cluster (for hosting the database in the cloud)
* Amazon Web Services (AWS) EC2 instance (for hosting the machines that will make the requests toward the database)

## Requirements
* AWS account and CLI credentials (more information on acquiring the credentials [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html) and [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html))
* ScyllaDB Cloud API token (get your API token [here](https://cloud.docs.scylladb.com/stable/api-docs/api-get-started.html))
* Terraform installed on your machine (installation instructions [here](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli))

## Get started
Clone this repository - if you haven't already - and navigate to the `stress` folder:
```bash
git clone https://github.com/scylladb/care-pet.git
cd stress/
```

In this repository you can find the Terraform configuration files needed to set up the demo. The configuration will create the following resources in AWS and ScyllaDB Cloud:
* ScyllaDB Cloud cluster
* VPC
* Subnets
* Security groups
* EC2 instance

Make sure that you have sufficient AWS permissions to create these items.

Start setting up infrastructure with Terraform:
```bash
terraform init
terraform plan
terraform apply
```

Setting up the infrastructure takes 10+ minutes.

After completion, SSH (use your private key file and the proper EC2 instance address) into the loader instance and start making requests to the database:
```bash
ssh -i "private_key.pem" [email protected]
```

Run the script:
```bash
sudo systemctl start cassandra-stress-benchmark
```

At this point, your ScyllaDB Cloud cluster will start getting requests. Check the results on the Grafana dashboard in ScyllaDB Cloud:
<add screenshot>
63 changes: 63 additions & 0 deletions stress/scylladb-cloud.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
terraform {
// Declare the required provider for ScyllaDB Cloud
required_providers {
scylladbcloud = {
source = "registry.terraform.io/scylladb/scylladbcloud"
}
}
}

// Set up the ScyllaDB Cloud provider with your API token
provider "scylladbcloud" {
token = var.scylla_cloud_token # Get your Token from our Support! Just open a ticket requesting it.
}

// Create a ScyllaDB Cloud cluster
resource "scylladbcloud_cluster" "scylladbcloud" {
name = var.custom_name # Set the cluster name
region = data.aws_region.current.name # Get the AWS region name where you want to launch the cluster
node_count = var.scylla_node_count # Set the number of nodes in the cluster
node_type = var.scylla_node_type # Set the instance type for the cluster nodes
cidr_block = "172.31.0.0/16" # Set the CIDR block for the VPC
cloud = "AWS" # Set the cloud provider to AWS
enable_vpc_peering = true # Enable VPC peering
enable_dns = true # Enable DNS
}

// Output the cluster ID
output "scylladbcloud_cluster_id" {
value = scylladbcloud_cluster.scylladbcloud.id
}

// Output the datacenter where the cluster was launched
output "scylladbcloud_cluster_datacenter" {
value = scylladbcloud_cluster.scylladbcloud.datacenter
}

// Set up VPC peering with the ScyllaDB Cloud cluster and a custom VPC
resource "scylladbcloud_vpc_peering" "scylladbcloud" {
cluster_id = scylladbcloud_cluster.scylladbcloud.id # Set the cluster ID for VPC peering
datacenter = scylladbcloud_cluster.scylladbcloud.datacenter # Set the datacenter for VPC peering
peer_vpc_id = aws_vpc.custom_vpc.id # Set the custom VPC ID for VPC peering
peer_cidr_block = var.custom_vpc # Set the custom VPC CIDR block for VPC peering
peer_region = data.aws_region.current.name # Set the custom VPC region name for VPC peering
peer_account_id = data.aws_caller_identity.current.account_id # Set the account ID for VPC peering

allow_cql = true # Allow CQL traffic over VPC peering
}

// Output the VPC peering connection ID
output "scylladbcloud_vpc_peering_connection_id" {
value = scylladbcloud_vpc_peering.scylladbcloud.connection_id
}

// Output the private IP addresses of the nodes in the ScyllaDB Cloud cluster
output "scylladbcloud_cluster_ips" {
value = scylladbcloud_cluster.scylladbcloud.node_private_ips
}

// Output the CQL password for the ScyllaDB Cloud cluster
output "scylladbcloud_cql_password" {
value = data.scylladbcloud_cql_auth.scylla.password # Get the CQL password for the cluster
sensitive = true # Mark the output as sensitive so it won't be shown in logs or output
}
87 changes: 87 additions & 0 deletions stress/scylladb-loader.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
####################################################################
# Creating 3 EC2 Instances:
####################################################################

# This block creates 3 EC2 instances based on the specified AMI, instance type, subnet ID, and security groups.
# It also creates tags to identify the instances and sets timeouts for creating the instances.

resource "aws_instance" "instance" {
count = length(aws_subnet.public_subnet.*.id)
ami = var.ami_id
instance_type = var.instance_type
subnet_id = element(aws_subnet.public_subnet.*.id, count.index)
security_groups = [aws_security_group.sg.id, ]
key_name = "care-pet-demo"
tags = {
"Name" = "${var.custom_name}-Loader-${count.index}"
"CreatedBy" = "care-pet-demo"
}

timeouts {
create = "10m"
}

# This block provisions files to each instance. It copies three files from the current directory
# to the remote instance: thanos-attack-0.yml, cassandra-stress.service, and cassandra-stress-benchmark.service.

provisioner "file" {
source = "thanos-attack-${count.index}.yml"
destination = "/home/scyllaadm/care-pet-stress-1m.yaml"
}
provisioner "file" {
source = "cassandra-stress.service"
destination = "/home/scyllaadm/cassandra-stress.service"
}
provisioner "file" {
source = "cassandra-stress-benchmark.service"
destination = "/home/scyllaadm/cassandra-stress-benchmark.service"
}

# This block runs remote-exec commands on each instance. It stops the scylla-server, creates a start.sh script,
# creates a benchmark.sh script, sets permissions on the scripts, moves two files to /etc/systemd/system/,
# runs daemon-reload, and starts the cassandra-stress service.

provisioner "remote-exec" {
inline = [
"sudo systemctl stop scylla-server |tee scylla.log",
"echo '/usr/bin/cassandra-stress user profile=./care-pet-stress-1m.yaml n=${var.num_of_ops} cl=local_quorum no-warmup \"ops(insert=1)\" -rate threads=${var.num_threads} fixed=450000/s -mode native cql3 user=${var.scylla_user} password=${local.scylla_pass} -log file=populating.log -node ${local.scylla_ips}' > start.sh",
"echo '/usr/bin/cassandra-stress user profile=./care-pet-stress-1m.yaml duration=24h no-warmup cl=local_quorum \"ops(insert=4,simple1=2)\" -rate threads=${var.num_threads} fixed=${var.throttle} -mode native cql3 user=${var.scylla_user} password=${local.scylla_pass} -log file=benchmarking.log -node ${local.scylla_ips}' > benchmark.sh",
"sudo chmod +x start.sh benchmark.sh",
"sudo mv /home/scyllaadm/cassandra-stress.service /etc/systemd/system/cassandra-stress.service ",
"sudo mv /home/scyllaadm/cassandra-stress-benchmark.service /etc/systemd/system/cassandra-stress-benchmark.service ", "sudo systemctl daemon-reload ",
"sudo systemctl start cassandra-stress.service",
]
}

# This connection block sets up an SSH connection to each EC2 instance using the scyllaadm user and the private key
# The coalesce function is used to select the public IP address of ScyllaDB Nodes
connection {
type = "ssh"
user = "scyllaadm"
private_key = file("$ssh_private_key")
host = coalesce(self.public_ip, self.private_ip)
agent = true
}

}


# Creating 3 Elastic IPs
resource "aws_eip" "eip" {
count = length(aws_instance.instance.*.id) # Create an Elastic IP for each EC2 instance
instance = element(aws_instance.instance.*.id, count.index) # Associate the Elastic IP with the current EC2 instance
public_ipv4_pool = "amazon" # Use the Amazon pool for public IPv4 addresses
vpc = true # Create a VPC Elastic IP address

tags = { # Add tags to the Elastic IP resource
"Name" = "${var.custom_name}-EIP-${count.index}"
}
}

# Creating EIP association with EC2 Instances
resource "aws_eip_association" "eip_association" {
count = length(aws_eip.eip) # Associate each Elastic IP with an EC2 instance
instance_id = element(aws_instance.instance.*.id, count.index) # Associate the current Elastic IP with the current EC2 instance
allocation_id = element(aws_eip.eip.*.id, count.index) # Associate the current Elastic IP with the current allocation ID
}

97 changes: 97 additions & 0 deletions stress/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

# Scylla Cloud API token
variable "scylla_cloud_token" {
description = "Scylla Cloud API token"
type = string
default = "<add token>"
}

# Environment name
variable "custom_name" {
description = "Name for the Scylla Cloud environment"
type = string
default = "care-pet-demo"
}

# Virtual Private Cloud (VPC) IP range
variable "custom_vpc" {
description = "CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}

# EC2 instance tenancy
variable "instance_tenancy" {
description = "EC2 instance tenancy, default or dedicated"
type = string
default = "default"
}

# Amazon Machine Image (AMI) ID
variable "ami_id" {
description = "AMI ID for the EC2 instance"
type = string
default = "ami-0a23f9b62c17c53fe"
}

# EC2 instance type
variable "instance_type" {
description = "Type of the EC2 instance"
type = string
default = "i4i.xlarge"
}

# SSH private key for EC2 instance access
variable "ssh_private_key" {
description = "SSH private key for EC2 instance access"
type = string
default = "<add path>"
}

# Number of Scylla Cloud instances to create
variable "scylla_node_count" {
description = "Number of Scylla Cloud instances to create"
type = string
default = "3"
}

# Scylla Cloud instance type
variable "scylla_node_type" {
description = "Type of Scylla Cloud instance"
type = string
default = "i3.xlarge"
}

# Total number of operations to run
variable "num_of_ops" {
description = "Total number of operations to run"
type = string
default = "100M"
}

# Number of threads for the Cassandra stress tool
variable "num_threads" {
description = "Number of threads for the Cassandra stress tool"
type = string
default = "256"
}

# Throttling for the Cassandra stress tool
variable "throttle" {
description = "Throttling for the Cassandra stress tool (in ops/sec)"
type = string
default = "900000/s "
}

# Scylla Cloud user
variable "scylla_user" {
description = "Scylla Cloud user"
type = string
default = "scylla"
}

locals {
scylla_ips = (join(",", [for s in scylladbcloud_cluster.scylladbcloud.node_private_ips : format("%s", s)]))
scylla_pass = data.scylladbcloud_cql_auth.scylla.password

}