Cheat Sheet-Amazon Web Services – Networking -Route 53

Introduction

  • Route 53 is AWS’s proprietary DNS service.
  • AWS written Route 53 from scratch i.e. do not use any code base, service for implementation.
  • What is DNS?
  • It can be consider as Domain names to IP mapping.
  • It is helpful for converting human friendly domain names into IP addresses by machines.
  • Why Route 53 name for AWS DNS?

By default DNS use default port 53 for TCP or UDP for communication.

  • Route 53 is global service not specific to any AWS Region.
  • It has API which help us to programmatically perform various operations.

Important Concepts for DNS

IP address types

  • IPv4
  • Represent 32 bit i.e. nearly 4 billion IPv4 addresses
  • IPv6
  • Represent 128 bit
  • Need: – every time when we add new device on internet we need to represent it with some unique identifier. As more and more devices available on internet and due to IOT devices we ran out of IPv4 addresses. IPv6 help us to resolve this IP scarcity issue.
  • Till Dec 2016 AWS don’t support IPv6

Domain registrar

  • Domain registrar is authority which ensure uniqueness of domain names to avoid duplication
  • Domains are registered with InterNIC and WhoIs database
  • Example of domain registrar
    • GoDaddy
    • Recently Amazon became domain registrar hence become bit easier to work with DNS

TTL

  • Indicates Time to live
  • It indicates amount of time DNS record cached on resolving server or user’s own PC.
  • It represented in seconds
  • Example :- whenever we request any specific domain name then our PC will check if it has address associated with this domain or not. If not then it will fetch it from resolving server. As soon as our PC receive IP associated with domain name it will cache that specific IP for time period of TTL. For next request our local PC will request it from cache and not from resolving server.
  • Caveat for DNS migration :- if we are adding additional
  • A record or
  • additional service to our production website
  • or moving application to AWS
  • Then many websites reduce TTL record to 300 seconds so that changes replicated across all client machines and then wait for previous TTL period.
  • If we don’t do this then few of our client request will go to old site while other go to new site.
  • Many applications have TTL by default for 2 days.

Caveat

  • We cannot use Route 53 to configure instances on premises.
  • We can support on premises DNS to support Amazon VPC.

DNS Records supported by Route 53

Type
A Address Record

§ Used by machine to translate the name of domain to IP addresses

§  Usually one domain name mapped to multiple IP addresses.

AAAA IPv6 Address Record.
PTR Pointer Record

It is exact opposite of A record i.e. it will provide domain name when IP address is provided.

A-AAAA

Reverse lookup i.e. fetching domain from IP
Example for YAHOO IP address

ptr

Type
NS Name Server Record

It is used by top level domain servers to direct traffic to the content DNS server.

SOA Start of authority record.

§   It is very first Name server for our domain name.

§   It gives majority of information for our domain

 

Type
CNAME Canonical Record Name

§   It is used to resolve one domain name to another domain.

§   A record points to IP address but CName points to another domain.

§   E.g. m.amazon.com and mobile.amazon.com both point to same application.

 

Alias ·         This term is specific to AWS

 

  • Need for Alias
  • The problem is with a cname you cannot use the cname in the “apex” of a domain. Meaning mydomain.com cannot point to a cname. But http://www.mydomain.com can.
  • Difference between CNAME and Alias
  • Both Alias and CNAME points to different DNS record.
  • CNAME cannot be used for Zone Apex record (naked domain names)
  • They differ from a CNAME record in that they are not visible to resolvers. Resolvers only see the A record and the resulting IP address of the target record.
What is mean by Naked domain name?
Internet domain name without www or subdomain is known as Naked domain name.

http://computerlanguage.com/ is naked domain

but http://www.computerlanguage.com/ is not naked domain.

Other record types

  • CAA (certification authority authorization)
  • MX (mail exchange record)
  • NAPTR (name authority pointer record)
  • SPF (sender policy framework)
  • SRV (service locator)
  • TXT (text record)

Routing Policies

Simple

  • It is default routing policy
  • We can associate A record with multiple IP addresses
  • Requests are handled in round robin fashion
  • Does not perform health check hence if any issue occurred with instance then user will get error message.

