【问题标题】:save IP address in mongoDB在mongoDB中保存IP地址
【发布时间】:2013-03-13 13:01:41
【问题描述】:

目前为了保存 IP 地址,我将其转换为数字并将其存储在集合中。基本上我这样做是为了记录目的。这意味着我希望尽可能快地以最小的空间存储信息。

我很少用它来查询。

我的想法

  • 存储为字符串肯定是低效的。
  • 存储为 4 位数字会更慢并且会占用更多空间。

尽管如此,我认为这是一种足够的方法,但是否有更好的方法适合我的目的?

【问题讨论】:

  • 4 个整数不适用于 IPv6 地址。 4 位数字不会比字符串占用更多空间。老实说,您必须决定是从源字符串进行转换还是空间损失更重要,并据此做出决定。
  • 是否需要查询生成的结构?如果 MongoDB 与其他数据库写入操作竞争,它可能不是日志记录的最佳选择。尝试选项,看看它们的表现如何。查看集合的stats (docs.mongodb.org/manual/reference/collection-statistics) 以了解平均文档的大小。您可能还想在内存缓冲中做一些事情,而不是编写许多微小的单个文档。
  • 你应该转换成字符串并存储它。
  • 我将它们存储为字符串。请记住,很快您将只有 IPv6,而且这些都是字符串和数字。
  • 如果可能,您应该将其存储为 4 字节整数。如果您有[o1, o2, o3, o4],则整数表示计算为o1<<24 + o2<<16 + o3<<8 + o4。这将使用比 4 元素列表更少的空间。

标签: mongodb ip-address


【解决方案1】:

绝对将 IP 地址保存为数字,如果您不介意这需要额外的工作,特别是如果您需要对地址进行查询并且您有大型表/集合。

原因如下:

存储

  • 如果存储为无符号整数,IPv4 地址为 4 个字节。
  • 当以点分八进制格式作为字符串写出时,IPv4 地址在 10 字节和 18 字节之间变化。 (假设平均值为 14 个字节。)

字符占 7-15 个字节,如果您使用的是可变长度字符串类型,则为 2-3 个字节,这取决于您使用的数据库。如果您有可用的固定长度字符串表示,则必须使用 15 个字符的固定宽度字段。

磁盘存储很便宜,因此在大多数用例中这不是一个因素。然而,内存并不便宜,如果您有一个大表/集合并且想要进行快速查询,那么您需要一个索引。字符串编码的 2-3 倍存储损失极大地减少了您可以索引的记录数量,同时仍将索引保留在内存中。

  • 如果存储为无符号整数,则 IPv6 地址为 16 个字节。 (可能是多个 4 或 8 字节整数,具体取决于您的平台。)
  • 一个 IPv6 地址的范围从 6 个字节到 42 个字节,当以十六进制缩写表示法编码为一个字符串时。

在低端,环回地址 (::1) 是 3 个字节加上可变长度字符串开销。在高端,像2002:4559:1FE2:1FE2:4559:1FE2:4559:1FE2 这样的地址使用 39 个字节加上可变长度字符串开销。

与 IPv4 不同,假设 IPv6 字符串的平均长度为 6 和 42 的平均值是不安全的,因为具有大量连续零的地址数量仅占整个 IPv6 地址空间的一小部分。只有一些特殊地址,如 loopback 和 autoconf 地址,可能会以这种方式进行压缩。

同样,对于字符串编码,与整数编码相比,这会造成 >2 倍的存储损失。

网络数学

您认为路由器将 IP 地址存储为字符串吗?他们当然不会。

