Native data structures offer a conventional method of storing and retrieving data. Through their implementation, they provide concurrency to your standalone applications – which is great, except that they are only limited to the threads inside an application process. And with scalable applications running on more than one server, the need to share the state of data structures amongst the applications arises.
This is where distributed data structures step in. While offering the functionality of conventional data structures, distributed data structures allow multiple processes and application instances to add, fetch and remove data simultaneously without compromising the consistency of data. These data structures resolve the problem that conventional data structures could not solve; these enable parallel computation.
Where does NCache fit in?
NCache, being an in-memory caching solution, enhances all the functionalities that distributed data structures provide. Using NCache as a distributed cache allows your structured data to be accessed from threads outside of the process.
You can add your data into a distributed data structure, cache it on any of the servers and marvel at how the data is now accessible to all the applications, processes, instances that are a part of your system regardless of which server stored that data.
To top it off, NCache provides high availability in the form of Partitioned replica topology. The data you keep in the cache servers is quite understandably important to you. Losing this data because of any server fault is not acceptable in any case. This is exactly why NCache allows you to keep replicas of your data in the caching server so that if one of the nodes goes down, there always remains a replicated set of the exact same data that can be used in such scenarios. This way you will never have data loss in your .NET application. On top of this all, you will have the authority to add caching server nodes at runtime according to your requirements.
NCache provides the functionality of replicating, partitioning, and scaling of data encapsulated inside the data structures. Therefore, developers using these data structures do not have to worry about the logic of distribution inside their .NET applications.
NCache Details Data Structures in NCache
Distributed Data Structures in NCache
NCache provides various data structures to achieve scalability, concurrency, and accuracy in your .NET application. Let us look at these data structures that enhance the overall performance of your application.
Distributed List
NCache provides DistributedList that is a native .NET implementation of the IList interface. NCache being a native .NET caching solution itself benefits you where your application is solely .NET based as well. What better thing for your .NET application to have than everything native and hospitable.
The following code snippets show how to create, populate and depopulate a distributed list in NCache.
One application creating and populating a list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Specify unique cache key for list string key = "ExpensiveProducts"; DataTypeAttributes dataTypeAttributes = new DataTypeAttributes(); dataTypeAttributes.Expiration = new Expiration(ExpirationType.Sliding, new TimeSpan(0, 2, 0)); // Create list of Product type IDistributedList<Product> list = cache.DataTypeManager.CreateList<Product>(key, dataTypeAttributes); // Get products to add to list Product[] products = FetchProductsFromDB(); foreach (var product in products) { // Add products to list list.Add(product); } |
Another application fetching and removing discontinued products from the list
1 2 3 4 5 6 |
// Get list of Product type IDistributedList<Product> list = IDistributedList <Customer> list = cache.DataTypeManager.GetList<Product>("ExpensiveProducts"); // Get range of discontinued products to be removed List<Product> itemsToRemove = FetchDiscontinuedProducts(); list.RemoveRange(itemsToRemove); |
Incorporating a distributed list in everyday applications is very simple. Provided below are some of the scenarios that portray applications in need of a distributed list implementation.
Use Case: Shopping cart
Let’s suppose that your .NET application is an e-commerce platform. In this application, the customers can add and remove items to and from the shopping cart. To allow these requests to be processed accordingly, you need to save each customer’s data that contains the customer’s identity and the items that are added or removed against that ID. The best and most organized way of doing this is by using a distributed list.
A distributed list, in a multi-server environment, saves your customer’s data and makes it available on all the servers. You can have this list keep track of all the items a customer bought, showed interest in or even the ones he chose to ignore. This not only improves the overall worth of your application by maintaining a sophisticated record but also makes data highly available for you.
Use Case: Leaderboard
For people who are interested in gaming, leaderboard acts as a vital source of information, be that online gaming or worldwide matches. These people are always interested in knowing which team is leading and who’s lagging behind. Information like this can be incorporated in an application that uses a list data structure to store the required data and broadcast it to all the interested users.
NCache Details Lists in NCache
Distributed Queue
NCache provides a First-in First-out implementation known as a DistributedQueue. Queues are used at runtime to store valuable information because of its FIFO behavior.
IDistributedQueue is an easy-to-understand and implement data structure provided by NCache. Look at the code below to get acquainted with basic operations in a queue, like creating a queue, adding and removing data from it.
One application creating and populating queue
1 2 3 4 5 6 7 8 9 |
string key = "CandidateQueue"; // Create Queue of Candidate type IDistributedQueue<Candidate> queue = cache.DataTypeManager.CreateQueue<Candidate>(key); foreach(var candidate in candidates) { // Add candidates to queue queue.Enqueue(candidate); } |
Another application fetching the queue from distributed cache and dequeuing first item
1 2 3 4 |
IDistributedQueue<Candidate> queue = cache.DataTypeManager.GetQueue<Candidate>("CandidateQueue"); // Remove first item of queue var firstCandidate = queue.Dequeue(); |
Mentioned below are some of the use cases of a distributed queue to give you a rough idea of where you can use a queue and what benefits are you going to get out of it.
Use Case: Message Queue
Your .NET application hosted on multiple servers entertaining multiple clients at once needs to send messages over to one of the clients that are using your application. What do you do here? In a distributed environment, you do not control the connection between your servers and the clients, meaning that you do not know which server is entertaining which client.
In such a scenario, you need a distributed queue to keep track of all the messages that need to be delivered to the clients. This list is distributed among all the cache servers to make sure that all the clients that are connected to your application have access to the same data at all times. NCache takes care of the replication of the distributed data for you. Hence, using a distributed queue in a distributed cache, you can achieve data concurrency and high availability.
Use Case: Sentiment Analysis
An application being used by an intelligence agency to filter out threatening or confidential tweets could totally benefit from a distributed queue provided by NCache. Let us assume that there are multiple nodes running your web application. What you want is to process these tweets in a distributed environment with such precision that one tweet doesn’t get processed more than once. The way to achieve this is if that application uses a distributed queue to store all the incoming tweets in it. This will make sure that no tweet gets processed twice, hence, improving the overall performance and accuracy of your application.
NCache Details Queues in NCache
Distributed HashSet
NCache provides an extremely fast and scalable implementation of sets called the DistributedHashSet. HashSet is an unordered datatype whose values are unique and distinctive.
Let’s look at the code below to understand how you can create and populate a HashSet.
First application populating a hashset
1 2 3 4 5 6 7 8 9 10 |
// Create unique keys for hashSets string mondayUsersKey = "UsersLoggedInOnMonday"; // Create hashSets of object type IDistributedHashSet<string> userSetMonday = cache.DataTypeManager.CreateHashSet<string>(mondayUsersIds); // Add user IDs for Monday userSetMonday.Add("john_smith"); userSetMonday.Add("mike_cohn"); userSetMonday.Add("mike_ross"); |
Second application fetching hashset and modifying it
1 2 3 4 5 6 |
// Getting hashset from cache IDistributedHashSet<string> userSetMonday = cache.DataTypeManager.GetHashSet<string>("UsersLoggedInOnMonday"); // Remove user with given ID from the set userSetMonday.Remove("mike_cohn"); userSetMonday.RemoveRandom(); |
You can use distributed HashSets where your application needs to perform operations on data that is unique in its nature. Here are some of the scenarios of applications whose performance is improved with the implementation of DistributedHashSet.
Use Case: IP Address Tracking
As hashsets do not contain any duplicate values, you can use NCache’s implementation of distributed HashSets to keep track of all the users and visitors of the website. For example, if you have an online book store, HashSets can help you identify, quite easily, which user is interested in which books and has bought how many books and whatnot.
Use Case: Analyzing E-Commerce Sales
You can keep all the information you need inside a HashSet. All a HashSet needs is a unique value to assign multiple values against it. For instance, you want to keep track of all the users that have bought anything off of your online store application. You want their IDs and against each ID, you want to keep a list of the items that customer has bought, items that were put to the wishlist, items that were removed from the wishlist. Now that you have all that information in a refined set, you can perform multiple operations on it with the utmost ease.
NCache Details HashSets in NCache
Distributed Dictionary
DistributedDictionary provided by NCache is a key-value pair that is a native .NET implementation of the IDictionary interface. A dictionary holds a value against a certain key and if that value needs to be changed, you need to override it.
You can use IDistributedDictionary in NCache to keep a record of products. You can create and add/remove product information to and from a dictionary in the following ways.
First application creating and populating a dictionary
1 2 3 4 5 6 7 8 9 10 11 12 |
string key = "ExpensiveProducts"; // Create dictionary of Product type IDistributedDictionary<string, Product> dictionary = cache.DataTypeManager.CreateDictionary<string, Product>(key); // Adding products to dictionary Product[] products = FetchProducts(); foreach(var product in products) { string productKey = $"Product:{product.ProductID}"; dictionary.Add(productKey, product); } |
Second application fetching and modifying dictionary
1 2 3 4 5 6 7 8 9 10 11 |
// Fetch dictionary of Product type from cache IDistributedDictionary<string, Product> dictionary = cache.DataTypeManager.GetDictionary<string, Product>("ExpensiveProducts"); // Create list of keys to remove List<string> keysToRemove = FetchDiscontinuedProducts(); // Get values from dictionary against the given keys ICollection<Product> values = dictionary.Get(keysToRemove); // Remove items from dictionary with given keys int itemsRemoved = dictionary.Remove(keysToRemove); |
A distributed dictionary can be used in multiple cases, proving to be extremely handy and efficient in each of them. Examples of such cases are provided below.
Use Case: Storing Encrypted Values in the Cache
One of the many advantages of using a dictionary in a distributed environment is when you need to store cryptographic keys. These keys need to be available to all servers that are a part of that distributed system. You store cyphered data in one of the cache servers as a Dictionary value along with its decryption key. Doing such a thing allows all the servers who might need that data in the future to have shared access to not only the data but also its decryption key.
Use Case: Storing Login Credentials
A distributed dictionary is the most efficient way to store and access a user’s login ID and password. Suppose there’s an application running on multiple servers that requires its users to provide security credentials for them to have access to sensitive data. To make sure that all servers catering to your application have access to this important information, you can cache these values as Dictionary key-value pairs. This makes sure that if one server adds a new key-value pair to the dictionary, any other server can easily search through the dictionary for the required data.
NCache Details Dictionary in NCache
Distributed Counter
NCache provides ICounter data structure that is used to increment and decrement the value with ease. To make your life a whole lot better, NCache lets you lock the data placed inside a counter to keep data consistent.
For your .NET application, the following code helps you understand how to create an ICounter instance, populate it with data and how to increment/decrement that value.
First application creating the counter with an initial value
1 2 3 4 5 6 7 8 |
string key = "SubscriptionCounter"; long initialValue = 15; // Create counter ICounter counter = cache.DataTypeManager.CreateCounter(key, initialValue); // Set the initial value of counter to 100 counter.SetValue(100); |
Second application fetching and modifying the counter
1 2 3 4 5 6 7 8 |
// Create counter ICounter counter = cache.DataTypeManager.GetCounter("SubscriptionCounter"); // Increment value of counter counter.Increment(); // Decrement value of counter counter.Decrement(); |
You can use counters in countless scenarios, you just need to look around and almost every problem you find can be solved by using distributed counters in a caching environment. Some of these scenarios are as follows.
Use Case: Page-View Count
To see how many views a webpage gets per hour or per day, depending on what you want, could easily be implemented using distributed counters in NCache. On every new view, the counter in the cache server will be incremented accordingly. This value along with all the values present in all the caching servers will be updated in the database after a certain amount of time. By doing this, you avoid many unnecessary trips to the database, hence, improving the overall performance of your .NET application.
Use Case: Tweets Analysis
Let’s say you have an application that keeps count of all the important tweets of politicians and celebrities. It also keeps track of the number of likes and dislikes, comments and stuff that their tweets receive. Now let’s say that a person A tweets and the likes on his tweet go from 0 to a million in less than half an hour. This is the kind of data that isn’t transient but you still need to persist it. But the speed on which you need to persist is far slower than the speed on which the data is being updated.
To record a change that is this abrupt and frequent, you definitely need a secondary component that does not let your database choke on the frequency of data. And this is where you need NCache. Being an in-memory cache comes in handy when you need to store information temporarily and then write it all in the database after an interval. Here, if you start caching the count of likes on A’s tweets instead of directly modifying the value in the database, you will be avoiding a whole lot of unnecessary network calls.
NCache Details Counters in NCache
Summarizing it all
When you have a single-tier architecture, you don’t need distributed data structures at all. You can keep and implement whichever data structure you need inside your application. But, when you move to multiple servers and start dealing with transient data that doesn’t need to be persisted, or data whose modification is extremely costly, your database chokes and performance is compromised. To avoid such a tragedy befalling your application, you need distributed data structures. And when you talk about distributed, you should always have NCache at the back of your mind.
NCache is extremely scalable and the fact that it is an in-memory solution makes it the best possible solution for all your data caching problems.