Azure 角色中缓存中的并发模型
重要
Microsoft 建议所有新开发使用 Azure Redis 缓存。 有关选择 Azure 缓存产品/服务的当前文档和指南,请参阅 哪种 Azure 缓存产品/服务适合我?
缓存体系结构允许任何缓存客户端访问任何缓存的数据(如果这些客户端具有适当的网络访问权限和配置设置)。 这对并发是一个挑战。
为了帮助你的应用程序处理并发问题,乐观并发模型和悲观并发模型均受系统支持。
乐观并发模型
在乐观并发模型中,对缓存对象的更新不需要锁定。 但当缓存客户端从缓存获得对象时,它还获得并存储该对象的当前版本。 当需要进行更新时,缓存客户端会将对象新值与已存储的版本对象一起发送。 仅当发送的版本与缓存中对象的当前版本匹配时,系统才会更新对象。 对象的每次更新都会更改其版本号,这可以防止更新覆盖其他人的更改。
本主题中的示例介绍乐观并发模式如何维护数据的一致性。
示例
在此示例中,两个缓存客户端(cacheClientA
和 cacheClientB
)将尝试更新具有相同键 RadioInventory
的同一缓存对象。
时间零:两个客户端检索同一对象
在时间零点 (T0),两个客户端都实例化 DataCacheItem 类,以捕获其要更新的缓存对象,以及与已该缓存对象关联的其他信息(例如,版本和标记信息)。 以下代码示例阐释了这一点。
'cacheClientA pulls the FM radio inventory from cache
Dim clientACacheFactory As DataCacheFactory = New DataCacheFactory()
Dim cacheClientA As DataCache = _
clientACacheFactory.GetCache("catalog")
Dim radioInventoryA As DataCacheItem = _
cacheClientA.GetCacheItem("RadioInventory")
'cacheClientB pulls the same FM radio inventory from cache
Dim clientBCacheFactory As DataCacheFactory = New DataCacheFactory()
Dim cacheClientB As DataCache = _
clientBCacheFactory.GetCache("catalog")
Dim radioInventoryB As DataCacheItem = _
cacheClientB.GetCacheItem("RadioInventory")
//cacheClientA pulls the FM radio inventory from cache
DataCacheFactory clientACacheFactory = new DataCacheFactory();
DataCache cacheClientA = clientACacheFactory.GetCache("catalog");
DataCacheItem radioInventoryA =
cacheClientA.GetCacheItem("RadioInventory");
//cacheClientB pulls the same FM radio inventory from cache
DataCacheFactory clientBCacheFactory = new DataCacheFactory();
DataCache cacheClientB = clientBCacheFactory.GetCache("catalog");
DataCacheItem radioInventoryB=
cacheClientB.GetCacheItem("RadioInventory");
注意
虽然此示例通过使用 GetCacheItem 方法检索 DataCacheItem 对象来获取版本信息,但也可以使用 Get 方法获取与检索的缓存项关联的 DataCacheItemVersion 对象。
第一次:第一次更新成功
在时间 1(T1),cacheClientA
更新具有新值的缓存对象 RadioInventory
。 当 cacheClientA
执行 Put 方法时,与 RadioInventory
缓存项目相关联的版本会递增。 此时,cacheClientB
具有过期缓存项目。 下面的示例说明了这一点。
'at time T1, cacheClientA updates the FM radio inventory
Dim newRadioInventoryA As Integer = 155
cacheClientA.Put("RadioInventory", newRadioInventoryA, _
radioInventoryA.Version)
//at time T1, cacheClientA updates the FM radio inventory
int newRadioInventoryA = 155;
cacheClientA.Put("RadioInventory", newRadioInventoryA,
radioInventoryA.Version);
时间 2:第二次更新失败
在时间 2(T2),cacheClientB
使用当前过期的版本号尝试更新 RadioInventory
缓存对象。 为防止 cacheClientA
的更改被覆盖,cacheClientB
Put 方法调用失败。 缓存客户端将引发 DataCacheException 对象,并将 ErrorCode 属性设置为 CacheItemVersionMismatch。 以下代码示例阐释了这一点。
'later, at time T2, cacheClientB tries to
'update the FM radio inventory, receives DataCacheException with
'an error code equal to DataCacheErrorCode.CacheItemVersionMismatch.
Dim newRadioInventoryB As Integer = 130
cacheClientB.Put("RadioInventory", newRadioInventoryB, _
radioInventoryB.Version)
//later, at time T2, cacheClientB tries to
//update the FM radio inventory, receives DataCacheException with
//an error code equal to DataCacheErrorCode.CacheItemVersionMismatch.
int newRadioInventoryB = 130;
cacheClientB.Put("RadioInventory", newRadioInventoryB,
radioInventoryB.Version);
悲观并发模型
在悲观并发模型中,客户端明确锁定要执行操作的对象。 锁定被释放之前,请求锁定的其他操作将被拒绝(系统不会阻止请求)。 当锁定对象时,锁定句柄将作为输出参数返回。 需要锁定句柄来解锁对象。 如果客户端应用程序在释放锁定对象前结束,则提供超时以释放锁定。 锁定的对象永不过期,但如果超过过期时间,则锁定的对象可能在被解除锁定后立即过期。
有关用于悲观并发模型的方法的详细信息,请参阅 并发方法
注意
不支持事务跨越操作。
注意
使用缓存的应用程序负责确定锁定的顺序并检测死锁(如果有)。
警告
仍然可以使用 Put 方法将缓存中锁定的对象替换为任何缓存客户端。 启用了缓存的应用程序负责对使用悲观并发模型的项目一致使用 PutAndUnlock。