如果您需要对 IP 地址进行网络数学运算,则字符串表示很麻烦。例如。如果您想编写一个搜索特定子网上所有地址的查询(“返回所有 IP 地址在 10.7.200.104/27 的记录”,您可以通过使用整数子网掩码屏蔽整数地址来轻松完成此操作。( Mongo 不支持此特定查询,但大多数 RDBMS 支持。)如果将地址存储为字符串,那么您的查询将需要将每一行转换为整数,然后对其进行屏蔽,这会慢几个数量级。(按位屏蔽对于 IPv4 地址,可以使用 2 个寄存器在几个 CPU 周期内完成。将字符串转换为整数需要遍历字符串。)

同样,整数地址的范围查询(“返回 192.168.1.50 和 192.168.50.100 之间的所有记录”)将能够使用索引,而对字符串地址的范围查询则不能。

底线

这需要更多的工作,但并不多(有一百万个 aton() 和 ntoa() 函数在那里),但是如果你正在构建一些严肃而可靠的东西,并且你想在未来证明它不受未来的需求和大型数据集的可能性,您应该将 IP 地址存储为整数,而不是字符串。

如果您正在做一些快速而肮脏的事情,并且不介意将来进行改造的可能性,那么请使用字符串。

出于 OP 的目的,如果您正在优化速度和空间,并且您认为您不想经常查询它,那么为什么要使用数据库呢?只需将 IP 地址打印到文件中。这将比将其存储在数据库中(具有相关的 API 和存储开销)更快、存储效率更高。

【讨论】:

  • 任何人都知道有什么好的资源可以记录在 mongodb 中存储 IP 地址的最佳/推荐方式吗?问题表明用户是这样做的,但我想知道他们是如何做到的。搜索“如何在 mongodb 中存储 ip 地址?”等主要显示与白名单IP相关的结果。谢谢。
【解决方案2】:

一种将 IP 地址保存为 int 的有效方法。如果你想用 cidr 过滤器标记一个 ip,这里有一个演示:

> db.getCollection('iptag').insert({tags: ['office'], hostmin: 2886991873, hostmax: 2887057406, cidr: '172.20.0.0/16'})
> db.getCollection('iptag').insert({tags: ['server'], hostmin: 173867009, hostmax: 173932542, cidr: '10.93.0.0/16'})
> db.getCollection('iptag').insert({tags: ['server'], hostmin: 173932545, hostmax: 173998078, cidr: '10.94.0.0/16'})

创建标签索引。

> db.getCollection('iptag').ensureIndex(tags: 1)

使用 cidr 范围过滤 ip。 ip2int('10.94.25.32') == 173938976.

> db.getCollection('iptag').find({hostmin: {$lte: 173938976}, hostmax: {$gte: 173938976}})

【讨论】:

    【解决方案3】:

    IPv4 是 4 个字节,因此您可以将其存储为 32 位整数(BSON 类型 16)。

    http://docs.mongodb.org/manual/reference/bson-types

    【讨论】:

    • 我想你还没有阅读我的问题。我知道我可以以这种方式存储它们,并且我已经将其写在问题中。我正在寻找一个更详尽的答案,然后您可以将它们存储为整数。
    • 我确实读过它。您的问题听起来像是“我以最好的方式做到了,但还有什么更好的方法?”。所以基本上我的回答是'是的,我认为这是最好的方法'。而且没有必要为这么简单的答案写一本书。
    【解决方案4】:

    IPv4 的最简单方法是使用 here 提供的有趣数学转换为 int。

    我使用下面的函数(js)在与db匹配之前进行转换

    ipv4Number: function (ip) {
        iparray = ip.split(".");
        ipnumber = parseInt(iparray[3]) +
            parseInt(iparray[2]) * 256 +
            parseInt(iparray[1]) * Math.pow(256, 2) +
            parseInt(iparray[0]) * Math.pow(256, 3);
        if (parseInt(ipnumber) > 0)return ipnumber;
        return 0;
    }
    

    【讨论】:

    • 这样做绝对没有意义,因为大多数语言都有做类似事情的本机函数。问题也不在于如何将 IP 转换为整数。
    猜你喜欢
    • 2012-08-31
    • 2014-07-28
    • 2015-02-28
    • 2011-03-04
    • 1970-01-01
    • 2013-07-21
    • 2016-01-13
    • 2014-07-05
    • 1970-01-01
    相关资源
    最近更新 更多