本文作者:小黑黑

[微信]缓存策略和分布式锁的使用

小黑黑 1年前 ( 2019-03-31 ) 394 抢沙发
[微信]缓存策略和分布式锁的使用摘要:        缓存是几乎所有大中型系统中非常重要的核心组成部分之一,我们也都使用过缓存,比如本地缓存,Redi...

       缓存是几乎所有大中型系统中非常重要的核心组成部分之一,我们也都使用过缓存,比如本地缓存,Redis缓存等,合理的使用缓存可以有效地减少服务器的计算量,有效的提升响应速度,让有限的资源服务更多的用户。

       SDK中许多的信息同样缓存的支持,如凭证信息,AppId,AppSecret等。SDK提供了三种缓存策略,分别是本地缓存,分布式缓存(Redis,MemCached),至于我们需要使用哪种缓存,我们可以根据自己实际的开发需要进行相应的配置,这里不讨论SDK中缓存策略的实现,有兴趣的可以下载源码研究。

一、使用本地缓存

       使用本地缓存我们不需要进行其他的配置,SDK默认使用的是本地缓存,下面是本地缓存的基本使用。

//获取缓存对象(本地缓存、Redis缓存、Memcached)都通过此方法获取
var cache = CacheStrategyFactory.GetObjectCacheStrategyInstance();

//设置缓存
cache.Set("A", "123");

//获取缓存
string str = cache.Get("A").ToString();

//删除缓存信息
cache.RemoveFromCache("A");

二、使用Redis缓存

       使用Redis缓存,实现我们要从nuget获取Senparc.Weixin.Cache.Redis.dll,然后在Startup类中配置以下信息。

//启用CO2NET曲剧注册,必须!
IRegisterService register = RegisterService.Start(env, senparcSetting.Value)
                                           .UseSenparcGlobal();

#region 全局缓存配置

//当同一个分布式缓存同事服务于多个网站,使用命名空间进行隔离
register.ChangeDefaultCacheNamespace("DefaultCache");

#region 配置和使用Redis缓存

var redisConfigurationStr = senparcSetting.Value.Cache_Redis_Configuration;
var useRedis = !string.IsNullOrEmpty(redisConfigurationStr) && redisConfigurationStr != "#Cache_Redis_Configuration#";
if (useRedis)
{
    Senparc.CO2NET.Cache.Redis.Register.SetConfigurationOption(redisConfigurationStr);

    Senparc.CO2NET.Cache.Redis.Register.UseKeyValueRedisNow();
}


#endregion
#endregion

#region 微信缓存设置,必须配置在 register.UseSenparcWeixin()之前

if (useRedis)
{
    app.UseSenparcWeixinCacheRedis();
}

#endregion

#region 开始注册微信信息

//开始注册微信信息
register.UseSenparcWeixin(senparcWeiXinSetting.Value, senparcSetting.Value)

#region 注册微信公众号或小程序
        .RegisterMpAccount(senparcWeiXinSetting.Value, "微信公众号开发Demo");

#endregion
#endregion

然后我们需要去appsettings.json文件中进行配置redis的连接字符串。

"SenparcSetting": {
  "DefaultCacheNamespace": "DefaultCache",

  //Redis配置
  "Cache_Redis_Configuration": "localhost:6379" //不包含密码
  //"Cache_Redis_Configuration": "localhost:6379,password=password,connectTimeout=1000,connectRetry=2,syncTimeout=10000,defaultDatabase=3"  密码及其他配置
},

注意是在SenparcSetting节点中配置,而不是SenparcWeiXinSetting。配置完之后,我们就可以使用Redis缓存了,使用Redis的方式和本地缓存一样,不需要进行改动。

//获取缓存对象(本地缓存、Redis缓存、Memcached)都通过此方法获取
var cache = CacheStrategyFactory.GetObjectCacheStrategyInstance();

//设置缓存
cache.Set("A", "123");

//获取缓存
string str = cache.Get("A").ToString();

//删除缓存信息
cache.RemoveFromCache("A");

三、使用Memcached缓存

      使用Memcached缓存的方式和使用Redis缓存的方式一样。我们同样需要先引用Senparc.Weixin.Cache.Memcached.dll,剩余的Startup配置以及appsettings.json的配置和Redis一样。

