Azure Cache for Redis
- Provides in-memory data store based on Redis software
- Redis improves performance and scalability of an app using a backend data store heavily
- Critical for low-latency and high-throughput
- Key scenario patterns:
- Data cache: Load data into cache, update cache if there are data changes
- Content cache: In-memory cache to store static content such as website headers, footers and banners
- Session store: Use cookie as a key to query data in a database, rather than overloading lots of information in user cookies
- Job and message queuing: Add tasks to a queue
- Distributed transactions: Batch commands to perform an operation, all must succeed otherwise roll back to initial state
- Azure Cache for Redis service tiers:
- Basic: OSS Redis cache running on a single VM, no SLA and used only for non-critical workloads
- Standard: OSS Redis cache running on two VMs in a replicated configuration
- Premium: High-performance OSS Redis cache deployed on more powerful VMs. Higher throughput, lower latency, better availability and more features
- Enterprise: High-performance cache powered by Redis Labs' Redis Enterprise software. Supports Redis modules (RediSearch, RedisBloom, RedisTimeSeries). More availability than Premium tier
- Enterprise Flash: Cost-effective large caches powered by same software as Enterprise tier. Extends data storage to nonvolatile memory on a VM (cheaper than DRAM, less per-GB memory cost)
Configuring Azure Cache for Redis
- Use portal, CLI or PowerShell
- Parameters:
- Name: Globally unique name used to generate a public-facing URL for service communication
- 1-63 characters
- Numbers, letters and a hyphen
- Can't start or end with a hyphen, consecutive hyphens aren't valid
- Location: Same region as your application
- Cache type: Service tier
- Clustering support: Premium tiers and above can implement clustering to automatically split a dataset among multiple nodes
- Max. shards is 10
- Cost incurred is the cost of the original node multipled by number of shards
- Name: Globally unique name used to generate a public-facing URL for service communication
- Redis has a CLI tool for interacting with the service as a client
- Download
- Clients need the hostd name, port and access key for the cache
- Host name is the public URL mentioned previously, the access key acts as a password
- A primary and secondary key are generated, either works. Good practice to periodically regenerate keys
- Expire stale cached values by applying a TTL to a key, causing it to automatically delete
- Set using seconds or milliseconds
- Expire time resolution is always 1 millisecond
- Information about expires are replicated and persisted on a disk (saves expiry date of key)
Interact with Azure Cache for Redis by Using .NET
- StackExchange.Redis is a popular high-performance Redis client for .NET
- Connection string for a Redis server:
- ssl: Ensures encrypted communication
- abortConnection: Allows connection to be created even if server is not available at that moment
[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False
- Main connection object is ConnectionMultiplexer to abstract the process of connecting to a Redis server, optimised to handle many connections efficiently
- Provides access to a Redis database
- Make use of publisher/subscribe features of Redis
- Access an individual server for maintenance or monitoring purposes
using StackExchange.Redis; ... var connectionString = "[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False"; var redisConnection = ConnectionMultiplexer.Connect(connectionString);
- Accessing a Redis database
- With the database object, you can store key/values in the cache
IDatabase db = redisConnection.GetDatabase();
bool wasSet = db.StringSet("favorite:flavor", "i-love-rocky-road"); string value = db.StringGet("favorite:flavor"); Console.WriteLine(value); // displays: ""i-love-rocky-road""
- Getting/Setting binary values
- Redis keys and values are binary safe
byte[] key = ...; byte[] value = ...; db.StringSet(key, value); byte[] key = ...; byte[] value = db.StringGet(key);
- Other common operations:
- CreateBatch, CreateTransaction, KeyDelete, KeyExists, KeyExpire, KeyRename, KeyTimeToLive, KeyType
- Complex values such as objects can be serialised to a textual format (XML, JSON) and stored as a string in the cache
- Newtonsoft.Json library in C#
- Cleaning up connection, need to Dispose of the ConnectionMultiplexer
redisConnection.Dispose(); redisConnection = null;
Azure Content Delivery Networks
- Global solution for rapidly delivering high-bandwith content to users
- Caches content at edge location across the world
- Can also accelerate dynamic content which can't be cached, using various network optimisations using CDN POPs
- Benefits of using Azure CDN to deliver web assets:
- Better performance and UX for end users, especially apps which use multiple round-trips to load content
- Large scaling to handle high loads, such as launch of a product
- Distribution of user requests and serving content directly from edge servers so there's less traffic sent to the origin server
- Key features:
- Dynamic site acceleration
- CDN caching rules
- HTTPS custom domain support
- Azure diagnostics log
- File compression
- Geo-filtering
How It Works
- Steps:
- Request Routing: A user requests a file via a URL (ex. <endpoint name>.azureedge.net). The DNS routes the request to the nearest or best-performing POP
- Cache Lookup: If the file isn't in the POP's cache, the POP fetches it from the origin server (ex. Azure Web App, Storage Account or any web server)
- File Delivery: The origin server sends the file to the POP, where it's cached and delivered to the user
- Caching: The file remains in the cache for a TTL duration, improving performance for subsequent users requesting the same file
- Requirements:
- Own at least one Azure subscription
- Need to create a CDN profile (collection of CDN endpoints)
- Create multiple CDN profiles if you want to use a mix of pricing tiers (Azure CDN pricing is applied at the CDN profile level)
- Limitations (each subscription has default limits for the following resources):
- Number of CDN profiles created
- Number of endpoints created in a CDN profile
- Number of custom domains mapped to an endpoint
Control Cache Behaviour on Azure CDN
- Use CDN caching rules to set or modify default cache expiration (either global or with custom conditions)
- Global: Set one global caching rule for each endpoint in your profile, affecting all requests to the endpoint. Overrides any HTTP cache-directive headers if applied
- Custom: Set one or more custom caching rules for each endpoint in your profile. Match specific paths and file extensions, processed in order and override global caching rule if applied
- Query string caching adjusts how Azure CDN treats caching for requests
- In the Standard ruels engine for Azure CDN, a rule consists of one or more match conditions and an action
- Common uses include overriding / defining a custom cache policy, redirecting requests and modifying HTTP request and response headers
- Each rule can have up to four match conditions
- Match conditions:
- Device type, HTTP version, request cookies, post argument, query string
- TTL is determined by the Cache-Control header in the HTTP response from origin server
- Azure CDN sets a default TTL if the user doesn't set one on the file (can be overridden via caching rules)
- Default TTL values:
- Generalised web delivery optimisations (7 days)
- Large file optimisations (1 day)
- Media streaming optimisations (1 year)
- Azure CDN caches content until its TTL expires
- After expiration, the edge node retrieves the latest version from origin to ensure users always get updated assets, version assets with new URLs for updates
- For urgent updates, purge cached content to refresh assets across edge notes using the portal, CLI or wildcards
az cdn endpoint purge \ --content-paths '/css/*' '/js/app.js' \ --name ContosoEndpoint \ --profile-name DemoProfile \ --resource-group ExampleGroup
- Preloading assets into an endpoint is useful if your app creates a large number of assets, this improves UX by prepopulating the cache before any actual requests occur
az cdn endpoint load \ --content-paths '/img/*' '/js/module.js' \ --name ContosoEndpoint \ --profile-name DemoProfile \ --resource-group ExampleGroup
- Geo-filtering enables you to allow or block content from specific countries/regions (based on country/region code)
- In the Standard tier, you can only allow or block the entire site
Interact with Azure CDN Using .NET
- From Visual Studio Package Manager console or .NET CLI, install Microsoft.Azure.Management.Cdn
- Creating a CDN client
static void Main(string[] args) { // Create CDN client CdnManagementClient cdn = new CdnManagementClient(new TokenCredentials(authResult.AccessToken)) { SubscriptionId = subscriptionId }; }
- List CDN profiles and endpoints
private static void ListProfilesAndEndpoints(CdnManagementClient cdn) { // List all the CDN profiles in this resource group var profileList = cdn.Profiles.ListByResourceGroup(resourceGroupName); foreach (Profile p in profileList) { Console.WriteLine("CDN profile {0}", p.Name); if (p.Name.Equals(profileName, StringComparison.OrdinalIgnoreCase)) { // Hey, that's the name of the CDN profile we want to create! profileAlreadyExists = true; } //List all the CDN endpoints on this CDN profile Console.WriteLine("Endpoints:"); var endpointList = cdn.Endpoints.ListByProfile(p.Name, resourceGroupName); foreach (Endpoint e in endpointList) { Console.WriteLine("-{0} ({1})", e.Name, e.HostName); if (e.Name.Equals(endpointName, StringComparison.OrdinalIgnoreCase)) { // The unique endpoint name already exists. endpointAlreadyExists = true; } } Console.WriteLine(); } }
- Create CDN profiles and endpoints
private static void CreateCdnProfile(CdnManagementClient cdn) { if (profileAlreadyExists) { Console.WriteLine("Profile {0} already exists.", profileName); } else { Console.WriteLine("Creating profile {0}.", profileName); ProfileCreateParameters profileParms = new ProfileCreateParameters() { Location = resourceLocation, Sku = new Sku(SkuName.StandardVerizon) }; cdn.Profiles.Create(profileName, profileParms, resourceGroupName); } }
private static void CreateCdnEndpoint(CdnManagementClient cdn) { if (endpointAlreadyExists) { Console.WriteLine("Endpoint {0} already exists.", endpointName); } else { Console.WriteLine("Creating endpoint {0} on profile {1}.", endpointName, profileName); EndpointCreateParameters endpointParms = new EndpointCreateParameters() { Origins = new List<DeepCreatedOrigin>() { new DeepCreatedOrigin("Contoso", "www.contoso.com") }, IsHttpAllowed = true, IsHttpsAllowed = true, Location = resourceLocation }; cdn.Endpoints.Create(endpointName, endpointParms, profileName, resourceGroupName); } }
- Purge an endpoint
private static void PromptPurgeCdnEndpoint(CdnManagementClient cdn) { if (PromptUser(String.Format("Purge CDN endpoint {0}?", endpointName))) { Console.WriteLine("Purging endpoint. Please wait..."); cdn.Endpoints.PurgeContent(resourceGroupName, profileName, endpointName, new List<string>() { "/*" }); Console.WriteLine("Done."); Console.WriteLine(); } }