Showing posts with label services. Show all posts
Showing posts with label services. Show all posts

Wednesday, November 25, 2015

Hardware Sizing for Java/Java EE Products

For doing a hardware sizing on Java/Java EE; especially where indexing or search frameworks like Solr/Lucene are involved - many more attributes add to the final sizing tabulation. [This entry does not include anything on Database Sizing]



Before we get ahead with a sizing exercise, we need to understand that the following will impact the accuracy of the metrics.

1. Decision on Exact Version of Runtime, Used Frameworks, Servers,
2. Experience of the Senior Engineer/Architect doing the Sizing Exercise
3. Understanding the Functional Characteristics of the System being Built
4. Agreeing upon the Non-Functional Characteristics of System being Built
5. Appreciating Sizing Environments [Development, Testing, Production, UAT,...]
6. The Future Extensions or Possible Lifeline of the System Being Built


The following are the most important standard guidelines and criteria for hardware or server sizing. Please note that these guidelines are for the server that hosts the Application. It does not contain any Database Sizing guidelines.  
  •  Hardware Component should operate at no more than 80% Utilization 
  •  Processor and Memory Resources should be allocated for Maximum User Load 
  •  User Think times and Network Latency should be taken into Account 
  •  Number of Potential Users and Number of Concurrent Users 
  •  Service Time and Average Response Time of your Application

If you are using Solr/Lucene type of indexing or disk-based frameworks; then it is important that you estimate the entire possible index size by deducing the number of documents, number of indexed fields and number of stored fields and also the average size of each document. By considering some buffer, you may be able to compute, almost accurately, the Disk Space. While computing the Estimated Memory Requirements for Solr/Lucene; additionally; the number of Unique Terms per Field also need to be considered. In the references below, I have provided a sheet (that has been made publicly available by 'Lucidworks'). It will also provide you all the attributes that you 'tune' to your Memory Sizing and Disk Space Requirements for Solr/Lucene, especially with respect to 'Caching of Query Terms'.

While doing sizing exercise, you can provide various tabulated forms as the result for each of the possible environments.  Alternatively, you may choose to present a single tabulated result (mentioning the environment for which you are providing this sizing). You may mention, the additional constraints that may be applicable across environments. It is important the buffer may be added to each of the computed attributes; keeping in mind the cost and future extensibility. Most of them come to a conclusion that "Hardware is Inexpensive these Days - We can Recommend something that is Beyond the Best Possible Maximum Load". Though this may work almost always, we may not be able to come out with a "Possible Minimum Estimate with Least Cost". Coming out with the the estimates; keeping latter in mind, will equip us to better understand the future issues that various functional and non-functional aspects may cause. This is especially if we want to achieve maximum efficiency under the constraints for all possible 'Loads'. For example, if we were to achieve this ('latter') in the 'Development, Testing or User Acceptance Testing' environments; we may be able ot point out that Memory Leak that would have manifested itself due to an Incorrect Development Practice or Deployment Strategy. Sometimes, we may also end giving a "Inflated Estimate" for an otherwise "Size-S System"; the resources which may always lie unused - if we go with the former approach.

Before I take you to the tabulation there are a few terms, that need definition (from the text book). They are very often assumed and the slight difference in their actual meanings may be better to know as it is.

User Think Time:  The time the user is not engaged in actual use of the processor (The time between Requests). This is used interchangeably with User Wait Time. In absolute real-life however, this has a slightly different impact as it involves the 'Time Required by an User for thinking and performing his next action in the application either due to the response or otherwise'.
Response Time: The response time measured at the client under load. (Average of Time). 
Concurrent Users:  The number of users measured on the server, taken in snapshots from the Server Status or Server Console.
Service Time:  The elapsed time to complete the operation measured for a single user.
Maximum User Load: The maximum number of concurrent users that may be expected or the system is tested for.
User Wait Times: The time elapsed between actions or clicks for a given user. This is used interchangeably with User Think Time. In absolute real-life however, this has a slightly different impact as it involves the 'Time Required by an User for analyzing or reading data received between request and also performing other tasks such as reading email, using the telephone, and chatting with a colleague or on other Applications simultaneously Running'. If we were to go deeper into Software Testing and Performance - Both of these may be put to great use to improve user experience and/or performance.
CPU Utilization: Average of the Total CPU Utilization as a Percentage.


The final tabulated Hardware Sizing Recommendation for the Java/Java EE Product will look like the following: (One Table is shown here for 'Development' environment and consideration for 'Production/UAT' environments provided below).

The Load Balancing, Data Clustering, Failover Strategy and Backup Strategy are not planned for, due to the nature of the System.

