Saturday, February 15, 2014

AppFabric Caching

I have been given a task to research and find out any replacement for ASP.NET Cache. And, whether the cache can be used in any other application type besides web. I have done some research and comparison in AppFabric Caching, Enterprise Library Caching Application Block and System.Runtime.Caching. Today topic cover about AppFabric Caching, next post will cover about System.Runtime.Caching.

Scenario

Normally we are puzzled with which caching technology should we use and what are the differences between AppFabric cache compare to the other cache technology.

The caching feature that AppFabric provided is distributed cache, which mean it makes the cache available and accessible in one or many servers but they are unified into one entity for your application. When you are using ASP.NET cache or any caching facility, you notice that the cache is only available to your own application domain.

Image credit &source from : MSDN

Features

Comparing AppFabric cache vs ASP.NET cache, here are the differences and special features.

  1. The cache can be distributed hosting in one or multiple server.
  2. The cache can be hosted in a different standalone server, separate from Application server.
  3. The cache cluster promote high availability. If one of the cache server is down for some reason, the cache will still be available.
  4. The cache automatically sync data between cache hosts.

Configuration

After you have installed and start configuring the AppFabric, you would come across the following window in the wizard.


There are 2 Caching Service configuration provider, one is SQL Server and another is XML. If you wonder which provider to pick, it is depending on your environment. For my server, it is not joined with Active Directory (AD). Therefore, XML is my only option. If you forcefully pick SQL Server, you would get the following notification:


The provider difference is just the location of keeping cache cluster configuration. All the information that you enter in the "Next" page will be stored in SQL Server or a XML file.

Since I am using XML configuration provider, I have to create a new workgroup account to run the Caching Service. You are not allowed to use built-in account such as NT AUTHORITY\NETWORK SERVICE. The same workgroup account needs to be created in the other cache server, and applying same configuration.




Now, you need to pick one of your cache server to be a lead host, then create a network shared folder in that server. The network shared folder must be accessible by other hosts and giving the Cache Service account read/write privilege.



Once you are done with it, configure the File Share in AppFabric Configuration Wizard. Then, set the cluster size. If you are configuring the lead host, choose the New Cluster. For other cache host, choose the Join Cluster.


Next, the default TCP ports which will be used by AppFabric Cache Service are shown in the spinner box. Note them down and create firewall rule to unblock those ports. If you find any of these ports conflicting or is being used by any of you applicantion, you can change the port here.


That's it for AppFabric Cache configuration.

Usage

The cache usage is similar to ASP.NET cache. Open up Visual Studio, create any new project, then add the following assemblies.

C:\Program Files\AppFabric 1.1 for Windows Server\Microsoft.ApplicationServer.Caching.Core.dll
C:\Program Files\AppFabric 1.1 for Windows Server\Microsoft.ApplicationServer.Caching.Client.dll

Note: You need to manually browse and locate the above assemblies. If you add the references from the Assemblies Extension page, they are actually coming from Windows Azure SDK.


The following is the error that you will encounter if you added wrong assemblies:

ErrorCode<ERRCA0019>:SubStatus<ES0001>:Check the client version. It should be within the allowed version range on the server. If necessary, upgrade the client to the allowed version.

The following code need to be run once only to initialize the cache for your application:
Code credit to Scott Hanselman.

private static DataCacheFactory _factory = null;
private static DataCache _cache = null;

public static DataCache GetCache()
{
    if (_cache != null)
        return _cache;

    //List cache host server
    //Note: 22233 is the cache port
    List<DataCacheServerEndpoint> servers = new List<DataCacheServerEndpoint>();
    servers.Add(new DataCacheServerEndpoint("MY-SYLVESTER-01", 22233));
    servers.Add(new DataCacheServerEndpoint("MY-SYLVESTER-02", 22233));
    servers.Add(new DataCacheServerEndpoint("MY-SYLVESTER-03", 22233));
    servers.Add(new DataCacheServerEndpoint("MY-SYLVESTER-04", 22233));
    servers.Add(new DataCacheServerEndpoint("MY-SYLVESTER-05", 22233));

    //Set the cache hosts
    DataCacheFactoryConfiguration configuration = new DataCacheFactoryConfiguration();
    configuration.Servers = servers;
    configuration.LocalCacheProperties = new DataCacheLocalCacheProperties();

    //Set this if you want to get notified if any changes to your cache
    configuration.NotificationProperties = new DataCacheNotificationProperties(10000, new System.TimeSpan(0, 0, 3));
    //Default value for queue length: 10000
    //Default value for poll interval: 300 seconds

    //Disable tracing to avoid informational/verbose messages on the web page
    DataCacheClientLogManager.ChangeLogLevel(System.Diagnostics.TraceLevel.Off);

    //Pass configuration settings to cacheFactory constructor
    _factory = new DataCacheFactory(configuration);

    //Get reference to named cache called "default"
    _cache = _factory.GetCache("default");

    return _cache;

}

