Wednesday, 9 May 2012

Multi-Tenancy

What is Multi-Tenancy ?
  • A single instance of the software runs on a server, serving multiple client  organizations (tenants) 
  • Designed to virtually partition its data and configuration 
  • Essential attribute of Cloud Computing 
What's a Tenant ?
  • Tenant is "my user who has her own users"
  • Multi-tenancy is not to the tenant's advantage instead its for the Multi-tenancy provider
  • Tenant would always prefer an environment which is isolated from other tenants


Levels in Multi-tenancy
Multitenancy can be introduced in either of 2 levels:
  1. Hypervisor level Isolation
  2. DB level Isolation

Hypervisor level Isolation
  • Maps the physical machine to a virtualized machine
  • Hypervisor allows to partition the hardware into finer granularity 
  • improve the efficiency by having more tenants running on the same physical machine 
  • Provides cleanest separation 
  • Less security concerns 
  • Easier cloud adoption
  • virtualization introduces a certain % of overheadvirtualization introduces a certain % of overhead 

DB level Isolation
  • Re-architect the underlying data layer  
  • Computing resources and application code shared between all the tenants on a server 
  • Introduce distributed and partitioned DB 
  • Degree of isolating is as good as the rewritten query 
  • Approaches for DB level Isolation:
  • Separated Databases
  • Shared Database, Separate Schemas
  • Shared Database, Shared Schema
  • No VM overhead 

Types of DB level Isolation:
  1. Separated Databases
  2. Shared Database, Separate Schemas
  3. Shared Database, Shared Schemas

Separated Databases


  • Each tenant has its own set of data, isolated from others
  • Metadata associates each database with the correct tenant 
  • Easy to extend the application's data model to meet tenants' individual needs 
  • Higher costs for hardware & maintaining equipment and backing up tenant data 


Shared Database, Separate Schemas


  • Multiple tenants in the same database 
  • Each tenant having its database schema
  • Moderate degree of logical data isolation
  • Tenant data is harder to restore in the event of a failure 
  • Appropriate for small number of tables per database

Shared Database, Shared Schemas


  • Same database & the same set of tables to host multiple tenants' data
  • Introduce an extra attribute "tenantId" in every table 
  • Append a "where tenantId = $thisTenantId" in every query 
  • Lowest hardware and backup costs 
  • Additional development effort in the area of security 
  • Small number of servers required


Virtualization vs Data Partitioning

 

Virtualization Data Partitioning
Type of Implementation
Simple
Complex
Nature
Multiple instances of the application and database servers on the same hardware as per the number of Tenants
Single instance of the application for all the tenants with a shared database schema
Architecture Changes
No
Yes
Extension
Each tenant can have its own extension of the code and database schema
Difficult to Maintain
Handling custom extensions for each tenant can be harder to implement.
Easy to Maintain
H/W Requirement
Very High
Very Less
Cost ( Dev. + Service)
Very High
Less
Multi-tenant
Not 100%
100%
Recommended
No
Yes




Hadoop - A Framework for Data Intensive Computing Applications





What does it do?
  • Hadoop implements Google’s MapReduce, using HDFS
  • MapReduce divides applications into many small blocks of work. 
  • HDFS creates multiple replicas of data blocks for reliability, placing them on compute nodes around the cluster. 
  • MapReduce can then process the data where it is located. 
  • Hadoop ‘s target is to run on clusters of the order of 10,000-nodes.


Hadoop: Assumptions
  • It is written with large clusters of computers in mind and is built around the following assumptions:
  • Hardware will fail.
  •  Processing will be run in batches. Thus there is an emphasis on high throughput as opposed to low latency.
  • Applications that run on HDFS have large data sets. A typical file in HDFS is gigabytes to terabytes in size. 
  • It should provide high aggregate data bandwidth and scale to hundreds of nodes in a single cluster. It should support tens of millions of files in a single instance.
  • Applications need a write-once-read-many access model. 
  • Moving Computation is Cheaper than Moving Data. 
  •  Portability is important.

Example Applications and Organizations using Hadoop
  • A9.com – Amazon: To build Amazon's product search indices; process millions of sessions daily for analytics, using both the Java and streaming APIs; clusters vary from 1 to 100 nodes. 
  • Yahoo! : More than 100,000 CPUs in ~20,000 computers running Hadoop; biggest cluster: 2000 nodes (2*4cpu boxes with 4TB disk each); used to support research for Ad Systems and Web Search 
  • AOL : Used for a variety of things ranging from statistics generation to running advanced algorithms for doing behavioral analysis and targeting; cluster size is 50 machines, Intel Xeon, dual processors, dual core, each with 16GB Ram and 800 GB hard-disk giving us a total of 37 TB HDFS capacity. 
  • Facebook: To store copies of internal log and dimension data sources and use it as a source for reporting/analytics and machine learning; 320 machine cluster with 2,560 cores and about 1.3 PB raw storage; 
  • FOX Interactive Media : 3 X 20 machine cluster (8 cores/machine, 2TB/machine storage) ; 10 machine cluster (8 cores/machine, 1TB/machine storage); Used for log analysis, data mining and machine learning 
  • University of Nebraska Lincoln: one medium-sized Hadoop cluster (200TB) to store and serve physics data;

MapReduce Paradigm
  • Programming  model developed at Google
  • Sort/merge based distributed computing
  • Initially, it was intended for their internal search/indexing application, but now used extensively by more organizations (e.g., Yahoo, Amazon.com, IBM, etc.)
  • It is functional style programming (e.g., LISP) that is naturally parallelizable across  a large cluster of workstations or PCS.
  •  The underlying system takes care of the partitioning of the input data, scheduling the program’s execution across several machines, handling machine failures, and managing required inter-machine communication. (This is the key for Hadoop’s success)


How does MapReduce work?
  • The run time partitions the input and provides it to different Map instances;
  • Map (key, value)  (key’, value’)
  • The run time collects the (key’, value’) pairs and distributes them to several Reduce functions so that each Reduce function gets the pairs with the same key’. 
  • Each Reduce produces a single (or zero) file output.
  • Map and Reduce are user written functions

Hadoop Architecture




MapReduce-Fault tolerance
  • Worker failure: The master pings every worker periodically. If no response is received from a worker in a certain amount of time, the master marks the worker as failed. Any map tasks completed by the worker are reset back to their initial idle state, and therefore become eligible for scheduling on other workers. Similarly, any map task or reduce task in progress on a failed worker is also reset to idle and becomes eligible for rescheduling.
  • Master Failure: It is easy to make the master write periodic checkpoints of the master data structures described above. If the master task dies, a new copy can be started from the last checkpointed state. However, in most cases, the user restarts the job.

Mapping workers to Processors
  • The input data (on HDFS) is stored on the local disks of the machines in the cluster. HDFS divides each file into 64 MB blocks, and stores several copies of each block (typically 3 copies) on different machines. 
  • The MapReduce master takes the location information of the input files into account and attempts to schedule a map task on a machine that contains a replica of the corresponding input data. Failing that, it attempts to schedule a map task near a replica of that task's input data. When running large MapReduce operations on a significant fraction of the workers in a cluster, most input data is read locally and consumes no network bandwidth.


Additional support functions
  • Partitioning function: The users of MapReduce specify the number of reduce tasks/output files that they desire (R). Data gets partitioned across these tasks using a partitioning function on the intermediate key. A default partitioning function is provided that uses hashing (e.g. .hash(key) mod R.). In some cases, it may be useful to partition data by some other function of the key. The user of the MapReduce library can provide a special partitioning function. 
  • Combiner function: User can specify a Combiner function that does partial merging of  the intermediate local disk data before it is sent over the network. The Combiner function is executed on each machine that performs a map task. Typically the same code is used to implement both the combiner and the reduce functions.


Hadoop Distributed File System (HDFS)
  • The Hadoop Distributed File System (HDFS) is a distributed file system designed to run on commodity hardware. It has many similarities with existing distributed file systems. However, the differences from other distributed file systems are significant. 
  • highly fault-tolerant and is designed to be deployed on low-cost hardware. 
  • provides high throughput access to application data and is suitable for applications that have large data sets. 
  • relaxes a few POSIX requirements to enable streaming access to file system data. 
  • part of the Apache Hadoop Core project. The project URL is http://hadoop.apache.org/core/. 

Hadoop Community
  • Hadoop Users
  1. Adobe
  2. Alibaba
  3. Amazon
  4. AOL
  5. Facebook
  6. Google
  7. IBM
  • Major Contributor
  1. Apache
  2. Cloudera
  3. Yahoo





Wednesday, 28 December 2011

Java XML Parsers


Today we would talk about common used XML parsers available in Java. They are:
1)      DOM
2)      STAX
3)      SAX

Sample XML file:

<?xml version="1.0"?><TDRS><TDR><Date>2011-12-6</Date><Time>18:38:1.47</Time><Timestamp>1323196681047</Timestamp><SystemID>TE06</SystemID><TransactionID>425425678</TransactionID><CorrelationID>none</CorrelationID><SCFTransID></SCFTransID><DeveloperApplication></DeveloperApplication><Company></Company><AppId></AppId><Environment></Environment><Bundle></Bundle><AuthMethod></AuthMethod><AuthToken></AuthToken><HTTPMethod>GET</HTTPMethod><APIType></APIType><SLT></SLT><API></API><APIAction>/</APIAction><SOAPAction></SOAPAction><ClientRequestTimestamp>0</ClientRequestTimestamp><APIAppTimestamp>1323196681040</APIAppTimestamp><APITargetRequestTimestamp>0</APITargetRequestTimestamp><APITargetResponseTimestamp>0</APITargetResponseTimestamp><ClientResponseTimestamp>0</ClientResponseTimestamp><Cached>0</Cached><EventType>Error</EventType><ClientEndpoint></ClientEndpoint><ClientIP>10.155.1.233</ClientIP><LocalIP></LocalIP><LocalPort>23394</LocalPort><TargetEndPoint></TargetEndPoint><TargetIP></TargetIP><StatusCode></StatusCode><ProviderCode></ProviderCode><HTTPStatusCode>403</HTTPStatusCode><Multiplier></Multiplier><Cost></Cost><QuotaAction></QuotaAction><OverQuota>0</OverQuota><OverDayQuota>0</OverDayQuota><OverWeekQuota>0</OverWeekQuota><OverMonthQuota>0</OverMonthQuota><PayloadSize>0</PayloadSize><TDRIdentifier>426561727188bae37b32990ee41</TDRIdentifier></TDR></TDRS>


1)      DOM Parser

§         It parses an entire XML document and load it into memory, modeling it with Object for easy traversal or manipulation.
§         Once the XML loaded in the memory then user can traverse in any direction i.e. forward or backward.
§         DOM Parser is slow and consume a lot of memory if it load a XML document which contains a lot of data, So should be used  for specific purpose (Traversing) only


  I.      DOM Parsing Only

private int domParsing (final String filename) throws SAXException, IOException, JaxenException {
        final int Records = 0;        final
String textfile = FileUtils.readFileToString
(new File (filename));        if ((this.dbf == null) || (this.db == null)) {            this.dbf = DocumentBuilderFactory.newInstance ();            try {                this.db = this.dbf.newDocumentBuilder ();            } catch (final ParserConfigurationException e) {            }        }
        if ((this.dbf != null) && (this.db != null)) {            this.doc = this.db.parse (new InputSource (new StringReader (textfile)));            this.doc.getDocumentElement ().normalize ();//            final Element e = this.doc.getDocumentElement ();
            final List <Node> tdrNodes = new DOMXPath ("TDRS").selectNodes (this.doc);            Long time = 0L;            for (int nodeIdx = 0; nodeIdx < tdrNodes.size (); ++nodeIdx) {                final Node tdrNode = tdrNodes.get (nodeIdx);                while (tdrNode.hasChildNodes ()) {                    final StringBuffer sb = new StringBuffer ();                    final Node childNode = tdrNode.getFirstChild ();                    tdrNode.removeChild (childNode);                    if (childNode.getNodeType () != 1) {                        continue;                    }                    final Long start = System.currentTimeMillis ();                    sb.append (childNode.getNodeName () + ":" + childNode.getNodeValue () + ";");
                    while (childNode.hasChildNodes ()) {
                        final Node grandchildNode = childNode.getFirstChild ();                        sb.append (grandchildNode.getNodeName () + ":" + grandchildNode.getTextContent () + ";");                        childNode.removeChild (grandchildNode);                    }
                    System.out.println (childNode.getNodeName () + "::" + sb.toString ());                    final Long end = System.currentTimeMillis ();                    time = time + (end - start);                    // System.out.println ("Time::" + (end - start) + " Map::" + params);                }                System.out.println ("Total Dom Time:" + time);            }        }        return Records;}


The output is:

TDR::TDR:null;Date:2011-12-6;Time:18:38:1.47;Timestamp:1323196681047;SystemID:TE06;TransactionID:425425678;CorrelationID:none;SCFTransID:;DeveloperApplication:;Company:;AppId:;Environment:;Bundle:;AuthMethod:;AuthToken:;HTTPMethod:GET;APIType:;SLT:;API:;APIAction:/;SOAPAction:;ClientRequestTimestamp:0;APIAppTimestamp:1323196681040;APITargetRequestTimestamp:0;APITargetResponseTimestamp:0;ClientResponseTimestamp:0;Cached:0;EventType:Error;ClientEndpoint:;ClientIP:10.155.1.233;LocalIP:;LocalPort:23394;TargetEndPoint:;TargetIP:;StatusCode:;ProviderCode:;HTTPStatusCode:403;Multiplier:;Cost:;QuotaAction:;OverQuota:0;OverDayQuota:0;OverWeekQuota:0;OverMonthQuota:0;PayloadSize:0;TDRIdentifier:426561727188bae37b32990ee41;



II.      DOM Validation with external XSD


private boolean validateDOM (final String xmlFile, final String xsdFile) {
        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance ();
        factory.setValidating (false);
        factory.setNamespaceAware (true);

        final SchemaFactory schemaFactory = SchemaFactory.newInstance ("http://www.w3.org/2001/XMLSchema");

        try {
            factory.setSchema (schemaFactory.newSchema (new Source[] {new StreamSource (xsdFile)}));
            final DocumentBuilder builder = factory.newDocumentBuilder ();

            builder.setErrorHandler (new ErrorHandler () {

                @Override
                public void warning (final SAXParseException arg0) throws SAXException {
                    // TODO Auto-generated method stub
                    try {
                        throw new Exception ();
                    } catch (final Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace ();
                    }
                }

                @Override
                public void fatalError (final SAXParseException arg0) throws SAXException {
                    // TODO Auto-generated method stub

                }

                @Override
                public void error (final SAXParseException arg0) throws SAXException {
                    // TODO Auto-generated method stub

                }
            });

            final Document document = builder.parse (new InputSource (xmlFile));
        } catch (final SAXException e) {
            e.printStackTrace ();
            return false;
        } catch (final ParserConfigurationException e) {
            e.printStackTrace ();
            return false;
        } catch (final IOException e) {
            e.printStackTrace ();
            return false;
        }
        return true;

    }




2)      STAX Parser – A Pull Parser

§         It’s a Pull Parser
§         Events are generated by the parsing application, thus providing parsing regulation to the client, rather than the parser
§         Developer can control the parsing i.e. you can suspend parsing, skip elements while parsing, and parse multiple documents
§         Parsing events gets generated as the XML document gets parsed


    I.      STAX Parsing Only

private void staxParsing (final String filename) {
        try {
            final FileInputStream fis = new FileInputStream (filename);
            // URL u = new URL(filename);
            // InputStream in = u.openStream();
            final XMLInputFactory factory = XMLInputFactory.newInstance ();
            final XMLStreamReader parser = factory.createXMLStreamReader (fis);

            HashMap <String, ValueTypePair> params = null;
            String NodeName = null;
            Class NodeType = null;
            for (int event = parser.next (); event != XMLStreamConstants.END_DOCUMENT; event = parser.next ()) {
                switch (event) {
                    case XMLStreamConstants.START_ELEMENT:
                        // System.out.println (parser.getLocalName ());
                        if ((parser.getLocalName () != null) && parser.getLocalName ().equalsIgnoreCase ("TDR")) {
                            params = new HashMap <String, ValueTypePair> ();
                        }
                        final int iIndex = this.alBillingXPaths.indexOf (parser.getLocalName ());
                        if (iIndex < 0) {
                            break;
                        }
                        NodeName = this.alBillingColumns.get (iIndex);
                        NodeType = this.alBillingClasses.get (iIndex);
                        break;
                    case XMLStreamConstants.END_ELEMENT:
                        if ((parser.getLocalName () != null) && parser.getLocalName ().equalsIgnoreCase ("TDR")) {
                            // System.out.println (params);
                        }
                        break;
                    case XMLStreamConstants.CHARACTERS:
                        if ((NodeName != null) && (params != null)) {
                            params.put (NodeName, new ValueTypePair (parser.getText (), NodeType));
                        }
                        break;
                    case XMLStreamConstants.CDATA:
                        if ((NodeName != null) && (params != null)) {
                            params.put (NodeName, new ValueTypePair (parser.getText (), NodeType));
                        }
                        break;
                }
            }
            parser.close ();
        } catch (final XMLStreamException ex) {
            System.out.println (ex);
        } catch (final IOException ex) {
            System.out.println ("IOException while parsing " + filename);
            ex.printStackTrace ();
        }
    }



    II.      STAX Validation

STAX Does not support Validation, which acts as its drawback.



3)      SAX Parser – A Push Parser

§         SAX Parser is a push parser
§         it’s parser which call the code & user don’t have full control over it
§         User can not stop the parsing in between
§         Its supports XSD validation



   I.      SAX Parsing Only

private static void saxParsing (final String filename) {
        try {

            final SAXParserFactory factory = SAXParserFactory.newInstance ();
            final SAXParser saxParser = factory.newSAXParser ();

            final DefaultHandler handler = new DefaultHandler () {

               
                @Override
                public void startElement (final String uri,
                                          final String localName,
                                          final String qName,
                                          final Attributes attributes) throws SAXException {

                   
                }

                @Override
                public void endElement (final String uri, final String localName, final String qName) throws SAXException {
                }

                @Override
                public void characters (final char ch[], final int start, final int length) throws SAXException {
                   
                }

            };

            saxParser.parse (filename, handler);

        } catch (final Exception e) {
            e.printStackTrace ();
        }

        System.out.println ("SAX Parsing ends");

    }



II.      SAX Validation & Parsing


private static boolean validateSAX (final String xmlFile, final String xsdFile) {
        final SAXParserFactory factory = SAXParserFactory.newInstance ();
        factory.setValidating (false);
        factory.setNamespaceAware (true);

        final SchemaFactory schemaFactory = SchemaFactory.newInstance ("http://www.w3.org/2001/XMLSchema");

        try {
            if (xsdFile != null) {
                factory.setSchema (schemaFactory.newSchema (new Source[] {new StreamSource (xsdFile)}));
            }
            final SAXParser parser = factory.newSAXParser ();

            final XMLReader reader = parser.getXMLReader ();
            reader.setErrorHandler (new ErrorHandler () {

                @Override
                public void warning (final SAXParseException arg0) throws SAXException {
                    // TODO Auto-generated method stub
                    try {
                        System.err.println ("warning::" + arg0);
                        throw new Exception ();
                    } catch (final Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace ();
                    }
                }

                @Override
                public void fatalError (final SAXParseException arg0) throws SAXException {
                    // TODO Auto-generated method stub
                    System.err.println ("fatal Error::" + arg0);

                }

                @Override
                public void error (final SAXParseException arg0) throws SAXException {
                    // TODO Auto-generated method stub
                    System.err.println ("Error::" + arg0.getMessage ());

                }
            });
            reader.parse (new InputSource (xmlFile));
        } catch (final SAXException e) {
            e.printStackTrace ();
            return false;
        } catch (final ParserConfigurationException e) {
            e.printStackTrace ();
            return false;
        } catch (final IOException e) {
            e.printStackTrace ();
            return false;
        }

        System.out.println ("SAX Parsing ends");

        return true;
    }




4)      Analysis


The xml file is first being validated using the xsd file & then forwarded for parsing, the parsing results are as

(result are generated by doing parsing through eclipse having a hepsize of 512 mb )

SNo.
# TDRS Nodes
Time: Dom Parser (ms)
Time: Stax Parser
(ms)
Time: SAX Parser
(ms)
1
10,000
6866
500
469
2
25,000
Out of Memory
1234
1118
3
50,000
Out of Memory
2422
2328
4
1,00,000
Out of Memory
4906
4672


Hence we conclude that SAX & STAX parsers are much more efficient than the DOM parsers & should be used if to & fro navigation not required in the XML