FIELD NAME
FIELD TYPE
Type of Environment
Development [/Testing]
Type of Machines
Physical [/Virtual]
Number of Servers
1x
Operating System
Red Hat Enterprise Linux - Linux X.Y.ZZ-AAA.BB.C.eRR.xpp_bb OS
Application Server
Weblogic ??c (Weblogic ??.?.?*)
Load Balancing
[NONE]
Data Clustering
[NONE]
Failover Strategy
[NONE]
Database Connections
10 [maxActive], 02 [maxIdle]
Backup Strategy
[NONE]
Processors
4 Cores
Concurrency
~500 Concurrent Users 
[Including Think Times]
Memory / RAM
4GB
Garbage Collection
Generational Garbage Collector [-XX:UseG1GC]
Disk Capacity
[Reasons]
    
   Lucene Indexing
~10GB SSD [/HDD]  
[Logs, Indexes, Dependencies, +Buffer]  

~300MB [Worst Case, +Buffer]
Java Heap Size

   Lucene
   Second Level Caching
Dedicated Machine [-Xms=??g -Xmx=??.?g]
 
~100MB [Worst Case, +Buffer]
 
~000MB [NONE]
 
This recommendation is for the Development Environment. It is best that the above is used / emulated for any of Development or Testing. For Production or User Acceptance Testing environments, the considerations (with our recommendations in brackets) related to Storage Capacity [500GB SSD], Storage Redundancy [RAID], Processor Cores [08+], Total Memory (RAM) [08GB+], Application Failover Strategy [Active-Active with 4x Physical Servers] should best match with Other Organizational or Hardware Tier Standards.


I am giving you the Following Links, which can be used as Reference to Get the Best Results:


Happy Hardware Sizing for Java/Java EE Products!


[Note: I am a Software Development Architect, working for a US based Software Product Company and this write-up is based on the work done as part of Special Product Customization for a Big Logistics Customer, as well as for later use in the Product Itself]. 
 
 

Sunday, February 15, 2015

REST Using Apache Wink

Representational State Transfer (REST)
Hypermedia as the Engine of Application State (HATEOAS)
  
 
I built this Product Web Service using Apache Wink. It can perform add, update, delete and retrieval of products in memory. I intend to explain the basics of REST using Apache Wink using this. REST stands for Representational State Transfer. REST is based on the concepts of Roy Fielding’s dissertation work as part of his thesis. It works on the HTTP protocol and has the following differences when compared to SOAP:
  • Works on HTTP protocol, as compared to SOAP which creates their own protocol
  • Uses HTTP GET, PUT, POST, DELETE as compared to SOAP which uses only POST
  • It uses the HTTP infrastructure, whereas SOAP is transport neutral     
  • The producer and consumer are aware of the content being exchanged     
  • It does not support many Non Functional Requirements or any WS-* Standards

INSTALLATIONS REQUIRED
Eclipse 4.2.0
Apache Wink 1.4.0
Apache Tomcat 8.0.9
JDK 1.7.0 / JRE 1.7.0
 

SERVER / WEB SERVICE
The steps to build the web service using Apache Wink are given below:

1.     Create a Dynamic Web Project in Eclipse

2.     Build the Core Application that performs CRUD 
 /**   
  *    
  */   
  package me.sumithpuri.rest.persistence;   
     
     
  import java.util.ArrayList;   
  import java.util.List;   
     
  import me.sumithpuri.rest.vo.Product;   
     
  /**   
  * @author sumith_puri   
  *   
  */   
  public class ProductPersistenceManager {   
     
    private List<Product> productDatabase = new ArrayList<Product>();   
    private static ProductPersistenceManager persistenceManager;   
    private static int id=0;   
       
    private ProductPersistenceManager() {   
          
    }   
       
    public void add(Product product) {   
          
       System.out.println("database: added one product");   
          
       // atomic id creation   
       id++;   
       product.setId(id);   
       productDatabase.add(product);   
    }   
       
    public List<Product> get() {   
       System.out.println("database: retrieved all products");   
       return productDatabase;   
    }   
       
    public void update(long productId, String productName) {   
       System.out.println("database: modified one product");   
          
       for(int i=0;i<productDatabase.size();i++) {   
            
         Product product = productDatabase.get(i);   
         if(product.getId()==productId) {   
            product.setName(productName);   
            productDatabase.remove(i);   
            productDatabase.add(i,product);   
         }   
       }   
       return;   
    }   
       
    public void delete(long productId) {   
       System.out.println("database: deleted one product");   
          
       for(int i=0;i<productDatabase.size();i++) {   
            
         Product product = productDatabase.get(i);   
         if(product.getId()==productId) productDatabase.remove(i);   
       }   
       return;   
    }   
       
    public static ProductPersistenceManager getInstance() {   
          
       if(persistenceManager==null) {   
         synchronized(ProductPersistenceManager.class) {   
            if(persistenceManager==null) {   
              persistenceManager = new ProductPersistenceManager();   
            }   
         }   
       }   
       return persistenceManager;   
    }   
  }   

