Cloud Challenge- Using Redis and RDS.
#CloudGuruChallenge
Improve perfomance using redis
https://acloudguru.com/blog/engineering/cloudguruchallenge-improve-application-performance-using-amazon-elasticache
For accomplish this issue I required:
- a valid AWS profile
- a valid KeyPair to be used in the EC2.
Steps
Implement RDS,VPC,EC2,REDIS using cdk
let vpc = new ec2.Vpc(this,'ChallengeVPC',{
cidr:'10.0.0.0/16',
natGateways:1,
maxAzs:2,
subnetConfiguration: [
{
cidrMask:24,
name:'App',
subnetType:ec2.SubnetType.PUBLIC
},
{
cidrMask:24,
name:'Rds',
subnetType:ec2.SubnetType.PRIVATE
},
{
cidrMask:24,
name:'Cache',
subnetType:ec2.SubnetType.PRIVATE
}
]
});
let subnetsForCluster = vpc.selectSubnets({ subnetGroupName:'Cache'});
let subnetsForRds = vpc.selectSubnets({subnetGroupName:'Rds'});
let ec2SG= new ec2.SecurityGroup(this,'ec2SG',{
vpc:vpc,
allowAllOutbound:true
});
const bastion = new BastionHostLinux(this,'bastion-id', {
vpc: vpc,
securityGroup: ec2SG,
instanceName: 'instance-bastion',
machineImage: new AmazonLinuxImage(),
instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.MICRO),
subnetSelection: vpc.selectSubnets({subnetType: ec2.SubnetType.PUBLIC})
});
bastion.instance.instance.addPropertyOverride('KeyName', 'for-bastion');
let clusterSG= new ec2.SecurityGroup(this,'redisSG',{
vpc:vpc,
securityGroupName:"Security group for REDIS"
});
let rdsSG = new ec2.SecurityGroup(this,'rdsSG',{
vpc:vpc
});
clusterSG.addIngressRule(ec2SG,ec2.Port.tcp(6579),'allow from ec2');
rdsSG.addIngressRule(ec2SG,ec2.Port.tcp(5432),'allow from ec2');
ec2SG.addIngressRule(Peer.anyIpv4(),ec2.Port.tcp(8080),'allow 8080 for public');
ec2SG.addIngressRule(Peer.anyIpv4(),ec2.Port.tcp(80),'allow 8080 for public');
ec2SG.addIngressRule(Peer.anyIpv4(),ec2.Port.tcp(22),'allow ssh from the world');
let subnetRDS = new rds.SubnetGroup(this,'subnet for rds',{
vpc: vpc,
description:'rds for data',
subnetGroupName:"subnet for rds",
vpcSubnets: {
subnets:subnetsForRds.subnets
}
});
let db = new rds.DatabaseInstance(this,'db-instance',{
vpc,
engine:rds.DatabaseInstanceEngine.postgres({
version:rds.PostgresEngineVersion.VER_11
}),
securityGroups:[rdsSG],
subnetGroup:subnetRDS,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3,
ec2.InstanceSize.MICRO),
multiAz:false,
databaseName:'dbname',
//@ts-ignore
credentials:rds.Credentials.fromPassword('administrator',SecretValue.plainText("paraguay"))
});
let subnetGroupRedis: CfnSubnetGroup;
// @ts-ignore
subnetGroupRedis = new elastic.CfnSubnetGroup(this, "Redis subnetGroup", {
cacheSubnetGroupName: "redis-private",
subnetIds: subnetsForCluster.subnetIds,
description: "Subnet para el redis"
});
// @ts-ignore
let redis = new elastic.CfnCacheCluster(this,
'Redis Cluster',{
engine:'redis',
cacheNodeType:"cache.t2.micro",
numCacheNodes:1,
clusterName:"cluster-redis",
vpcSecurityGroupIds:[clusterSG.securityGroupId],
cacheSubnetGroupName:subnetGroupRedis.cacheSubnetGroupName,
});
redis.addDependsOn(subnetGroupRedis);
Log by ssh
Inside the public ec2:
ssh ec2-user@34.xxx.xxx.xxx -i keys/for-bastion.pem
install psycopg2,postgres,flask,parserconfig,redis
Modifications to file [app.py]
# /usr/bin/python2.7
import psycopg2
from configparser import ConfigParser
from flask import Flask, request, render_template, g, abort
import time
import redis
def config(filename='config/database.ini', section='postgresql'):
# create a parser
parser = ConfigParser()
# read config file
parser.read(filename)
# get section, default to postgresql
db = {}
if parser.has_section(section):
params = parser.items(section)
for param in params:
db[param[0]] = param[1]
else:
raise Exception('Section {0} not found in the {1} file'.format(section, filename))
return db
def fetch(sql):
# connect to database listed in database.ini
ttl = 10 # Time to live in seconds
try:
params = config(filename='config/database.ini',section='redis')
cache = redis.Redis.from_url(params['redis_url'])
result = cache.get(sql)
if result:
return result
else:
# connect to database listed in database.ini
conn = connect()
cur = conn.cursor()
cur.execute(sql)
# fetch one row
result = cur.fetchone()
print('Closing connection to database...')
cur.close()
conn.close()
# cache result
cache.setex(sql, ttl, ''.join(result))
return result
except (Exception, psycopg2.DatabaseError) as error:
print(error)
def connect():
""" Connect to the PostgreSQL database server and return a cursor """
conn = None
try:
# read connection parameters
params = config()
# connect to the PostgreSQL server
print('Connecting to the PostgreSQL database...')
conn = psycopg2.connect(**params)
except (Exception, psycopg2.DatabaseError) as error:
print("Error:", error)
conn = None
else:
# return a conn
return conn
app = Flask(__name__)
@app.before_request
def before_request():
g.request_start_time = time.time()
g.request_time = lambda: "%.5fs" % (time.time() - g.request_start_time)
@app.route("/")
def index():
sql = 'SELECT slow_version();'
db_result = fetch(sql)
if(db_result):
db_version = "".join([str(i) for i in db_result])
else:
abort(500)
params = config()
return render_template('index.html', db_version = db_version, db_host = params['host'])
if __name__ == "__main__": # on running python app.py
app.run() # run the flask app

Modifications to config/database.ini
[postgresql]
host=database-1.covqqx1gffj6.us-east-1.rds.amazonaws.com
database=challenge
user=challenge
password=ACGChall3ng3
[redis]
redis_url=redis://cluster-redis.6ddjjb.0001.use1.cache.amazonaws.com:6379
We can see the response using the RDS response

From the log of EC2

Response using redis

From the log,we can see that is not requesting the RDS

About the author
I am developer from Paraguay, a person who loves to code and learn many things.
Comments
Join the discussionNo comments yet. Be the first to comment.