My Experiments with Date Diff in JavaScript

Calculating the difference between two dates in JavaScript is relatively easy. First of all JavaScript provides a facility to create a Date object with various overloaded constructors. This provides a uniform way for the comparison. It also provides an ability to use the less than or greater than operator on the JavaScript Date object to check whether a particular date is before or after the other date.

Having said that, the Date does not provide any direct way to find out exact difference between the two dates in terms of days, hours, minutes and so on. However using some of the existing functions of the Date class, the date difference in the required format can be derived. Here is the complete html code along with the required JavaScript to demonstrate the same.

<html>
<head>
<title> Date Diff in JavaScript </title>
<style>
    body {
        font-family: arial;
        font-size: 18px;
	font-weight: bold;
        margin: 30px 0 0 30px;
    }

    span {
        color: #444;
	font-weight: normal;
    }
    .diff {
        margin-top: 20px;
    }
</style>
<script language="JavaScript">
    function init() {
        var currentDate = new Date();
        var date1Ele = document.getElementById("date1");
        date1Ele.innerHTML = currentDate;

        var newDate = new Date(2012, 4, 21, 0, 0, 0, 0);
        var date2Ele = document.getElementById("date2");
        date2Ele.innerHTML = newDate;

        var dateDiffEle = document.getElementById("dateDiff");
        dateDiffEle.innerHTML = getDatesDifference(currentDate, newDate);
    }

    function getDatesDifference(dateFrom, dateTo) {
        var fromMillis = dateFrom.getTime();
        var toMillis = dateTo.getTime();
        var deltaMillis = 0;
        if(fromMillis < toMillis) {
            deltaMillis = toMillis - fromMillis;
        }
        else {
            deltaMillis = fromMillis - toMillis;
        }
        return getFormattedDelta(deltaMillis);
    }

    function getFormattedDelta(deltaMillis) {
        var millis = Math.floor(deltaMillis % 1000);
        var seconds = Math.floor((deltaMillis / 1000) % 60);
        var minutes = Math.floor(deltaMillis /(1000 * 60)) % 60;
        var hours = Math.floor(deltaMillis /(1000 * 60 * 60)) % 24;
        var days = Math.floor(deltaMillis /(1000 * 60 * 60 * 24));
        return days + " Day(s) " + hours + " Hour(s) " + minutes + " Minute(s) " + 
               seconds + " Second(s) and " + millis + " Millisecond(s).";
    }
</script>
</head>

<body onLoad="init();">
    <h1>Date Diff in JavaScript</h1>
    <div>Date 1 : <span id="date1"></span></div>
    <div>Date 2 : <span id="date2"></span></div>
    <div class="diff">Date Diff : <span id="dateDiff"></span></div>
</body>
</html>

In the above code we have taken advantage of the function date.getTime() which returns the number of milliseconds since 1970/01/01. This forms a common baseline to compare 2 dates. Here is quick summary of the code.

  • Style and Body block is added just as a need to render the results to demonstrate the date difference in the required format.
  • There are three functions in the Script block which is of our interest in this example.
    • init() : This function is called on load to populate/render the values of dates and their diff.
    • getDatesDifference(dateFrom, dateTo) : This function accepts 2 date objects as an input parameter. Retrieves the milliseconds of both the dates to get the difference. This difference of milliseconds is passed to the next function for formatting.
    • getFormattedDelta(deltaMillis) : This function accepts delta milliseconds as an input and formats it in the required string. Days, Hours, Minutes, Seconds and Milliseconds are calculated from the delta milliseconds using simple arithmetic.

You may want to paste the above code as an html file and see the results in the browser. Try updating the inputs of variable newDate to see the variations. Here is a screen shot of browser after loading HTML with the above code.

Date Diff in JavaScript

Output of above code as seen on the browser

This is just an example, and one can think of returning the diff string in some other reusable format from the function getFormattedDelta(). Perhaps it could be delimited string or XML or JSON.

Complete reference of JavaScript Date object can be found here.

Android : Application Preferences – using SharedPreferences

