Cloud Challenge- Using Redis and RDS.

#CloudGuruChallenge

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 -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

CallWebServerFlask.png

From the log of EC2

FromFlask.png

Response using redis

Redis.png

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

RedisResponse.png