3. Add the Supporting JAR files in the Build Path

4. Create the REST Web Service using Apache Wink (GET, POST, DELETE, PUT)
 package me.sumithpuri.rest.webservice;  
   
   
 import java.util.List;  
   
 import javax.ws.rs.DELETE;  
 import javax.ws.rs.GET;  
 import javax.ws.rs.POST;  
 import javax.ws.rs.PUT;  
 import javax.ws.rs.Path;  
 import javax.ws.rs.PathParam;  
 import javax.ws.rs.Produces;  
 import javax.ws.rs.core.MediaType;  
   
 import me.sumithpuri.rest.persistence.ProductPersistenceManager;  
 import me.sumithpuri.rest.vo.Product;  
   
 /**  
  * @author sumith_puri  
  *  
  */  
 @Path("product")  
 public class ProductWebService {  
   
     ProductPersistenceManager persistenceManager = ProductPersistenceManager.getInstance();  
       
     @GET  
     @Produces(MediaType.TEXT_PLAIN)  
     public String getProducts() {  
           
         List<Product> products = persistenceManager.get();  
         String productList = new String();  
           
         for(Product producti: products) {  
             productList+=producti.toString() + "\n";  
         }  
           
         // return as plain text - other types include xml, json  
         return productList;  
     }  
       
     @POST  
     public String addProducts(String productStr) {  
           
         Product product = new Product();  
         product.setName(productStr);  
         persistenceManager.add(product);  
           
         return productStr;  
     }  
       
     @DELETE  
     @Path("/{id}")  
     public void deleteProduct(@PathParam(value="id") long id) {  
           
         persistenceManager.delete(id);  
         return;  
     }  
       
     @PUT  
     @Path("/{id}")  
     public void modifyProduct(@PathParam(value="id") long id, String productName) {  
           
         persistenceManager.update(id, productName);  
         return;  
     }  
 }  
   

5.  Configure Application for Apache Wink
To allow Apache Wink to locate this service as a REST web service, you can either define an additional class or configure an application file. We are using an application to mention all our web service.

You can place this under WEB-INF/ and name the file as simply ‘application’ (without any extension).
 me.sumithpuri.rest.webservice.ProductWebService  

Next, you need to specify the servlet related configuration for allowing Apache Wink REST Servlet to locate this appliatiocn configuration, by specifying the location of ‘application’ as the parameter ‘applicationConfigLocation’ in WEB-INF/web.xml
 <?xml version="1.0" encoding="UTF-8"?>  
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">  
  <display-name>products</display-name>  
  <servlet>  
   <servlet-name>restService</servlet-name>  
   <servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>  
   <init-param>  
    <param-name>applicationConfigLocation</param-name>  
    <param-value>/WEB-INF/application</param-value>  
   </init-param>  
  </servlet>  
  <servlet-mapping>  
   <servlet-name>restService</servlet-name>  
   <url-pattern>/rest/*</url-pattern>  
  </servlet-mapping>  
 </web-app>  

6. Deploy as Apache Tomcat Web App, Directly

CLIENT / WEB SERVICE CLIENT
The steps to test the web service or write a REST client are as follows:

1. Create a Java Project in Eclipse
2. Include the Support Client JAR files in the Classpath

3. Build the client to test or access GET method
4. Build the client to test or access POST method
5. Build the client to test or access DELETE method
6. Build the client to test or access PUT method
 package me.sumithpuri.rest.client;  
   
 import javax.ws.rs.core.MediaType;  
   
 import org.apache.wink.client.ClientConfig;  
 import org.apache.wink.client.Resource;  
 import org.apache.wink.client.RestClient;  
   
   
 /**  
  * @author sumith_puri  
  *  
  */  
 class ProductRESTClient {  
   
     static String REST_WEB_SERVICE="http://localhost:8080/products/rest/product";  
     static ClientConfig clientConfig = new ClientConfig();  
   
     /**  
      * @param args  
      */  
     public static void main(String[] args) throws Exception {  
                   
         try {  
               
             ProductRESTClient restClient = new ProductRESTClient();              
             System.out.println("Apache Wink Based REST Client");  
             System.out.println("Sumith Kumar Puri (c) 2015");  
             System.out.println("=============================");  
               
             restClient.configureClient();  
             System.out.println();  
               
             restClient.invokeGET();  
             System.out.println();  
                       
             String product="Sumith Puri" + (int) (Math.random()*9999);  
             restClient.invokePOST(product);  
               
             System.out.println();  
             product="Sumith Puri" + (int) (Math.random()*9999);  
             restClient.invokePOST(product);  
               
             System.out.println();  
             product="Sumith Puri" + (int) (Math.random()*9999);  
             restClient.invokePOST(product);  
               
             System.out.println();  
             product="Sumith Puri" + (int) (Math.random()*9999);  
             restClient.invokePOST(product);  
               
             System.out.println();  
             restClient.invokeGET();  
               
             System.out.println();  
             restClient.invokeDELETE(2L);  
               
             System.out.println();  
             restClient.invokeGET();  
               
             System.out.println();  
             product="Sumith Puri" + (int) (Math.random()*9999);  
             restClient.invokePOST(product);  
               
             System.out.println();  
             product="Sumith Puri" + (int) (Math.random()*9999);  
             restClient.invokePOST(product);  
   
             System.out.println();  
             restClient.invokeDELETE(4L);  
   
             System.out.println();  
             restClient.invokeGET();  
               
             System.out.println();  
             restClient.invokePUT(3L,"Sumith Puri");  
               
             System.out.println();  
             restClient.invokeGET();  
         } catch (Exception e) {  
               
             e.printStackTrace();  
         }  
     }  
       
   
     public void configureClient() {  
   
     }  
       
     public void invokeGET() {  
           
         System.out.println("Testing GET command....");      
         RestClient restClient = new RestClient(clientConfig);  
         Resource resource = restClient.resource(REST_WEB_SERVICE);  
         String response = resource.accept("text/plain").get(String.class);  
         System.out.printf(response);  
         System.out.println("...GET command is successful");  
     }  
       
     public void invokePOST(String product) {  
           
         System.out.println("Testing POST command...");  
         RestClient restClient = new RestClient(clientConfig);  
         Resource resource = restClient.resource(REST_WEB_SERVICE);  
         resource.contentType(MediaType.TEXT_PLAIN).accept(MediaType.TEXT_PLAIN).post(String.class,product);  
         System.out.println("...POST command is successful");  
     }  
   
       
     public void invokePUT(Long id, String productName) {  
           
         System.out.println("Testing PUT command...");  
         RestClient restClient = new RestClient(clientConfig);  
         Resource resource = restClient.resource(REST_WEB_SERVICE+"/"+id);  
         resource.contentType(MediaType.TEXT_PLAIN).accept(MediaType.TEXT_PLAIN).put(String.class, productName);  
         System.out.println("...PUT command is successful");  
     }  
       
     public void invokeDELETE(Long id) {  
           
         System.out.println("Testing DELETE command...");  
         RestClient restClient = new RestClient(clientConfig);  
         Resource resource = restClient.resource(REST_WEB_SERVICE+"/"+id);  
         resource.contentType(MediaType.TEXT_PLAIN).accept(MediaType.TEXT_PLAIN).delete();  
         System.out.println("...DELETE command is successful");  
     }  
 }  
   



OUTPUT (FIRST ACCESS)
Apache Wink Based REST Client
Sumith Kumar Puri (c) 2015
=============================

Testing GET command....
...GET command is successful

Testing POST command...
...POST command is successful

Testing POST command...
...POST command is successful

Testing GET command....
ID:1, NAME: Sumith Puri3169
ID:2, NAME: Sumith Puri6052
...GET command is successful

Testing DELETE command...
...DELETE command is successful

Testing GET command....
ID:1, NAME: Sumith Puri3169
...GET command is successful

Testing POST command...
...POST command is successful

Testing POST command...
...POST command is successful

Testing DELETE command...
...DELETE command is successful

Testing GET command....
ID:1, NAME: Sumith Puri3169
ID:3, NAME: Sumith Puri732
...GET command is successful

Testing PUT command...
...PUT command is successful

Testing GET command....
ID:1, NAME: Sumith Puri3169
ID:3, NAME: Sumith Puri
...GET command is successful


DOWNLOADS
You may download the products.war (including source) web service as well as the products-client.jar (including source).


CONCLUSION
In this blog, you have seen how to build REST web services using Apache Wink for basic data types. Next, I will blog on how to include Jackson or Jettison as the stream reader or stream writer JSON libraries, so that we can read and write complex or application object types. It will be titled ‘REST Using Apache Wink and Jackson/Jettison’.


[GitHub Repository for Code Samples]
https://github.com/sumithpuri/skp-code-marathon-hochiminh