There are several valid use cases like saving user preferences, saving application settings, saving high scores of games and so on where data persistence is the need of an application. Android provides several ways of persisting the application data. SharedPreferences comes very handy and this is one of the preferred way used for persisting simple application data.

What is SharedPreferences

SharedPreferences can be simply viewed as Java Map which stores the data in key/value pairs. However there are few differences and limitations comparing this with Maps. The good thing about SharedPreferences is that the data is persisted across the user sessions. That means the data is available to the application even after restarting the application or the phone.

Android SDK provides APIs to store and retrieve the data using android.content.SharedPreferences. While storing or retrieving data, the key is always going to be of type String and the value could be of following types:

  • boolean
  • float
  • int
  • long
  • String
  • Set

Show me the Code

Here is the code to get the handle to SharedPreferences.

import android.content.SharedPreferences;
...
	private SharedPreferences prefs;
	public void onCreate(Bundle savedInstanceState) {
		...
		SharedPreferences prefs = getSharedPreferences(MODE_PRIVATE);
		...
	}

The method getSharedPreferences(..) of application context class returns the reference to SharedPreferences which is anonymous and so the scope is limited to this activity. This is not shared across the activities. Any activity can have only one such private(and anonymous) reference of SharedPreferences.

To make the SharedPreferences available across the activities one has to provide a name to it. Here is the code for the same.

import android.content.SharedPreferences;
...
	public static final String HIGH_SCORES = "HighScores";
	private SharedPreferences prefs;
	public void onCreate(Bundle savedInstanceState) {
		...
		SharedPreferences prefs = getSharedPreferences(HIGH_SCORES, MODE_PRIVATE);
		...
	}

Above code snippet shows another way to retrieve/initialize the SharedPreferences. Note the same method is used here but the reference is initialized using the name HIGH_SCORES. This is application level preferences and available across all the activities. Any activity in the application can retrieve the same preferences using the known string/name. In this case it is HIGH_SCORES. There is no limit on creating this kind of named preferences. So application developer can segregate the data as per the name in different preferences.

Storing the Preferences

Here is how one can store the data in the preferences. android.content.SharedPreferences.Editor interface provides separate APIs to store different types of values. For example to store boolean value, the API is putBoolean(String key, boolean value). similarly there are different methods to store different data types as mentioned in the first section. Following different setters can be used.

  • putBoolean(String key, boolean value)
  • putFloat(String key, float value)
  • putInt(String key, int value)
  • putLong(String key, long value)
  • putString(String key, String value)
  • putStringSet(String key, Set values)

Here is a quick example of getting the Editor and storing the values.

import android.content.SharedPreferences;
...
	public static final String HIGH_SCORES = "HighScores";
	private SharedPreferences prefs;
	SharedPreferences prefs = getSharedPreferences(HIGH_SCORES, MODE_PRIVATE);
	SharedPreferences.Editor editor = prefs.edit();
	editor.putString("PlayerName", "Anonymous");
	editor.putInt("HighScore", 0);
	editor.commit();

In the above code, we are adding a string “Anonymous” against the name “PlayerName” and an integer value 0 against the name “HighScore”. Do not forget to call editor.commit() or editor.apply() after setting the values. Without any of these function calls the new values will not be persisted to given preferences.

Note: All the above put methods returns the a reference to the same Editor object, so you can chain put calls together. Something like editor.putString("PlayerName", "Anonymous").putInt("HighScore", 0);

Retrieving the Preferences

SharedPreferences interface provides separate APIs to retrieve different types of values. For example to retrieve boolean value, the API is getBoolean(String key, boolean defValue). Here the key is the string key used while storing this boolean value and defValue is the default value to return if this preference does not exists. Following different getters are available.

  • getBoolean(String key, boolean defValue)
  • getFloat(String key, float defValue)
  • getInt(String key, int defValue)
  • getLong(String key, long defValue)
  • getString(String key, String defValue)
  • getStringSet(String key, Set defValues)

Using above methods previously saved preferences can be retrieved.

import android.content.SharedPreferences;
...
	public static final String HIGH_SCORES = "HighScores";
	private SharedPreferences prefs;
	SharedPreferences prefs = getSharedPreferences(HIGH_SCORES, MODE_PRIVATE);
	String player = prefs.getString("PlayerName", "Anonymous");
	int score = prefs.getInt("HighScore", 0);

Above code demonstrates the retrieval of the values already saved in the previous section. If there is no value saved (or preference does not exists) for a given string key, the getXXX() functions returns the default values supplied as a second parameter to get function.

Note: All these getter methods throws ClassCastException if the preference is retrieved using the wrong getter. For example the above code should throw ClassCastException if tried to use something like prefs.getFloat("PlayerName", "Anonymous") or prefs.getBoolean("HighScore", 0). In such cases it won’t return the default value. So it is important to retrieve the value with the proper getter which is a couterpart of its setter.

I have made use of the SharedPreferences to store user’s high scores for the game Light Me Up I have published on Google Play.

Android : Move to SD Card

Move to SD card is the feature which is introduced in Android 2.2. This feature allows system/user to optionally decide whether the application will be stored on phone’s internal memory or on SD card. This is configurable and allows user to decide anytime to move the application to SD card later after installation.

Move to SD Card

Let’s first see how it looks like.

On the phone with Android 2.2 and above, go to Settings -> Applications -> Manage Applications.

This lists all the downloaded/installed applications. Clicking on any of the application the screen come up with the details of application something like the image here.

There are several button controls along with Move to SD card. This button allows user to explicitly move the application to SD card. This button will not enable by default and needs some configuration in the AndroidManifest.xml file. Depending on the configuration, the behavior of this button will change on this screen.

Here are the details about enabling this button for your application.

 

 

Add android:installLocation attribute to manifest tag as follows.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.ajitmahajani.lightmeup"
      android:versionCode="1"
      android:versionName="1.0.0"
      android:installLocation="auto">
    <uses-sdk android:minSdkVersion="4" />

    ...

</manifest>

Checkout the line #5 here. If this attribute is not present, the default behavior is to allow installation to internal storage only. This will not give option to user to move it to SD card.

Few things to note here. The android:minSdkVersion in the above example is 4 and this feature is introduced in Android 2.2. So will it work? The answer is yes. However the button Move to SD card will be grayed out on the phones having Android below 2.2. One more important thing to note is that the build target needs to be updated to at least API Level 8 (since the feature is introduced in Android 2.2). Build target of the project can be updated from the Eclipse [Go to project properties by right clicking on it. Click on Android in the left page].

Note : To use this feature in the application DOES NOT require any permission tag to be added the AndroidManifest.xml file.

The attribute android:installLocation can have following possible values.

  1. "internalOnly" : The application must be installed on the internal device storage only. If this is set, the application will never be installed on the external storage. If the internal storage is full, then the system will not install the application. This is also the default behavior if you do not define android:installLocation.
  2. "auto" : The application may be installed on the external storage, but the system will install the application on the internal storage by default. If the internal storage is full, then the system will install it on the external storage. Once installed, the user can move the application to either internal or external storage through the system settings.
  3. "preferExternal" : The application prefers to be installed on the external storage (SD card). There is no guarantee that the system will honor this request. The application might be installed on internal storage if the external media is unavailable or full, or if the application uses the forward-locking mechanism (not supported on external storage). Once installed, the user can move the application to either internal or external storage through the system settings.

There are some type of applications which should NOT be installed on the external storage. Find the further details here.

Android : Lock Screen Orientation

This is another trivial tip. Some application screen demands to lock the orientation in either Portrait or Landscape mode.
There are two ways to do this in the android. Depending on specific requirements the approach can be decided.

From the configuration

This is obvious approach where the setting can be done in the AndroidManifest.xml of the project. Below is the configuration.

<application android:icon="@drawable/icon" android:label="@string/app_name">
	<activity android:name=".MainActivity"
		  android:label="@string/app_name"
		  android:screenOrientation="portrait"
	    <intent-filter>
		<action android:name="android.intent.action.MAIN" />
		<category android:name="android.intent.category.LAUNCHER" />
	    </intent-filter>
	</activity>
	<activity android:name=".Activity1"
		  android:label="@string/app_name"
		  android:screenOrientation="portrait"
	</activity>
	<activity android:name=".Activity2"
		  android:label="@string/app_name"
		  android:screenOrientation="portrait"
	</activity>
</application>

This is standard setting of the activity in AndroidManifest.xml. Note the lines #4, #12 and #16 in the above code snippet. By adding attribute for the activity tag, the screen contents will be always displayed in the portrait mode. This line needs to be added to all those activities which needs to be displayed in portrait mode. Change the above string value to landscape to lock the orientation in landscape mode for a given activity.

Programmatic Approach

This is another way to achieve the same from the code. Add following code in the activity’s onCreate(Bundle savedInstanceState) method.

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}

Line #3 in the above code snippet sets the screen orientation to landscape for a given activity. Using programmatic approach allows developer to optionally lock the screen orientation by checking some condition if needed.

Function setRequestedOrientation(int requestedOrientation) takes int parameter which is ActivityInfo.screenOrientation. List of possible values for this parameter can be seen here.

Android : Full Screen Activity

In some applications it may be required to show the activity on full screen. One of the advantages is to utilize the full real estate on the screen. The activity will be fill the whole screen without showing the activity title and the phone notification area.

There are two ways to do this in the android. Depending on specific requirements the approach can be decided.

From the configuration

This is obvious approach where the setting can be done in the AndroidManifest.xml of the project. Below is the configuration.

<application android:icon="@drawable/icon" android:label="@string/app_name">
	....
	<activity android:name=".Activity1"
		  android:label="@string/app_name"
		  android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
	</activity>
	<activity android:name=".Activity2"
		  android:label="@string/app_name"
		  android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
	</activity>
	....
</application>

This is standard setting of the activity in AndroidManifest.xml. Note the lines #5 and #9 in the above code snippet. By adding this theme the activity will be displayed full screen. This line needs to be added to all those activities which needs to be displayed as full screen.

Programmatic Approach

This is another way to achieve the same from the code. Add following code in the activity’s onCreate(Bundle savedInstanceState) method.

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // remove title
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.main);
}

Note requestWindowFeature(Window.FEATURE_NO_TITLE) is called before setting the flags for windows. Also these calls should be done before setting the content view i.e. setContentView(R.layout.main) here. Using programmatic approach allows developer to optionally set the full screen mode by checking some condition if needed.

Several other Window features can be controlled using this technique. List of window features can be seen here.

My Experiments with Random number in JavaScript

Recently somebody asked me about how to generate a random number in JavaScript. While explaining him the basics of it, refreshed my experiments with the random number generation in JavaScript, which triggered this blog post.

In recent times most of the web applications make use of JavaScript for client side logic. Due to availability of several powerful third-party JavaScript libraries, developer’s life has become easy, writing the JavaScript code. However for small use of JavaScript it may not be possible/advisable to load these 3rd party libraries in the application. In such cases basic functions provided by JavaScript might be handy.

For example generating random numbers using the basic JavaScript is pretty trivial. With the simple tweak one can have several variations to generate the random. Sharing some of my experiments done with generating random numbers using JavaScript.

Basic Function

Let’s look at the basic form of the random function in JavaScript.

Math.random()

Above function generates the random numbers between 0 and 1. So if you try printing the results of this function on the browser, the generated numbers might look like this.

0.6001346987898531
0.37660487408682053

Expanding the range

What if I want to generate the random numbers bigger than 1? The trick is to use multiplier. Since basic function generates random fractions between 0 and 1, the multiplier number increases the upper limit of the range to the multiplier.

Math.random() * 11

Using multiplier 11, one can generate random numbers between 0 and 10.

9.378415845093869
3.6694326353729254

You may see the results something like this. They are still with the fractions and not the whole numbers.

Truncating the fractions

Function Math.floor() is there for rescue to remove the fractions from the generated numbers. It returns the whole part of the number by truncating the factional part of it.

Math.floor(Math.random() * 11)

One can even write a quick utility function as below.

