Improve perfomance using redis
acloudguru.com/blog/engineering/cloudguruch..
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
![FromFlask.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627570193391/gtexPxq-_.png)
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