Weighted

  • Similar to Simple routing policy with following difference
  • Use to route traffic to multiple resources in proportions that you specify. E.g. if we have three servers then we can set policy to route 50% traffic to first server, 40 % to second server and remaining 10% to third server.
  • Use cases
  • We are having servers of different capacity in that case we can use this policy i.e. routing most of the traffic to server with higher capacity.
  • In few scenarios we might need to get early feedback from customer for newly developed UI. In that scenario we can use this strategy.

 

Latency

  • When our system used from multiple geographic location and our system is also present in multiple AWS regions then this strategy used.
  • Route traffic to the resource that provides the best latency.

Failover

  • Use when you want to configure active-passive failover.
  • Route 53 will perform health check. If health check fails for primary site then it will route traffic to secondary site.

Geolocation

  • Use when we are having application catering to customers all over the world.
  • Consider we are having AWS environment in Europe and Asia and If we set this routing policy then users from Netherlands can route requests to Application customized for Dutch. If someone is coming from India then AWS will route request for application customized for India based users.

 

 

Advertisements

Amazon Web Services – Storage

This mind map highlight various storage types and supported services in AWS

AWS_storage

 

Mind map for simple storage service(S3)

simple_storage_service (1)

 

Mind map for cloud front

Cloud_front

 

Mind map for block storage supported by AWS

Block_storage

 

Spring Boot, Spring Cloud Lectures

  1. Spring Boot, Cloud Micro Services Introduction
    1. Monolithic Applications Advantages Drawbacks
    2. Reactive Application

Performance Tip :- Avoid Catching Exceptions

Introduction

In this post we will look at simple example how does catching exception impact performance.

Code Sample

Code for catching exception

private static void exceptionTest(){
 int i=0;
 int j=1;
 try{
 int k=j/i;
 }catch(ArithmeticException ex){
 //not good idea to catch run time exception but catch for demo only
 }
 }

Code where conditions are handled

private static void withoutExceptionTest(){
 int i=0;
 int j=1;
 if(i>0){
 int k=j/i;
 }
 }

method to call logic

private static long exceptionTestLoop(int iterations,boolean isCatchException){
 long startTime=System.nanoTime();
 for(int i=0;i<iterations;i++){
 if(isCatchException){
 exceptionTest();
 }else{
 withoutExceptionTest();
 }
 }
 long endTime=System.nanoTime();
 long time=endTime-startTime;
 return time;
 }

main method

public static void main(String[] args) {
 int itr=1000000;
 long timeForCatching=exceptionTestLoop(itr,true);
 long time=exceptionTestLoop(itr,false);
 System.out.println("Time for catching Exception "+timeForCatching+" without catching "+time);
 }

Results

exception_catch

Conclusion

Avoid catching exception as it will reduce response time. above example demonstrate results for simple single threaded application but situation become worst in multi threaded environment.

Compare JSON API

Introduction

In this post we will compare   two famous JSON specific API i.e.  GSON and Jackson from performance point of view. json_1

Code

Wrapper

This class is used for conversion to JSON

public class MeasurementRecord {
       private String measurementId;
      private long duration;
      private long time;
      private MeasurementType type=MeasurementType.METHOD_CALL;
       public MeasurementRecord(String measurementId, long duration, long time,
              MeasurementType type) {
             super();
             this.measurementId = measurementId;
             this.duration = duration;
             this.time = time;
             this.type = type;
       }
//getters and setters
}

code for creating list

private static List<String> getList(int iteration){
    List l=new ArrayList();
    for(int i=0;i<iteration;i++){
    l.add(new MeasurementRecord("/test.html", 10, System.currentTimeMillis(), MeasurementType.WEB_REQUEST));
    }
    return l;
    }

Jackson API

private static long jacksonTest(int iteration)throws Exception{
             ObjectMapper mapper=new ObjectMapper();
             List<String> l=getList(iteration);
             long T1=System.nanoTime();
             String json=mapper.writeValueAsString(l);
             long T2=System.nanoTime();
             return (T2-T1);
       }

Gson API

private static long gsonTest(int iteration){
             Gson gson = new GsonBuilder().create();
             List l=getList(iteration);
             long T1=System.nanoTime();
             String json=gson.toJson(l);
             long T2=System.nanoTime();
             return (T2-T1);
       }