<script type="text/javascript">
function generateRandomInteger(maxRange) {
	return Math.floor(Math.random() * maxRange);
}
</script>

The results returned by the above function will be whole numbers. However there is a catch. It does not guarantee the unique random number in succession. So if there is a need to generate a unique random numbers in a loop this might not work. It is possible that the number generated repeats when called in succession.

And the reason is simple. The number generated by Math.Random() function is in fraction. And small fractional difference between 2 numbers is also considered as non-repeated random number. However due to use of multiplier and the truncation, the whole part of the number is the same and due to use of Math.floor() function one gets the same number multiple times.

For example numbers 9.378415845093869 and 9.478415245093169 are unique random numbers, but after using Math.floor() function both becomes 9.

Generate Unique Random

To resolve this duplicate random number issue, I have used a while loop to check the duplication and regenerate the number before return. Here is the modified generateRandomInteger() function.

<script type="text/javascript">
var lastNum = 0;
function generateRandomInteger(maxRange) {
	while(true) {
		var randomNumber = Math.floor(Math.random() * maxRange);
		if(lastNum != randomNumber) {
			lastNum = randomNumber;
			break;
		}
	}
	return lastNum;
}
</script>

In the above example the while loop which iterate to find out the unique random number as compare to the last generated number. As you see there are drawbacks of this approach and couple of them listed below.

  1. There is a need of tracking the last generated number to compare with the newly generated random number. In the above example the variable is lastNum. Assume this function is called from different locations, the last number generated for one caller may not match with the other caller. Since lastNum need to be global variable, the same will be used for multiple callers. And there are chances of getting the non-unique number in succession in case of multiple callers. Also this functions assume the script is loaded once and the variable lastNum does not reset to 0 for every call of function.
  2. The biggest drawback could be the while loop. The condition of the loop is always true and virtually it is an infinite loop. For small values of maxRange it might iterate several times by degrading the overall performance of the application. Especially when some operation is dependent on the return of this function. When calling this function by passing 1 as maxRange will take the while loop into infinite iterations.

To overcome the first drawback mentioned, the crude way could be that the caller also passes the last generated value to the function.

For the later case, the small values can be handled by adding the break after certain predefined iteration. However this does not guarantee the unique random numbers. The other workaround would be to specify some minimum limit for this input parameter passed. For example it should be greater than 8.

What if there is a need to generate the random number between the range. Either we can use the above function to achieve this by controlling the input parameter. Or write a new function which takes the min and max of the range to generate the number. Next section details the experiment of the same.

Generate Unique Random between Range

Logically the current function generateRandomInteger() above also returns the random number between the range. Just that the min or lower integer is implicit and always zero. That derives a new function which takes 2 parameters for min and max integer of the range. The obvious implementation of the function may look like this.

<script type="text/javascript">
var lastNum = 0;
function generateRandomIntegerForRange(minRange, maxRange) {
	while(true) {
		var randomNumber = Math.floor(Math.random() * maxRange);
		if((lastNum != randomNumber) && (randomNumber > minRange)) {
			lastNum = randomNumber;
			break;
		}
	}
	return lastNum;
}
</script>

The logic in the modified function primarily generates the random number between 0 and the maxRange. However there is extra check to confirm whether the unique random is greater than the minRange before returning the unique number.

The function logic can be further simplified while keeping the same check in the IF loop as earlier function generateRandomInteger(). Where the random will be generated between 0 and (maxRange - minRange) and then add minRange to it. So the function will look like this.

<script type="text/javascript">
var lastNum = 0;
function generateRandomIntegerForRange(minRange, maxRange) {
	while(true) {
		var randomNumber = Math.floor(Math.random() * (maxRange - minRange)) + minRange;
		if(lastNum != randomNumber) {
			lastNum = randomNumber;
			break;
		}
	}
	return lastNum;
}
</script>

Both the above approached have the same drawbacks of the earlier functions. In this case the difference between maxRange and minRange should not be too small.

Note that in the example code I have not added the validation such as whether the parameter passed to function is indeed a number, maxRange is greater than minRange and so on. Similarly the drawbacks listed above can be very well handled with few more lines of code.

