Redis是否是本地缓存的可行解决方案?

时间:2016-04-15 20:03:05

标签: c# winforms caching asp.net-web-api redis

在我的场景中,我有一个连接到WebApi2的Winforms客户端。数据存储在SQL Server数据库中。

为了提高性能,我正在研究将数据存储在本地缓存中是否可行。优选地,本地高速缓存应该存储在文件中而不是保存在存储器中,因为RAM可能是个问题。数据是所有POCO类,有些比其他类复杂得多,并且大多数类彼此相关。

我列出了哪些框架可行的候选名单:

  1. 的MemoryCache
  2. 分布式缓存
  3. 的CacheManager
  4. StackExchange.Redis
  5. 本地数据库
  6. 使用MemoryCache,我需要实现自己的解决方案,但它符合我的初始要求。

    然而,我看到的一个常见问题是更新相关类。例如,我在CustomerAddressPostCode之间存在关系。如果我更改邮政编码对象中的某些属性,我可以轻松更新其本地缓存。但是如何更新/无效使用此邮政编码的任何其他类,在这种情况下CustomerAddress

    上面的任何框架是否都有帮助这种情况的方法,还是完全依赖于开发人员来处理这种缓存失效?

2 个答案:

答案 0 :(得分:1)

  

为了加快性能,我正在研究是否在本地存储数据   缓存是一个可行的解决方案优选地,本地缓存应该是   存储在文件中而不是保存在内存中,因为RAM可能是一个问题

整个问题是避免将其存储在文件中,以避免缓慢的DISK操作,因此Redis是基于RAM的内存。

  

上面的任何框架都有这种方法有帮助吗?   情况,还是完全依赖于开发人员来处理   这样的缓存失效?

您可以将整个对象保存为JSON,而不是应用逻辑并反汇编对象,这在应用更改时也会很慢并且容易出错。

答案 1 :(得分:1)

CachingFramework.Redis库提供了一种机制,可以将标记与键和哈希相关联,这样您就可以在一次操作中使它们失效。

我假设你会:

  • 使用“地址:{AddressId} ”等密钥在Redis中存储客户地址。
  • 使用“ PostCode:{PostCodeId} ”等密钥将邮政编码存储在Redis中。

你的模型是这样的:

public class CustomerAddress
{
    public int CustomerAddressId { get; set; }
    public int CustomerId { get; set; }
    public int PostCodeId { get; set; }
}
public class PostCode
{
    public int PostCodeId { get; set; }
    public string Code { get; set; }
}

我的建议是:

  • 使用“ Tag-PostCode:{PostCodeId} ”等标记在Redis上标记客户地址对象。
  • 使用cache-aside pattern从缓存/数据库中检索客户地址和邮政编码。
  • 更改邮政编码时,按标签使缓存对象无效。

这样的事情应该可行:

public class DataAccess
{
    private Context _cacheContext = new CachingFramework.Redis.Context("localhost:6379");

    private string FormatPostCodeKey(int postCodeId)
    {
        return string.Format("PostCode:{0}", postCodeId);
    }

    private string FormatPostCodeTag(int postCodeId)
    {
        return string.Format("Tag-PostCode:{0}", postCodeId);
    }

    private string FormatAddressKey(int customerAddressId)
    {
        return string.Format("Address:{0}", customerAddressId);
    }

    public void InsertPostCode(PostCode postCode)
    {
        Sql.InsertPostCode(postCode);
    }

    public void UpdatePostCode(PostCode postCode)
    {
        Sql.UpdatePostCode(postCode);
        //Invalidate cache: remove CustomerAddresses and PostCode related
        _cacheContext.Cache.InvalidateKeysByTag(FormatPostCodeTag(postCode.PostCodeId));
    }

    public void DeletePostCode(int postCodeId)
    {
        Sql.DeletePostCode(postCodeId);
        _cacheContext.Cache.InvalidateKeysByTag(FormatPostCodeTag(postCodeId));
    }

    public PostCode GetPostCode(int postCodeId)
    {
        // Get/Insert the postcode from/into Cache with key = PostCode{PostCodeId}. 
        // Mark the object with tag = Tag-PostCode:{PostCodeId}
        return _cacheContext.Cache.FetchObject(
            FormatPostCodeKey(postCodeId),              // Redis Key to use
            () => Sql.GetPostCode(postCodeId),          // Delegate to get the value from database
            new[] { FormatPostCodeTag(postCodeId) });   // Tags related
    }

    public void InsertCustomerAddress(CustomerAddress customerAddress)
    {
        Sql.InsertCustomerAddress(customerAddress);
    }

    public void UpdateCustomerAddress(CustomerAddress customerAddress)
    {
        var updated = Sql.UpdateCustomerAddress(customerAddress);
        if (updated.PostCodeId != customerAddress.PostCodeId)
        {
            var addressKey = FormatAddressKey(customerAddress.CustomerAddressId);
            _cacheContext.Cache.RenameTagForKey(addressKey, FormatPostCodeTag(customerAddress.PostCodeId), FormatPostCodeTag(updated.PostCodeId));
        }
    }

    public void DeleteCustomerAddress(CustomerAddress customerAddress)
    {
        Sql.DeleteCustomerAddress(customerAddress.CustomerAddressId);
        //Clean-up, remove the postcode tag from the CustomerAddress:
        _cacheContext.Cache.RemoveTagsFromKey(FormatAddressKey(customerAddress.CustomerAddressId), new [] { FormatPostCodeTag(customerAddress.PostCodeId) });
    }

    public CustomerAddress GetCustomerAddress(int customerAddressId)
    {
        // Get/Insert the address from/into Cache with key = Address:{CustomerAddressId}. 
        // Mark the object with tag = Tag-PostCode:{PostCodeId}
        return _cacheContext.Cache.FetchObject(
            FormatAddressKey(customerAddressId),
            () => Sql.GetCustomerAddress(customerAddressId),
            a => new[] { FormatPostCodeTag(a.PostCodeId) });
    }
}