In order to insert data into the cache, just the following one liner:

public void SetData(string key, object data)
{
    _cache.Put(key, data);

}

In order to get the data from the cache, one liner as follow:

public object GetData(string key)
{
    return _cache.Get(key);

}

There are more complicated DataCache methods supported, check it out from MSDN.

Cache Notification

If you need the AppFabric Cache Service to notify you any changes to the cache, there are a few callback event can be subscribed. Before you can use this feature, you need to enable it during the cache initialization by setting the DataCacheNotificationProperties in DataCacheFactoryConfiguration.

Also, you need to enable notification by using this PowerShell command: 
Set-CacheConfig -CacheName <Cache Name> -NotificationsEnabled true

You also can change the AppFabric Cache configuration XML file in the shared folder.

Then, restart the cache cluster by restarting the AppFabric Caching Service windows service or executing the PowerShell command: Restart-CacheCluster

All the AppFabric Caching PowerShell command can be found HERE.


Now, I want to get notified when someone replace one of the cache item. The following is the code use to subscribe the callback method:

private static DataCache _cache;
       
static AppFabricCacheService ()
{
    _cache = CacheUtil.GetCache();

    _cache.AddItemLevelCallback(
        "myItem",
        DataCacheOperations.ReplaceItem,
        OnDataCacheItemChanged);
}

private static void OnDataCacheItemChanged(string cacheName, string regionName, string key, DataCacheItemVersion version, DataCacheOperations cacheOperation, DataCacheNotificationDescriptor nd)
{
    Debug.WriteLine("Someone changed my cache item!");
    Debug.WriteLine("Cache Name: " + cacheName);
    Debug.WriteLine("Cache Item Key: " + key);
}

If you want to get notified for other action to the cache, you can use different DataCacheOperations filter. More Info

You can use the bitwise OR to add more filter to your callback event subscription. For example, the following code will raise the OnDataCacheItemChanged callback method if someone add or replace or remove your cache item.

_cache.AddItemLevelCallback(
    "myItem",
    DataCacheOperations.AddItem |
    DataCacheOperations.ReplaceItem |
    DataCacheOperations.RemoveItem,
    OnDataCacheItemChanged);

AppFabric cache notification not just support cache item level notification, it also support for:

  • Cache level in bulk
  • Cache level
  • Item level
  • Region level


Note: These callback events are not supported in Windows Azure Shared Caching.

There are a few more things about AppFabric Caching, but it is too much to cover in one topic. The common and important thing that we need to know about caching such as security, concurrency, expiration and eviction, all can be found in this MSDN article.

Summary

The AppFabric caching is awesome, however, IMHO, if you are needing a simple cache that replace ASP.NET cache, AppFabric caching is overkill. Unless, you really need a caching service that support high availability, scalability, this is what you want.

AppFabric caching is meant to be hosted in different server from your application server. Therefore, hardware and software licensing needs to be considered. Otherwise, you can still choose to ignore the recommendation from Microsoft by hosting the AppFabric cache in the same server with your application server. Then, the server hardware resource could become the concern.

I notice that the AppFabric cache memory consumption is rather high compare to other normal caching facility. By default, the AppFabric caching will utilize 50% of your server memory. And, it is going to reserve quite some amount of memory even though you never have that much of data keeping in the cache or not. However, don't worry, the memory reserve can be tuned down by setting the high / low watermark percentage of memory in the cluster host configuration. See Windows Server AppFabric Memory Consumption Behavior for more info.

If you are looking for smaller caching facility and a replacement for ASP.NET cache for non web application, please come back and check out the next coming blog post.


Monday, January 20, 2014

C# Extension Methods Performance

Today I read a blog regarding extension methods from Serena Yeoh. In her blog, she shows that how extension methods can be very helpful in making the code look more meaningful and cleaner. If you are interested to checkout how she uses extension methods to beautify the data access component in layered architecture, feel free to visit her blog.

I know a lot of people including myself are concerned about the performance of using extension methods. Therefore, I have done some comparison and testing to find out whether is it bad to use extension methods?

Now, I am comparing the layered architecture sample code that uses extension methods which is given by Serena versus the same sample that uses normal way (object methods) which you can find it from HERE. The following are the code snippets from both sample code:

Extension Method Way

public Leave Apply(Leave leave)
{
    leave.Status = LeaveStatuses.Pending;
    leave.DateSubmitted = DateTime.Now;
    leave.IsCompleted = false;

    LeaveStatusLog log = CreateLog(leave);

    Validations.ValidateLeaveDates(leave);

    // Check for overlapping leaves.
    if (leave.IsOverlap())
    {
        throw new ApplicationException("Date range is overlapping with another leave.");
    }

    using (TransactionScope ts =
        new TransactionScope(TransactionScopeOption.Required))
    {
        // Step 1 - Calling Create.
        leave.Create();

        // Step 2 - Calling Create on log.
        log.LeaveID = leave.LeaveID;
        log.Create();

        ts.Complete();
    }

    return leave;

}

Object Method Way

public Leave Apply(Leave leave)
{
    leave.Status = LeaveStatuses.Pending;
    leave.DateSubmitted = DateTime.Now;
    leave.IsCompleted = false;

    LeaveStatusLog log = CreateLog(leave);

    // Data access component declarations.
    var leaveDAC = new LeaveDAC();
    var leaveStatusLogDAC = new LeaveStatusLogDAC();

    Validations.ValidateLeaveDates(leave);

    // Check for overlapping leaves.
    if (leaveDAC.IsOverlap(leave))
    {
        throw new ApplicationException("Date range is overlapping with another leave.");
    }

    using (TransactionScope ts =
        new TransactionScope(TransactionScopeOption.Required))
    {
        // Step 1 - Calling Create on LeaveDAC.
        leaveDAC.Create(leave);

        // Step 2 - Calling Create on LeaveStatusLogDAC.
        log.LeaveID = leave.LeaveID;
        leaveStatusLogDAC.Create(log);

        ts.Complete();
    }

    return leave;
}

Note the yellow highlighted differences. First is the extension method way, second is the normal object or instance method way.

Compare #1: MSIL - Microsoft Intermediate Language

First, let's find out how the above sample codes get translated into MSIL. Open up the intermediate language disassembler first by opening the Visual Studio Command Tool, then execute the ildasm.exe.

Next, use the IL disassembler to open up the compiled dll.



A bunch of IL codes will appear. Keep the window open. Then, repeat the same steps above to open another IL disassembler and open another compiled dll that contain the source code that use normal object method way.

Extension Method Way

  // Code size       136 (0x88)
  .maxstack  2
  .locals init ([0] class [LeaveSample.Entities]LeaveSample.Entities.LeaveStatusLog log,
           [1] class [System.Transactions]System.Transactions.TransactionScope ts,
           [2] class [LeaveSample.Entities]LeaveSample.Entities.Leave CS$1$0000,
           [3] bool CS$4$0001)

The following IL codes are from within try catch block only.

  .try
  {
    IL_004b:  nop
    IL_004c:  ldarg.1
    IL_004d:  call       void [LeaveSample.Data]LeaveSample.Data.LeaveDAC::Create(class [LeaveSample.Entities]LeaveSample.Entities.Leave)
    IL_0052:  nop
    IL_0053:  ldloc.0
    IL_0054:  ldarg.1
    IL_0055:  callvirt   instance int64 [LeaveSample.Entities]LeaveSample.Entities.Leave::get_LeaveID()
    IL_005a:  callvirt   instance void [LeaveSample.Entities]LeaveSample.Entities.LeaveStatusLog::set_LeaveID(int64)
    IL_005f:  nop
    IL_0060:  ldloc.0
    IL_0061:  call       class [LeaveSample.Entities]LeaveSample.Entities.LeaveStatusLog [LeaveSample.Data]LeaveSample.Data.LeaveStatusLogDAC::Create(class [LeaveSample.Entities]LeaveSample.Entities.LeaveStatusLog)
    IL_0066:  pop
    IL_0067:  ldloc.1
    IL_0068:  callvirt   instance void [System.Transactions]System.Transactions.TransactionScope::Complete()
    IL_006d:  nop
    IL_006e:  nop
    IL_006f:  leave.s    IL_0081

  }  // end .try

Object Method Way

  // Code size       157 (0x9d)
  .maxstack  2
  .locals init ([0] class [LeaveSample.Entities]LeaveSample.Entities.LeaveStatusLog log,
           [1] class [LeaveSample.Data]LeaveSample.Data.LeaveDAC leaveDAC,
           [2] class [LeaveSample.Data]LeaveSample.Data.LeaveStatusLogDAC leaveStatusLogDAC,
           [3] class [System.Transactions]System.Transactions.TransactionScope ts,
           [4] class [LeaveSample.Entities]LeaveSample.Entities.Leave CS$1$0000,
           [5] bool CS$4$0001)

The following IL codes are from within try catch block only.

  .try
  {
    IL_005a:  nop
    IL_005b:  ldloc.1
    IL_005c:  ldarg.1
    IL_005d:  callvirt   instance class [LeaveSample.Entities]LeaveSample.Entities.Leave [LeaveSample.Data]LeaveSample.Data.LeaveDAC::Create(class [LeaveSample.Entities]LeaveSample.Entities.Leave)
    IL_0062:  pop
    IL_0063:  ldloc.0
    IL_0064:  ldarg.1
    IL_0065:  callvirt   instance int64 [LeaveSample.Entities]LeaveSample.Entities.Leave::get_LeaveID()
    IL_006a:  callvirt   instance void [LeaveSample.Entities]LeaveSample.Entities.LeaveStatusLog::set_LeaveID(int64)
    IL_006f:  nop
    IL_0070:  ldloc.2
    IL_0071:  ldloc.0
    IL_0072:  callvirt   instance class [LeaveSample.Entities]LeaveSample.Entities.LeaveStatusLog [LeaveSample.Data]LeaveSample.Data.LeaveStatusLogDAC::Create(class [LeaveSample.Entities]LeaveSample.Entities.LeaveStatusLog)
    IL_0077:  pop
    IL_0078:  ldloc.3
    IL_0079:  callvirt   instance void [System.Transactions]System.Transactions.TransactionScope::Complete()
    IL_007e:  nop
    IL_007f:  nop
    IL_0080:  leave.s    IL_0094

  }  // end .try

Appendix for IL instruction:

nop = do nothing, for breakpoint purpose
ldloc = load local variable
ldarg = load argument
callvirt = call a late-bound object method
call = call a method
pop = pop a value from stack

The Differences

The method that use extension methods has smaller code size. The local variable count also lesser during initialization because missing LeaveDAC and LeaveStatusLogDAC objects.

Notice the call and callvirt IL instruction? Extension method is translated into call instruction, while the object method is translated into callvirt instruction. Understood that the extension methods are declared as static method, no doubt it is early binding, but the newly instantiated object method is considered as late-binding, serious? @.@

Anyway, the IL codes are later needed to be compiled with JIT compiler. By looking at the IL codes, it may not sufficient to tell which perform better.

Compare #2: Profiling

Let's see the response time comparison for both extension method and object method by using instrumentation profiling with Visual Studio 2013 Premium or Ultimate edition. You can use any other profiler tool to perform the similar testing. Please refer to this post to see how to use the Visual Studio Profiler.

Test Scenario: Submit 10 leave application.

Here is the result of using extension method:
Avg Elapsed Exclusive Time : 0.06 ms




Here is the result of using object method:
Avg Elapsed Exclusive Time : 0.07 ms


The Difference:

Woot! @.@
Extension method win by 0.01ms difference. Unbelievable!

Compare #3: Stress Test

Let's see what happen if the Apply leave method is called 10,000 times. I wrote a very simple unit test to stress the service that would call the extension method or object method for 10,000 times.

[TestMethod]
public void StressTest()
{
    //Prepare the test data first
    List<Leave> leaves = new List<Leave>();
    for (int i = 1; i <= 10000; i++)
    {
        leaves.Add(new Leave()
        {
            StartDate = DateTime.Today,
            EndDate = DateTime.Today,
            Duration = 1,
            Category = LeaveCategories.Annual,
            Employee = "Unit Test " + i.ToString(),
            Description = "Unit Test",
        });
    }
           
    LeaveController upc = new LeaveController();
    Stopwatch watch = new Stopwatch();

    //Start the timing
    watch.Start();

    //Start stressing the WCF service
    foreach(Leave leave in leaves)
    {
        upc.Apply(leave);
    }

    //Stop the timing
    watch.Stop();

    Debug.WriteLine("Total milisecond: " + watch.ElapsedMilliseconds.ToString());
}

I ran the unit test for 3 times in order to be fair.

The extension method result after completed the test:
Round 1: 221695 ms
Round 2: 218811 ms
Round 3: 228312 ms
Average: 222939 ms

The object method result after completed the test:
Round 1: 226168 ms
Round 2: 218680 ms
Round 3: 214087 ms
Average: 219645 ms

The Differences:

The object method win! When multiple instances versus singleton, logically multiple instances should win. When there are a lot of tasks need to be completed, a group of people work on it is always quicker to finish compare to one person works on it.

Summary

The extension method performance has not much different compare to object method. If the extension methods really can make your code look cleaner and meaningful, IMHO, just go for it. For more information about implementing layered architecture with extension methods, please visit Serena blog.

If you find my test above is not accurate to tell which is perform better, feel free to share your thought in the comment section below.


Send Transactional SMS with API

This post cover how to send transactional SMS using the Alibaba Cloud Short Message Service API. Transactional SMS usually come with One Tim...