These were some of my experiments with the JavaScript random number generation. Feel free to extend it with your comments.

Unable to find a javac on Eclipse

After upgrading the java version on my windows laptop I started getting the following error in eclipse while compiling the java project using Ant

Unable to find a javac
com.sun.tools.javac.Main is not on the classpath.
Perhaps JAVA_HOME does not point to the JDK

Java Upgrade was an issue?

My eclipse version is Helios. Old version of Java on my system was jdk1.6_13 and Eclipse was working fine with it. I am using Ant to build the java project within Eclipse.

For the project needs, I had to migrate the system’s java version to jdk1.6_27. I completely uninstalled the old java and reinstalled the new version of java on the system. Having done this I restarted the Eclipse IDE. After running the Ant build from IDE I started getting the above said error.

I updated the JAVA_HOME environment variable on the system to point to the latest. Tried adding required java jars in the CLASSPATH environment variable. Also verified from the commandline that indeed it is picking up the latest installed java.

BTW it is clearly mentioned on the wiki that Eclipse DOES NOT consult the JAVA_HOME environment variable.

So I tried to explicitly update the JRE configuration in Eclipse by adding it from Window->Preferences->Java->Installed JREs but with no success in removing the error.

Finally got it working

At last somebody suggested to explicitly add the tools.jar in the Ant configuration and that resolved the issue.

To do that, go to Window->Preferences->Ant->Runtime in Eclipse IDE. Under Classpath tab there is ‘Global Entries’ where add the entry of tools.jar from the currently installed JDK using ‘Add External JARs’ button.

And that’s it. It solved the issue. Ant build just runs fine as earlier. As a curiosity I checked on one of my old setup of Eclipse on the other machine to see the ‘Global Entries’ in the Ant configuration. And the entry of tools.jar from the currently installed java was already there. So it seems after reinstalling the java, this entry goes away which then needs to be set explicitly.

Architectural considerations for High traffic web portals

Almost everyone today is aware of internet based companies such as Yahoo!, MSN and Google. These are sites concurrently handling several million visitors from across the globe every hour. Have you ever wondered about what goes into designing such high volume websites? This blog discusses the factors that need to be kept in mind while designing such portals.

There are several aspects to architecting high traffic web portals, which are expected to serve high concurrency with high availability and without degrading the performance. Apart from the architecture, other SDLC phases such as design, development and deployment also need special considerations. Since architecting the system is the very first step towards building the portal, this post will highlight some of the important architectural considerations.

To withstand the heavy traffic, the system should primarily be scalable, be highly available and should be able to intelligently delegate/distribute the traffic to improve the overall performance. Each of these aspects is discussed in turn below.

Scalability

Scalability is about concurrency and expandability. In the current context, it is related more to servers which are serving the application. Higher the capacity of the server, more the traffic it can serve. There are two types of scaling with their own pros and cons and it is a judgmental decision to choose which one (or even both, in combination) to go for depending on the expected traffic.

Vertical Scaling vs. Horizontal Scaling

Vertical Scaling:

Also known as scaling up. This means adding more hardware resources in terms of number of processors, memory etc. to the existing server to cope up with increasing traffic. The ease of implementation of this method also comes with some disadvantages, such as:

  • Continuous upgrading of server is expensive.
  • There is always a limit for a given server to upgrade to.
  • If the server crashes, the application is not available.

Horizontal Scaling:

Also known as scaling out. In this approach, instead of adding hardware resources to the existing server, extra server machines (maybe with comparatively lower capacity) are added to the pool. All the servers serve the same application. This is a cheaper approach since individual servers need not have very high-end configuration. Additionally, even if one server crashes, the others in the cluster will still continue to serve the application. The only drawback is that it requires more administrative efforts in terms of configuring and monitoring the cluster.

High Availability

Backup Server

In this configuration, two servers are deployed for the same application. The primary server serves the application and the second server acts as a backup for the primary. If the primary server goes down for some reason, the backup server takes care of the user requests. There are two configurations possible with this:

Active-Standby: where the standby server is passive while the primary server is active. In case the primary server goes down, the current user sessions are not maintained when the backup server takes over.

Active-Active: In this case, the user sessions are maintained and are continued to be served by the backup server when the primary goes down.

Clustering

For very high traffic, the clustered approach (Horizontal Scaling), which ensures high availability of the application, is effective. With the clustered environment, the user gets a seamless experience. This kind of environment can be configured to maintain the user’s web sessions in case any of the servers go down. Most of today’s application servers provide clustering as an inbuilt feature. Using proper load balancing mechanisms in place, one can have different servers of different capacity in the same cluster.

Performance

Performance refers to how efficiently a site responds to browser requests according to predefined benchmarks. The application performance can be designed, tuned, and measured. As said earlier, it can also be affected by many complex factors, including application design and construction, database connectivity, network capacity and bandwidth, back office services (such as mail, proxy, and security services), and hardware server resources. In the scope of this post, below are some of the considerations for performance while architecting the system.

Load Balancers

In a clustered environment, it may be possible that all the servers are not of the same capacity in terms of CPU, RAM, etc. Software load balancers are available which can enforce a policy on the site while distributing the load across the servers. The simplest policy could be of a “round robin” type where requests are passed sequentially to all servers, thus utilizing cycles of each server in the cluster. Some of these tools also allow configuring the rules for individual servers on the basis of its CPU capacity, RAM or current load on the server. For example, servers having low capacity would serve comparatively lesser number of requests to maintain the performance benchmarks.

Delegating the Traffic

While loading any web page, a browser sends several HTTP requests to the server to download associated content such as images, CSS and JavaScript files, video files etc., which are required to be rendered on the page. It is possible to distribute the implicit requests for this content across different servers to allow the main application server to serve the dynamic contents of the main page. Several techniques can be adopted to achieve this, as discussed next.

Proxy Web Server

This is a commonly used technique where the web server acts as a proxy to the application server. All the static content (such as images, CSS, JavaScript and video files) used by the site is deployed and served by the web server. Only relevant requests are forwarded to the application server, which reduces the direct load on the application server. These web servers can also form a cluster in front of the application server cluster.

Use of CDN

A content delivery network or content distribution network (CDN) is a system of computers placed at various geographical locations in a network so as to maximize bandwidth for access to the data from clients throughout the network. All the servers in the network deploy and serve the same content. A client accesses a copy of the data nearest to it, as opposed to all clients accessing the same central server, so as to avoid a bottleneck near that server. These systems implement routing algorithms such that the nearest server serves the request for the fastest delivery.

Various vendors in the market provide this service with a high quality, low-cost and low network load. A CDN can offer 100% availability, even with large power, network or hardware outages.

Third Party Storage Services

This approach refers to using third-party services to store the data on their servers. These services help in reducing the initial investments in infrastructure. The storage space can be bought on demand. Generally, these services are used to store contents uploaded by users.
There are services such as Amazon S3 which provide online storage through a simple web services interface at a very nominal cost to store and retrieve the contents.
Although this approach is generally useful in reducing the hardware cost, it can also help in performance improvements in this context. Since the contents are stored on third-party servers and are also available as URI, the overall load on the main server is reduced to some extent.

Conclusion

In summary, some of the important architectural considerations for designing high traffic web sites and portals have been discussed in this blog. There are also several other factors at different phases of the design which need to be considered to achieve good concurrency and performance.

Meta tag for IE compatibility

Coming out a new web browser in the market had always been a nightmare for web developer. I have seen people spending lot of time just to make the web pages compatible with different types of web browsers. Perticularly when it’s different versions of IE, you can expect lots of CSS overrides and specific JavaScript to get the compatibility.

At least for IE compatibility, Microsoft suggested a way by providing a META TAG. By including the suggested meta tag in the head section of web pages, one can simulate the rendering of the web page on the older version of IE browser for which it is already compatible.

To make your existing application (working on IE7 and probably breaking on IE8) include the following tag to simulate IE7 on recently launched IE8.

For more information visit:
http://msdn.microsoft.com/en-us/library/cc817574.aspx

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: