Last active
January 24, 2025 17:17
-
-
Save mikesparr/62631b855e0854d6c47602fed9dc34ba to your computer and use it in GitHub Desktop.
Experiment with Google Cloud Memorystore Redis instances fronted by internal load balancer and Twemproxy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| ##################################################################### | |
| # REFERENCES | |
| # - https://cloud.google.com/blog/products/databases/running-redis-on-gcp-four-deployment-scenarios | |
| # - https://cloud.google.com/memorystore/docs/redis/high-availability | |
| # - https://redis.com/redis-enterprise/technology/highly-available-redis/ | |
| ##################################################################### | |
| export PROJECT_ID=$(gcloud config get-value project) | |
| export PROJECT_USER=$(gcloud config get-value core/account) # set current user | |
| export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)") | |
| export IDNS=${PROJECT_ID}.svc.id.goog # workload identity domain | |
| export GCP_REGION="us-central1" # CHANGEME (OPT) | |
| export GCP_ZONE="us-central1-a" # CHANGEME (OPT) | |
| export NETWORK_NAME="default" | |
| # enable apis | |
| gcloud services enable compute.googleapis.com \ | |
| redis.googleapis.com \ | |
| artifactregistry.googleapis.com \ | |
| cloudbuild.googleapis.com \ | |
| storage.googleapis.com | |
| # configure gcloud sdk | |
| gcloud config set compute/region $GCP_REGION | |
| gcloud config set compute/zone $GCP_ZONE | |
| ##################################################################### | |
| # ARTIFACT REGISTRY SETUP | |
| ##################################################################### | |
| # create repository | |
| export REPO_NAME="pod3" # CHANGEME (OPT) | |
| gcloud artifacts repositories create $REPO_NAME \ | |
| --repository-format=docker \ | |
| --location=$GCP_REGION \ | |
| --description="Docker repository" | |
| # configure auth | |
| gcloud auth configure-docker ${GCP_REGION}-docker.pkg.dev | |
| ##################################################################### | |
| # REDIS INSTANCES | |
| # | |
| # TIP: this can take a long time, but CTRL+C will cycle through loop and launch them in parallel | |
| # | |
| ##################################################################### | |
| # create redis memorystore instances | |
| for i in {1..9}; do gcloud redis instances create redis${i} --size=1 --region=$GCP_REGION --tier=STANDARD; done | |
| ##################################################################### | |
| # TWEMPROXY DOCKER IMAGE | |
| ##################################################################### | |
| # prepare Twemproxy container | |
| export PROXY_DIR="twemproxy" | |
| export PROXY_CONFIG_FILE="nutcracker.yml" | |
| export IMAGE_NAME="twemproxy" | |
| export TAG_NAME="test1" | |
| export PROXY_PORT=26379 | |
| mkdir $PROXY_DIR | |
| cd $PROXY_DIR | |
| cat > $PROXY_CONFIG_FILE << EOF | |
| alpha: | |
| listen: 0.0.0.0:$PROXY_PORT | |
| hash: fnv1a_64 | |
| distribution: ketama | |
| timeout: 1000 | |
| backlog: 512 | |
| preconnect: true | |
| redis: true | |
| auto_eject_hosts: true | |
| server_retry_timeout: 2000 | |
| server_failure_limit: 2 | |
| servers: | |
| EOF | |
| # append redis servers to config file | |
| gcloud redis instances list \ | |
| --region=$GCP_REGION | awk '{ printf " - %s:%s:1\n", $6, $7 }' | tail -n +2 >> $PROXY_CONFIG_FILE | |
| # create dockerfile | |
| cat > Dockerfile << EOF | |
| FROM alpine:3.16.2 | |
| RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories | |
| RUN apk add --update twemproxy | |
| EXPOSE $PROXY_PORT | |
| COPY $PROXY_CONFIG_FILE /etc/nutcracker/ | |
| ENTRYPOINT ["/usr/sbin/nutcracker"] | |
| CMD ["-c", "/etc/nutcracker/$PROXY_CONFIG_FILE"] | |
| EOF | |
| # build / push image to artifact registry (using local Dockerfile) | |
| gcloud builds submit --tag ${GCP_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${TAG_NAME} | |
| ##################################################################### | |
| # TWEMPROXY CLUSTER | |
| ##################################################################### | |
| export INSTANCE_TEMPLATE_NAME="twemproxy" | |
| export INSTANCE_GROUP_NAME="ig-twemproxy" | |
| # create instance template | |
| gcloud compute instance-templates create-with-container $INSTANCE_TEMPLATE_NAME \ | |
| --machine-type=n1-standard-8 \ | |
| --tags=twemproxy-$PROXY_PORT,allow-health-checks-tcp \ | |
| --container-image ${GCP_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${TAG_NAME} | |
| # create managed instance group | |
| gcloud compute instance-groups managed create $INSTANCE_GROUP_NAME \ | |
| --base-instance-name $INSTANCE_GROUP_NAME \ | |
| --size 3 \ | |
| --template twemproxy \ | |
| --region $GCP_REGION | |
| gcloud compute instance-groups managed set-autoscaling $INSTANCE_GROUP_NAME \ | |
| --max-num-replicas 10 \ | |
| --min-num-replicas 3 \ | |
| --target-cpu-utilization 0.6 \ | |
| --cool-down-period 60 \ | |
| --region $GCP_REGION | |
| ##################################################################### | |
| # LOAD BALANCING | |
| ##################################################################### | |
| export HEALTH_CHECK_NAME="hc-twemproxy" | |
| export LOAD_BALANCER_NAME="ilb-twemproxy" | |
| export FWD_RULE_NAME="fr-ilb-twemproxy" | |
| # create health check | |
| gcloud compute health-checks create tcp $HEALTH_CHECK_NAME \ | |
| --port $PROXY_PORT --check-interval 5 --healthy-threshold 2 | |
| # create backend service | |
| gcloud compute backend-services create $LOAD_BALANCER_NAME \ | |
| --load-balancing-scheme internal \ | |
| --session-affinity client_ip_port_proto \ | |
| --region $GCP_REGION \ | |
| --health-checks $HEALTH_CHECK_NAME \ | |
| --protocol tcp | |
| # add instance group to backend | |
| gcloud compute backend-services add-backend $LOAD_BALANCER_NAME \ | |
| --instance-group $INSTANCE_GROUP_NAME \ | |
| --instance-group-region $GCP_REGION \ | |
| --region $GCP_REGION | |
| # add forwarding rule | |
| gcloud compute forwarding-rules create $FWD_RULE_NAME \ | |
| --load-balancing-scheme internal \ | |
| --ip-protocol tcp \ | |
| --ports $PROXY_PORT \ | |
| --backend-service $LOAD_BALANCER_NAME \ | |
| --region $GCP_REGION | |
| # add firewall rules | |
| gcloud compute firewall-rules create allow-twemproxy \ | |
| --action allow --direction INGRESS \ | |
| --source-ranges 10.128.0.0/20 \ | |
| --target-tags twemproxy-$PROXY_PORT \ | |
| --rules tcp:$PROXY_PORT | |
| gcloud compute firewall-rules create allow-health-check \ | |
| --action allow --direction INGRESS \ | |
| --source-ranges 130.211.0.0/22,35.191.0.0/16 \ | |
| --target-tags allow-health-checks-tcp \ | |
| --rules tcp,udp,icmp | |
| # set load balancer IP | |
| export ILB_ADDRESS=$(gcloud compute forwarding-rules describe $FWD_RULE_NAME --format="value(IPAddress)") | |
| ##################################################################### | |
| # BENCHMARKING (TEMPORARY INSTANCE) | |
| ##################################################################### | |
| export TEST_VM_NAME="redis-benchmark" | |
| export SCRIPT_NAME="startup.sh" | |
| # create startup script to install redis tools | |
| cat > $SCRIPT_NAME << EOF | |
| #! /bin/bash | |
| apt update | |
| apt -y install redis-tools | |
| EOF | |
| # create instance with startup script (local) | |
| gcloud compute instances create $TEST_VM_NAME \ | |
| --image-project=debian-cloud \ | |
| --image-family=debian-10 \ | |
| --metadata-from-file=startup-script="./$SCRIPT_NAME" | |
| # test redis proxy connection (ping => PONG) | |
| gcloud compute ssh \ | |
| --zone $GCP_ZONE $TEST_VM_NAME \ | |
| -- redis-cli -h $ILB_ADDRESS -p $PROXY_PORT ping | |
| # run redis benchmark | |
| gcloud compute ssh \ | |
| --zone $GCP_ZONE $TEST_VM_NAME \ | |
| -- redis-benchmark -q -h $ILB_ADDRESS -p $PROXY_PORT \ | |
| -c 100 -n 1000000 -k 1 -t set,get,mset,incr,lpush,lpop,sadd,spop,lpush,lrange | |
| ##################################################################### | |
| # CLEAN UP | |
| ##################################################################### | |
| # change to parent dir | |
| cd .. | |
| # remove working dir | |
| rm -rf $PROXY_DIR="twemproxy" | |
| # delete benchmark instance | |
| gcloud compute instances delete $TEST_VM_NAME | |
| # delete project to avoid unnecessary billing | |
| gcloud projects delete $PROJECT_ID |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Overview
An article shared by a customer was very dated so I wanted to update and simplify the instructions to try out Twemproxy and ILB fronting a pool of Redis servers run by Google Cloud Memorystore.
Changes
awkscript to capture correct columns (IP,PORT)Result