//启用CO2NET曲剧注册,必须!
IRegisterService register = RegisterService.Start(env, senparcSetting.Value)
                                           .UseSenparcGlobal();

#region 全局缓存配置

//当同一个分布式缓存同事服务于多个网站,使用命名空间进行隔离
register.ChangeDefaultCacheNamespace("DefaultCache");

#region 配置和使用Memcached缓存

var memcachedConfigurationStr = senparcSetting.Value.Cache_Memcached_Configuration;
var useMemcached = !string.IsNullOrEmpty(memcachedConfigurationStr) && memcachedConfigurationStr != "#Cache_Memcached_Configuration#";
if (useMemcached)
{
    Senparc.CO2NET.Cache.Memcached.Register.SetConfigurationOption(memcachedConfigurationStr);
    Senparc.CO2NET.Cache.Memcached.Register.UseMemcachedNow();
}
#endregion

#endregion

#region 微信缓存设置,必须配置在 register.UseSenparcWeixin()之前

if (useMemcached)
{
    app.UseSenparcWeixinCacheMemcached();
}
#endregion

#region 开始注册微信信息

//开始注册微信信息
register.UseSenparcWeixin(senparcWeiXinSetting.Value, senparcSetting.Value)

#region 注册微信公众号或小程序
        .RegisterMpAccount(senparcWeiXinSetting.Value, "微信公众号开发Demo");

#endregion
#endregion
"SenparcSetting": {
    "DefaultCacheNamespace": "DefaultCache",
    "Cache_Memcached_Configuration": "#{Cache_Memcached_Configuration}#" //Memcache缓存配置
  }

四、分布式锁的使用

       锁的概念代价应该都了解,我们在实际项目开发中也或多或少的使用过锁,比如在应用服务器是单机的情况下,我们通常使用lock关键字对同一静态变量进行加锁,达到对某些资源过过程互斥访问的目的,确保在同一个时间内只有一个线程或过程访问特定的资源,这种加锁的情况在并发场景下是必须考虑的。

       但随着分布式的发展,我们这种在本地加锁的方法往往不能满足我们的需求,在我们分布式的环境中上面加锁的方法就会失效。比如:我们微信公众号开发过程中需要使用AccessToken,AccessToke具有唯一性,每次被重新获取后,之前的AccessToken就会失效,由于我们使用了分布式缓存,当多台服务器的请求同时到达时,a1请求r1服务器,开始获取新的AccessToken,用时0.2秒,在这0.2秒的过程中,a2请求r2服务器,也进行获取新的AccessToken,同时也用时0.2秒,在a1请求获取到r1服务器返回的AccessToken之后,接着处理自己的逻辑,而在a2得到r2服务器返回的AccessToken时,a1的下一次请求的AccessToken就会失效,那么他就会重新执行前面获取AccessToken的过程,相应的a2也会遇到相应的情况,这样就会导致多个请求争夺刷新AccessToken的情况,当获取AccessToken的次数被使用完之后,那么我们的系统将无法继续提供服务,我们虽然在单台服务器上使用lock锁,但这并不能解决我们分布式情况下的问题。

       在SDK中,已经为我们实现了分布式锁,那么我们该怎样使用呢?

//BeginCacheLock创建一个分布式锁
using (var cacheLock = stratgety.BeginCacheLock("Test", "A"))
{
    if (cacheLock.LockSuccessful)
    {
        //成功获取到锁
    }
    else
    {
        //超时,没有拿到锁
    } 
}

在我们需要使用分布式锁的时候,我们只需要这样就可以使用分布式锁了。其中BeginCacheLock方法中有4个参数。

resourceName:资源名称,用于定义当前服务的对象,类似于命名空间。

key:key标识,加锁资源的下一集精确锁定的范围。和resourceName合并成缓存的Key。

retryDelay:重试延时。为了争夺锁,我们需要不停的访问数据库,那么这个就是延时重试的时间。

retryCount:重试次数。


分享到: 网站分享代码

发表评论

快捷回复:

评论列表 (暂无评论,394人围观)参与讨论

还没有评论,来说两句吧...