If yours is a high-traffic, data-focused application that requires scalability, you would be remiss not to use Scala. Scala offers users the advantages of both object-oriented and functional programming, all in one, that grows with the demands of its users.
Unfortunately, whereas Scala application tiers are linearly scalable, the corresponding databases are not. Consequentially, heavy transactional loads might cause a database bottleneck, which may overload your system. You can avoid this by incorporating a data caching tier (specifically, in-memory distributed caching) with Scala applications for faster data access. NCache is one such caching solution. NCache is an open-source, in-memory distributed cache that supports Scala-based applications. It lets users add new servers to your cluster to satisfy rising performance needs, which helps achieve high transactional speeds and data consistency.
Why Use Distributed Caching with Scala?
NCache, along with its vast features and enhanced caching capabilities, gives flexible options for you to use with Scala. NCache will enhance your Scala applications in the following ways:
- Improved Performance: Data is stored in an in-memory cache, yielding maximum performance and faster response times.
- Reliability: If an application server goes down or somehow data is lost, NCache provides reliability with the help of data replication.
- Scalability: NCache provides linear scalability by allowing you to add more cache servers when the transaction load grows. For example, while using your Scala application, you can instantly add a new cache server depending on the situation and continue to serve more requests without stopping your application.
- High-Availability & Fault Tolerance: When used in the context of a web farm, NCache provides better fault tolerance by keeping the data available across all server nodes in a clustered cache with no single point of failure.
- Cluster Topologies: NCache offers different caching topologies to make your Scala applications more reliable and scalable. For example, Replicated Topology provides load balancing to let your application handle intensive traffic, whereas the Partitioned-Replica Topology provides higher reliability and scalability for faster transactions.
Configuring Scala Client with NCache
First and foremost, you must install the NCache edition you require, as directed in its installation guide. After which, you can create a clustered cache using the NCache Manager as per your topology preference and start your cluster before we come to the part of the process that incorporates Scala. Before we begin, you must ensure you have JDK 11 installed, the environment variable set for Java, and a version of Scala (i.e., 3.0+). Now presuming you’ve chosen the NCache Enterprise Edition, you must edit your pom.xml file, specifically the <dependency> section, as follows:
1 |
import com.alachisoft.ncache.scala.client.*; |
This configuration adds all the necessary jars to your application. Following this, you must add the following import statement to your application before you connect to your cache.
1 2 3 4 5 |
<dependency> <groupId>com.alachisoft.ncache</groupId> <artifactId>ncache-scala-client</artifactId> <version>5.3.1</version> </dependency> |
Using NCache API in Scala
Post-connection, the majority of NCache’s client-side API is available to use for Scala. You can get sample codes for these features on NCache’s GitHub repository or learn more about them in its Programmers Guide. Here are a few of them to help you get started:
Basic Operations for Caching Data
However, before you can truly take advantage of even the most basic data caching features you need to create a cache handle. NCache provides users with the Cache interface to get an instance of NCache’s cache and create a connection as desired. Moreover, the CacheManager class lets you connect to the cache instance via the getCache method. Once you’ve created such a cache handle as demonstrated below you can proceed.
1 2 3 4 5 6 7 8 9 10 11 12 |
try { var cacheName = "demoCache"; // Connect to cache val cache = CacheManager.getCache(cacheName) } catch { case exception: Exception => // Handle any errors } |
NCache stores data as key-value pairs. So, unique identifiers (keys) are saved with data (values). Therefore, NCache, like most key-value databases, stores, retrieves, and manages data using CRUD operations. It offers a variety of CRUD APIs for synchronously or asynchronously caching atomic or bulk data. For instance, you can add data with metadata to the cache as follows:
1 2 3 4 5 6 7 8 9 10 11 |
// Get product from a database against the given product ID val product = fetchProductFromDB(1001) // Generate a unique cache key for this product val key = "Product:" + product.getProductId // You can specify multiple properties e.g. Priority, DataExpiration, etc. should you so desire. val cacheItem = new CacheItem(product) // Add CacheItem to cache val version = cache.add(key, cacheItem) |
Similarly, you can update, delete and fetch these CacheItem’s with the appropriate API.
Groups, Tags & Named Tags
Speaking of fetching, one of the ways you can make the process easier is by categorizing them in some way. To this end, NCache offers Groups, Tags, and Named Tags. You can add a CacheItem as part of a logical group as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Get customer from database against given customer ID val customer = fetchCustomerFromDB(1000) // Create a unique cache key for this customer. val key = "Customer:" + customer.getCustomerId //Retrieve cache item from cache val cacheItem = cache.getCacheItem(key) // Specify the new group to be updated cacheItem.setGroup("US Customers") // Re-insert the cacheItem in the cache with updated groups cache.insert(key, cacheItem) |
Further, you can search for them and retrieve their keys, as demonstrated below:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
val groupName = "Important Customers" val retrievedKeys = cache.getSearchService.getGroupKeys(groupName) if (retrievedKeys != null && retrievedKeys.nonEmpty) { // Iterate over the result for (key <- retrievedKeys) { // Perform operations } } else { // No data against the group found } |
You can achieve similar results by employing Tags and Named Tags – provided you use the appropriate API.
Conclusion
Scala is one of the most useful programming languages out there, and unfortunately, not many caching solutions offer the support necessary to take advantage of its strengths. Luckily, NCache and its extensive features do not suffer from this drawback. Download NCache today and take your application to the next level!