I recently started investigating Windows Server AppFabric, which is different from Windows Azure AppFabric, and trying understand how to use AppFabric, what are some of the operational support implications and functional capabilities and limitations. To help me get going, I have been reading the book Pro Windows Server AppFabric by Stephen Kaufman and going through the Windows Server AppFabric Training Kit. The free downloadable training kit was more valuable in helping me understand Windows Server AppFabric.
As always, the only way to truly learn new technology is to take it out for a spin. Here are some of the powershell scripts that I've used to create the cache and get it going:
# Import the necessary administration modules Import-Module DistributedCacheAdministration Import-Module DistributedCacheConfiguration # List the available powershell commands Get-Command -module DistributedCacheAdministration Get-Command -module DistributedCacheConfiguration # These were run on the localhost of AppFabric Use-CacheCluster # Start the cache cluster Start-CacheCluster # Check to make sure it is up and running Get-CacheHost # Create a new cache New-Cache -CacheName MyTestCache -TimeToLive 60 -Expirable true # Check cache is created Get-Cache # Grant local user access to cache Grant-CacheAllowedClientAccount MyUserId # Check security settings Get-CacheAllowedClientAccounts # After a few runs, check Cache statistics Get-CacheStatistics -CacheName MyTestCache # Get Cache configuration information Get-CacheConfig MyTestCache # Creating a Cache with HA - all server needs to be on # Windows Server Enterprise Edition # Any host not on Enterprise Edition will not start cache cluster New-Cache MyNewHACache -Secondaries 1 # Modifying the cache to enable callbacks Set-CacheConfig -CacheName MyTestCache -NotificationsEnabled true -TimeToLive 180
For the client, I wrote some F# scripts to experiment with Windows Server AppFabric. I ran these on the local server and the loopback adapter enabled:
// I copied the libraries from c:\windows\system32\appfabric #r @"C:\lib\Microsoft.ApplicationServer.Caching.Client.dll" #r @"C:\lib\Microsoft.ApplicationServer.Caching.Core.dll" open System open System.Collections.Generic open Microsoft.ApplicationServer.Caching // Make sure you grant // grant-cacheallowedclientaccount my-user-id // Expensive operation, do this once on startup let dcf = new DataCacheFactory( let servers = new List<DataCacheServerEndpoint>() new DataCacheServerEndpoint("localhost",22233) |> servers.Add new DataCacheFactoryConfiguration(Servers=servers)) printfn "Data Cache Factory Created!" // Testing add/get in default region let cache = dcf.GetCache("MyTestCache") let retval = cache.Add("mykey","hello app fabric!") cache.Get("mykey") // Create a new region in the cache, this will pin to a single cache node cache.CreateRegion("stocks") // Helper function to create DataCacheTags let createTags tags = Seq.map (fun tag -> new DataCacheTag(tag)) tags type Company = { Symbol : string; Name: string; Address : string; Phone : string; Tags :seq<string> } // Create a bunch of company info and put it in the "stocks" region [{Symbol="AAPL"; Name="Appl Inc."; Phone="408-996-1010"; Address="1 Infinite Loop, Cupertino, CA 95014"; Tags = ["Technology";"Nasdaq";"Personal Computers"]}; {Symbol="CAT"; Name="Caterpillar, Inc."; Phone="309-675-1000"; Address="100 North East Adams Street, Peoria, IL 61629"; Tags = ["Dow";"Industrial Goods";"Farm & Construction Machinery"]}; {Symbol="ACI"; Name="Arch Coal, Inc."; Phone="314-994-2700"; Address="Once City Place Drive, Suite 300, St. Louis, MO 63141"; Tags = ["Basic Materials";"Industrial Metals & Materials"]}; {Symbol="HP"; Name="Hewlett-Packard Company"; Phone="650-857-1501"; Address="3000 Hanover Street, Palo Alto, Ca 94304"; Tags = ["Dow";"Technology"; "Diversified Computer Systems"]}; {Symbol="JPM"; Name="JP Morgan Chase & Co."; Phone="212-270-6000"; Address="270 Park Avenue, New York, NY 10017"; Tags = ["Dow";"Financial"; "Money Center Banks"]}; {Symbol="XOM"; Name="Exxon Mobile Corporation"; Phone="972-444-1000"; Address="5959 Las Colinas Boulevard, Irving, TX 75039-2298"; Tags = ["Dow";"Basic Materials"; "Major Integrated Oil & Gas"]};] |> Seq.iter (fun item -> cache.Put(item.Symbol, item, (createTags item.Tags),"stocks") |> ignore) // Get all stocks in "stocks" region as a HashMap let stocks = cache.GetObjectsInRegion("stocks") // Bulk get, only available with defined regions not default region let myportfolio = ["AAPL";"CAT";"HP";"JPM"] let mystocks = cache.BulkGet(myportfolio,"stocks") // Getting objects from cache by tags (again, only available in defined region) cache.GetObjectsByTag(new DataCacheTag("Dow Jones"),"stocks") // Getting stuff by all tags (AND filter) let candidateTags = ["Technology"; "Personal Computers"] |> createTags cache.GetObjectsByAllTags(candidateTags,"stocks") // Getting stuff by any tags (OR filter) let interestTags = ["Technology"; "Financial"; "Basic Materials"] |> createTags cache.GetObjectsByAnyTag(interestTags,"stocks") // Concurrency policy is strictly done by the client // No explicit cache server control on concurrency // Optimistic Currency example cache.Remove("mykey") let version = cache.Add("mykey","mystuff") // Pretend another thread snuck in and modified this cache item. cache.Put("mykey","changed value") // This will check that somebody else modified this and throw an exception cache.Put("mykey","another value",version) // Pessimistic locking - locks across all cache nodes let mutable lockHandle:DataCacheLockHandle = null let item = cache.GetAndLock("mykey",TimeSpan.FromMinutes(60.0), &lockHandle,true) // This will throw error due to the first lockHandle let mutable lockHandle2:DataCacheLockHandle = null // This will throw an exception as it was already previously locked let item2 = cache.GetAndLock("mykey",TimeSpan.FromMinutes(60.0),&lockHandle2, true) // This will totally ignore locking policies and overwrite things // Locking is controlled by diligence on the client side. cache.Put("mykey","no enforced concurrency on the server") // Finally, this will update the data and unlock this item in the cache // Need to redo the GetAndLock for this to work. Previous statement would wipe out the lock cache.PutAndUnlock("mykey","new stuff",lockHandle) // Working with Callbacks (DataCacheOperations.AddItem, fun cacheName regionName key version cacheOperation nd -> printfn "Item added to cache : %s\n" key) |> cache.AddCacheLevelCallback |> ignore // When this is call, it could be seconds or minutes before anything // is printed to the console cache.Add("newkey","new stuff")