From 34fafedd1da02fc399fe6fbc9b29c7d7e45ff89f Mon Sep 17 00:00:00 2001 From: Attila Toth Date: Mon, 14 Aug 2023 19:35:52 +0200 Subject: [PATCH] Add 1m ops demo files and readme --- stress/README.md | 49 ++++++++++++++++++++ stress/scylladb-cloud.tf | 63 +++++++++++++++++++++++++ stress/scylladb-loader.tf | 87 +++++++++++++++++++++++++++++++++++ stress/variables.tf | 97 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 stress/README.md create mode 100644 stress/scylladb-cloud.tf create mode 100644 stress/scylladb-loader.tf create mode 100644 stress/variables.tf diff --git a/stress/README.md b/stress/README.md new file mode 100644 index 00000000..94bdf0c7 --- /dev/null +++ b/stress/README.md @@ -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" scyllaadm@ec2-11-11-111-11.eu-north-1.compute.amazonaws.com +``` + +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: + \ No newline at end of file diff --git a/stress/scylladb-cloud.tf b/stress/scylladb-cloud.tf new file mode 100644 index 00000000..16c800cc --- /dev/null +++ b/stress/scylladb-cloud.tf @@ -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 +} diff --git a/stress/scylladb-loader.tf b/stress/scylladb-loader.tf new file mode 100644 index 00000000..962c019f --- /dev/null +++ b/stress/scylladb-loader.tf @@ -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 +} + diff --git a/stress/variables.tf b/stress/variables.tf new file mode 100644 index 00000000..83d70e83 --- /dev/null +++ b/stress/variables.tf @@ -0,0 +1,97 @@ + +# Scylla Cloud API token +variable "scylla_cloud_token" { + description = "Scylla Cloud API token" + type = string + default = "" +} + +# 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 = "" +} + +# 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 + +}