Results results graph

Conclusion

For converting small or medium size list GSON provide better response as compared to Jackson but for large size list Jackson provide some better response than GSON. Based on this results one can conclude that for converting small or medium size list to JSON one can use GSON for better performance.

Angular JS Service

Introduction

in previous post we concentrated on how to consume json data from server. i.e.  user provide stock symbol in search box and and click on search button.

in this post we will add one more functionality i.e. adding stock to watch list(although stock data is not updated but we will check how to auto refresh this data in next post.)

Need for Service

Irrespective of programming language service provide following benefits

  1. writing business logic
  2. writing common code which can be reused by multiple controllers

apart from this in angular js it provide one more benefit i.e. caching of data which can be accessed by multiple controllers, giving http call.

UI

User provide stock symbol and click search.

search_result

user click on add to watch list system will add stock in watch list.

bookMark

In view(html) use

  1. stockSearchWatchListController.js  :-JS for searching stock and adding it to watchlist
  2. yahooFinanceYQLAPIService.js :-
    1. Service for communicating with remote server on http.
    2. Caching common data required for searching and watchlist activities.
  3. we are using google font

<script src=”https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js”></script&gt;
        <script src=”stockSearchWatchListController.js”></script>
        <script src=”yahooFinanceYQLAPIService.js”></script>
        <link href=’http://fonts.googleapis.com/css?family=Amaranth:400,400italic&#8217; rel=’stylesheet’ type=’text/css’>
       
        <style>
            body {font-family: ‘Amaranth’, sans-serif;}
            table, th , td {border: 1px solid grey;border-collapse: collapse;padding: 5px;}
            table tr:nth-child(even) {background-color: #f1f1f1;}
            table tr:nth-child(odd) {background-color: #ffffff;}
            table th {background-color: #A0AFD8;color:F9F7F7;}
            button {background-color: #A0AFD8;  border-radius: 5px;font-style: italic; text-decoration: underline;}
            input{border-radius: 5px; font-style: italic;}
        </style>

Create module in stockSearchWatchListController.js

//define module named stockModule
var stockModule = angular.module(‘stockModule’,[]);

Create yahooFinanceYQLAPIService and register it in module

Create default implementation  of 

var yahooFinanceYQLAPIService=function($http){

//default implementation

}; 

 Register service with module.

 var module=angular.module(“stockModule”);

module.factory(“yahooFinanceYQLAPIService”,yahooFinanceYQLAPIService);

stockSearchWatchListController.js

//define module named stockModule
var stockModule = angular.module(‘stockModule’,[]);
//replace $http with yahooFinanceYQLAPIService since yahooFinanceYQLAPIService is taking care of http communication
stockModule.controller(‘myStockSeachController’,function($scope,yahooFinanceYQLAPIService){
    $scope.getScriptDetails=function(){
        console.log(“script details “+$scope.scriptcode);
        var response=yahooFinanceYQLAPIService.getScriptsDetails($scope.scriptcode);
        response.success(function(data, status, headers, config) {
                $scope.scriptDetails=data;
        });
      
        response.error(function(data, status, headers, config) {
                console.log(“failure “+data+” status “+status+” headers “+headers);
        });
          
    };
   
});

stockModule.controller(‘addStockToWatchListController’,function($scope,yahooFinanceYQLAPIService){
    $scope.addToWatchList=function(){
        console.log(“adding script to watchList”);
        var response=yahooFinanceYQLAPIService.addScriptToWatchList();
        if (response === undefined) {
            return;
        }
        response.success(function(data, status, headers, config) {
                if(data.query.count!=1){
                    $scope.scripts=data.query.results.quote;
                }else{
                    var scriptArray=[];
                    scriptArray.push(data.query.results.quote);
                    $scope.scripts=scriptArray;
                }
        });
      
        response.error(function(data, status, headers, config) {
                console.log(“failure “+data+” status “+status+” headers “+headers);
        });
      
    };
   
 
    });

yahooFinanceYQLAPIService.js

var yahooFinanceYQLAPIService=function($http){
    var latestScriptCode=”;//useful for addScriptToWatchList i.e. shared between both search controller and watchlist controller.
    var getScriptsDetails=function(script){
        var url=’https://query.yahooapis.com/v1/public/yql&#8217;;
        var query=’select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22’+’\”+script+’%22)&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback’;
        url=url+’?q=’+query;
        latestScriptCode=script;
        return $http.get(url);
    };

var watchListScripts=[];
    var addScriptToWatchList=function addScriptToWatchList(){
        if(watchListScripts.indexOf(latestScriptCode)>=0){
            return;
        }
        watchListScripts.push(latestScriptCode);
        console.log(“watchListScripts:- “+watchListScripts.join());
        var url=’https://query.yahooapis.com/v1/public/yql&#8217;;
        var query=’select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22’+’\”+watchListScripts.join()+’%22)&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback’;
        url=url+’?q=’+query;
        return $http.get(url);
    };

    return{
        getScriptsDetails:getScriptsDetails,
        addScriptToWatchList:addScriptToWatchList
    };
}; 

var module=angular.module(“stockModule”);
module.factory(“yahooFinanceYQLAPIService”,yahooFinanceYQLAPIService);

view(html)

    <body ng-app=”stockModule”>
        <div ng-controller=”myStockSeachController” align=”center”>
                <div>Stock Quote</div>
                <div>
                    <form name=”stockQuoteForm”>
                            <input type=”text” required placeholder=”scriptcode” class=”form-control”    ng-model=”scriptcode”>
                            <button ng-click=”getScriptDetails()” type=”button” class=”btn btn-primary”>Search</button>
                    </form>
                </div>
            <table     ng-show=”scriptDetails”>
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>symbol</th>
                        <th>LastTradePriceOnly</th>
                        <th>Ask</th>
                        <th>Bid</th>
                        <th>AverageDailyVolume</th>
                        <th>Currency</th>
                        <th>LastTradeDate</th>
                        <th>LastTradeTime</th>
                        <th>DaysLow</th>
                        <th>DaysHigh</th>
                        <th>YearLow</th>
                        <th>YearHigh</th>
                        <th>PE Ratio</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>{{scriptDetails.query.results.quote.Name}}</td>
                        <td>{{scriptDetails.query.results.quote.symbol}}</td>
                        <td>{{scriptDetails.query.results.quote.LastTradePriceOnly}}</td>
                        <td>{{scriptDetails.query.results.quote.Ask}}</td>
                        <td>{{scriptDetails.query.results.quote.Bid}}</td>
                        <td>{{scriptDetails.query.results.quote.AverageDailyVolume}}</td>
                        <td>{{scriptDetails.query.results.quote.Currency}}</td>
                        <td>{{scriptDetails.query.results.quote.LastTradeDate}}</td>
                        <td>{{scriptDetails.query.results.quote.LastTradeTime}}</td>
                        <td>{{scriptDetails.query.results.quote.DaysLow}}</td>
                        <td>{{scriptDetails.query.results.quote.DaysHigh}}</td>
                        <td>{{scriptDetails.query.results.quote.YearLow}}</td>
                        <td>{{scriptDetails.query.results.quote.YearHigh}}</td>
                        <td>{{scriptDetails.query.results.quote.PERatio}}</td>
                    </tr>
                </tbody>
            </table>
            </div>
   
   
    <div ng-controller=”addStockToWatchListController” align=”center”>
        <p>
        <button ng-click=”addToWatchList()” type=”button” class=”btn btn-primary”>AddToWatchList</button>
        </p>
        <div ng-show=”scripts”>
            <table>
                <thead>
                    <tr>
                        <th ng-click=”sortColumn(‘Name’)” >Name</th>
                        <th  ng-click=”sortColumn(‘symbol’)”>symbol</th>
                        <th  ng-click=”sortColumn(‘LastTradePriceOnly’)”>LastTradePriceOnly</th>
                        <th  ng-click=”sortColumn(‘Ask’)”>Ask</th>
                        <th  ng-click=”sortColumn(‘Bid’)”>Bid</th>
                        <th  ng-click=”sortColumn(‘AverageDailyVolume’)”>AverageDailyVolume</th>
                        <th>Currency</th>
                        <th  ng-click=”sortColumn(‘LastTradeDate’)”>LastTradeDate</th>
                        <th  ng-click=”sortColumn(‘LastTradeTime’)”>LastTradeTime</th>
                        <th  ng-click=”sortColumn(‘DaysLow’)”>DaysLow</th>
                        <th ng-click=”sortColumn(‘DaysHigh’)”>DaysHigh</th>
                        <th  ng-click=”sortColumn(‘YearLow’)”>YearLow</th>
                        <th  ng-click=”sortColumn(‘YearHigh’)”>YearHigh</th>
                        <th  ng-click=”sortColumn(‘PERatio’)”>PE Ratio</th>
                    </tr>
                </thead>
                <tbody>
                    <tr ng-repeat=”sc in scripts”>
                        <td>{{sc.Name}}</td>
                        <td>{{sc.symbol}}</td>
                        <td>{{sc.LastTradePriceOnly}}</td>
                        <td>{{sc.Ask}}</td>
                        <td>{{sc.Bid}}</td>
                        <td>{{sc.AverageDailyVolume}}</td>
                        <td>{{sc.Currency}}</td>
                        <td>{{sc.LastTradeDate}}</td>
                        <td>{{sc.LastTradeTime}}</td>
                        <td>{{sc.DaysLow}}</td>
                        <td>{{sc.DaysHigh}}</td>
                        <td>{{sc.YearLow}}</td>
                        <td>{{sc.YearHigh}}</td>
                        <td>{{sc.PERatio}}</td>
                    </tr>
                </tbody>
        </table>
    </div>
    </div>
   
               
      
</body>
 

 

 

Step by step approach for web application performance improvement.

Introduction

This  post will concentrate on optimal ways to improve performance of Java based web application (although this post concentrates on Java based web application same thought process can be applied to web applications developed in other technology stack) without impacting monetary cost.

We will cover the following points from performance point of view.

  1. Important factors impacting performance of system.
  2. Patterns of performance issues
  3. Step by step approach in improving performance of system by keeping same infrastructure, i.e. without impacting cost to project.

Performance improvement activity is not a one time activity, but it is an iterative activity which involves PDCA (Plan, Do, Check, Act)

Factors impacting web application performance.

  1. Total number of users accessing (logged into) system
  2. Total number of transactions hitting to the system
  3. The Total amount of data fetched by the  client (both human and other systems)

By looking at above parameters one can easily say the performance of system degrades when any of these parameters increases.

Ways to improve performance of the system is by

  • Reducing load on system with the help of distributing load across systems (This approach mostly involves hardware cost and installation of load balancer hence we will not concentrate on this point here, but can be implemented once steps involved in this post are implemented. ).
  • Make the system work for the  least  amount of data to for request received by the client.

Patterns  for  Performance issues

Whenever a performance issue occurred one can observe any of these patterns.

  1. Issue specific to single user
    1. In order to determine RCA for these types of issue one needs to determine if client  system has incompatible software installed or some  upgradation happened recently.
  2. An issue occurred only at a specific site/location
    1. Probable root cause for these types of problems
      1. Network related issues at that specific location
    2. Incompatible software installation or some upgradation happened recently.
  3. Issue observed only for specific functionality.
    1. One needs to find the issue is specific to code, persistence layer or it is specific to external interface (webservice, JMS) system is communicating.
  4. Issue observed across all locations during a specific time frame (work hours, month end etc)
    1. These types of issues are examples of system unable to handle load.
  5. Issue observed intermittently
    1. These types of issues are more dangerous and root cause of these types of problems can be observed by taking heap/thread dumps.

Important components in  web applications

Majority of web applications will have the following components

application

Steps to improve the performance of the system.

Although one can improve performance  of system by various techniques, but ideal way is to improve performance at client layer then at application code level and at the end at persistence layer.

improve performance  from client side —>Application Code—> Persistence layer.

Steps  at   client side (browser)

These actions are related to working primarily on static content, i.e. Java Script, CSS, Images etc.

Segregate inline JS, CSS to separate JS, CSS file

Many standard browsers have important feature i.e. caching of static content (JS, CSS). Writing inline JS and CSS kills caching feature provided by the browser. Inline static content also involves pain of moving information from host to client for each client request.

This activity is a good example of making the system work on less data.

Following is screenshot for Mozilla browser indicating the amount of data transferred and the time taken in order to complete a request for first time any subsequent calls will not give call to the server but will load from the local cache of browsers.

page_loading

Replace existing JS, CSS by minified JS.

Minification is activity of removing unwanted data (whitespace, comments) from production ready static content. Few tools also provide a facility for converting big variables into small. This way one can reduce the amount of data to be transferred to client side.

A web application can have both application specific JS, CSS and  third party JS, CSS (e.g.. JQuery, Angular JS, Bootstrap…..).

Various famous  JS, CSS libraries provide both  minified and normal versions (minified version removes all unnecessary white spaces. Replace long identifiers by short).

Following is screenshot indicating the amount of data downloaded and time taken for loading minifed version of angular js.

page_loading_min

The total amount of improvement in time  (509-78) *100/509 nearly 84%

Total amount of improvement in data (937.81-122.96)*100 /937.81 nearly 86%

Compressing application specific static content

In order to compress application specific static content (JS, CSS) various modification tools available

Few common examples of compressors

  1. YUI Compressor: – Tool from Yahoo
  2. JsMin: – from Douglas Crockford, one of the most respected personality in the field Java script.
  3. Google Closure: -Tool from Google

Remove Http 404 status code

Http 404 status code sent by the http host  when requested resource not available to host. These types of requests create unnecessary network round trips.

Following links help in configuring access logs for jboss and Weblogic server.

Configure access logs in Weblogic

Configure access logs in JBOSS

Imp Note: - enabling access log in, the system will increase load on system, hence must be used with caution.

Replace client side pagination/huge table data by server side pagination

Server side pagination help loading page quickly. This technique fetches only required records to be displayed on the view.

Another way to improve page loading time is by forcing users to narrow down searches.

Steps  on   the server  (application/web server) side

Integrate application with the application performance monitoring (APM) tool.

Purpose of integrating these tools is to measure performance of the system in production with minimal load on system. It also helps in determining parameters during load. Although the majority of these tools utilizes java’s bytecode instrumentation, but JAMon provides Aspect oriented programming (AOP).

Important parameters from performance point of view.

  • Maximum number of users logged into the system.
  • Maximum transactions hitting to the system (determine transaction rate)
  • Most frequently hit URLS on the system.
  • Slow Running transactions in the system.
  • Slow Running SQL queries.
  • Most frequently occurred Exceptions.

Following are few important APM tools.

table

Some other APM tools are New Relic, Compuware Dyna trace. These tools  along with AppDynamics present in Gartner’s magic quadrant.

Reduce IO

One can use following techniques for reducing IO.

  • Reduce number of logs to file
  • Remove System.out.println
  • Reduce size of log file :- it is always better to write to small files instead of writing and analyzing huge files
  • Avoid catching too many exceptions in the system. Handle it properly. Following code indicates how system will behave for exception and without exception. Various APM tools provide most frequently thrown exceptions and code which is throwing them.
public class ExceptionTest {

       private static void exceptionTest(){

             int i=0;

             int j=1;

             try{

                    int k=j/i;

             }catch(ArithmeticException ex){

             }

       }

       private static void withoutExceptionTest(){

             int i=0;

             int j=1;

             if(i>0){

                    int k=j/i;

             }

       }

       private static void exceptionTestLoop(int iterations,boolean isHandleException){

             long startTime=System.nanoTime();

             for(int i=0;i<iterations;i++){

                    if(isHandleException){

                           exceptionTest();

                    }else{

                           withoutExceptionTest();

                    }

             }

             long endTime=System.nanoTime();

             long time=endTime-startTime;

             System.out.println(“time for execution  exception “+time+” iterations “+iterations+” isHandleException “+isHandleException);

       }

       public static void main(String[] args) {

             exceptionTestLoop(100000,true);

             exceptionTestLoop(100000,false);

       }

}

results

Steps  on the DB side.

Although this post concentrate mainly on application code and browser specific side but following are easier techniques on persistence layer.

  1. Add indexes to columns: – this technique improves performance of Select Queries but reduces DML hence must be used with caution.
  2. Use run time parameters to SQL queries instead of using hard coded static parameters
  3. Cache master data instead of fetching it from db
  4. Archive database on predefined interval
%d bloggers like this: