# Cloud Challenge- Using Redis and RDS.

### 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
                                                                  
![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](https://cdn.hashnode.com/res/hashnode/image/upload/v1627570503194/f3OZ1yfcI.png)

From the log of EC2

![FromFlask.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627570451586/Tzb8QLgzG.png)

Response using redis


![Redis.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627570539620/Mny8OQUXH.png)


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


![RedisResponse.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627570563353/aHPjQo_J-.png)

