【问题标题】:How to memcache or store key value pair when key is in range and not a single value?当键在范围内而不是单个值时,如何内存缓存或存储键值对?
【发布时间】:2016-04-07 18:12:50
【问题描述】:

我们的数据库中有一个表,其中包含城市的静态 IP 范围及其 IP 地址。它看起来像:


IP-TO、IP-FROM、城市

100、110、A

111、168、B

...

965、1000、Z

我已经提到了样本数据。实际数据非常庞大,表中有近 64k 行。

对于我们网站上的每个用户,我们通过在 sql express 服务器上执行 sql 查询,根据他们的 IP 地址确定他们的城市。

由于数据是静态的,例如IP在100到110范围内的每个用户都属于A市,我们每次都不必要地访问数据库。

我们正在考虑缓存每个唯一的 ip 访问。例如: IP-100 映射到 A IP-101 映射到 A ... IP-110 映射到 A

但这会在 memcache 中创建 64k 个键,我觉得当我们知道范围时,存储多个具有相同值的键是没有意义的。

我们能否以某种更好的方式做到这一点,即通过最小的内存缓存键或完全使用不同的方法?

【问题讨论】:

  • 在示例中,我看到每个 IP 范围有 10 个差异。范围是否始终具有恒定值?
  • 没有。这只是样本数据。不像那样。为了更清楚,我会修改它。

标签: c# .net memcached enyim


【解决方案1】:

可以对 IP 地址列表进行排序(因为它们本质上是数字)。如果您有大量不重叠的 IP 范围列表,您可以将它们分类到一个大列表中。如果你有一个大的、排序的值列表,你可以在上面做一个binary search。使用 64k 项,您可以在大约 16 次比较中搜索整个列表(几乎是即时的)。

使用正确的索引和查询,您的数据库或许能够为您完成这项工作。如果您认为另一种方式可能更快(提示:使用分析来确定它是否真的如此!)或者担心对数据库的额外访问,您可以将整个表的数据缓存在内存中,然后搜索列表。概括地说:

public class IPRangeCache
{
    private List<IPRangeRecord> sortedRangeRecords = null; // get from database

    public string GetCity(IPAddress ip) {
        // binary search to find from sortedRangeRecords
    }
}

二分查找需要同时考虑开始和结束的数字。自定义比较器或自定义二进制搜索应该可以做到这一点。这应该很快。

您也可以尝试在字典中缓存最后几分钟的 IP 地址,但我认为它不太可能更快。

【讨论】:

    【解决方案2】:

    我们可以使用 C# 通用字典。

    我们创建一个包含 IP 范围的类。此类将充当字典的键。

    class IP_Range 
    {
        public int MinIP { get; set; }
        public int MaxIP { get; set; }
    }
    

    然后我们必须创建一个比较器类来帮助比较字典的键。

    class IP_RangeComparer : IEqualityComparer<IP_Range>
    {
        public bool Equals(IP_Range r1, IP_Range r2)
        {
            return (r1.MinIP == r2.MinIP && r1.MaxIP == r2.MaxIP);
        }
    
        public int GetHashCode(IP_Range r)
        {
            return r.MinIP.GetHashCode();
        }
    }
    

    然后我们可以创建一个通用字典并如下使用它:

    IDictionary<IP_Range, string> myCache = new Dictionary<IP_Range, string>(new IP_RangeComparer());
    
    // Adding entries
    myCache.Add(new IP_Range() { MinIP = 100, MaxIP = 110 }, "A");
    myCache.Add(new IP_Range() { MinIP = 111, MaxIP = 168 }, "B");
    myCache.Add(new IP_Range() { MinIP = 169, MaxIP = 200 }, "C");
    
    // Reading the dictionary
    string city = myCache[new IP_Range() { MinIP = 169, MaxIP = 200 }];
    

    更多解释请参考this article

    注意:要找出您正在搜索的特定 IP 的密钥,您必须遍历 myCache.Keys 集合。

    【讨论】:

      【解决方案3】:

      您可以创建IpAddressfrom the value 的实例,然后仅使用one of the bytes 作为缓存键。这样,您只需为 001.xxx.xxx.xxx 访问一次数据库,为 002.xxx.xxx.xxx 访问一次,等等。

      var address = new IPAddress(value);
      var bytes = address.GetAddressBytes(); //an array of four bytes
      

      【讨论】:

        猜你喜欢
        • 2011-03-08
        • 1970-01-01
        • 2021-12-10
        • 2014-03-20
        • 2020-06-09
        • 1970-01-01
        • 2017-06-12
        • 2011-07-04
        • 1970-01-01
        相关资源
        最近更新 更多