用于跟踪 IPv6/IPv4 个地址的关系数据库——我提议的模式是否有效?
Relational database for tracking IPv6/IPv4 addresses -- will my proposed schema work?
背景
我正在构建一个 IPAM 应用程序来跟踪和存储各个 IPv4 和 IPv6 地址的元数据。后端旨在成为一个无聊的、与供应商无关的关系数据库。
IPv6 可以在巨大的可寻址范围内处理大量数据 space,但所讨论的范围本身并不构成大数据,所以如果我的技术存在一些实际缺陷,我不愿意更改后端架构当前的方法最好由时髦的 NoSQL 解决方案提供,但代价是关系和 ACIDity。
(我不是要记录整个地址 space,只是任意客户使用的实时地址。)
架构
规范化给定 IP 地址的字符串表示形式并将其用作主键。 IPv4 地址被转换为 IPv6 并以 ffff
为前缀。 IPv6 地址被压缩和小写。
第二个字段指示相关记录是哪个协议版本——4 或 6。这里的想法是,如果用户在 IPv4 子网中搜索记录,我可以快速排除 IPv6 space ,反之亦然。
接下来的八个字段 (ugh) 都是地址中每个八位字节的整数表示(octet_1
、octet_2
等)。
索引
主键应该已经是它自己的唯一索引。
在 (version, octet_1, ..., octet_8)
上创建一个附加索引。
正在查询
为了搜索任一版本的特定 IP,我可以简单地按照与上述相同的方式规范化 IP 字符串并通过主键搜索。
为了按子网搜索,应用程序计算范围的 start/end 地址,将两者都转换为 IPv6,将两者都转换为八元组,并查询所有包含八元组的记录。
我 运行 使用这种方法可能会遇到什么问题?改进建议?
从 ipv4s casted as ipv6 are not the same thing
到 your index will explode / write performance will suck
的任何内容都是公平的游戏。
我构建了一个测试 POC 来验证此模式的功能,但我担心此模型在生产环境中的任何潜在缺点。
如果你可以选择数据库后端,那就选择 PostgreSQL。它内置了 IP 地址类型,因此提供了出色的性能和功能。
但是您说过您想成为数据库不可知论者,所以让我们专注于此。在那种情况下,我将仅使用以 ::ffff: 为前缀的 IPv4 地址进行字符串表示,但随后仅使用小写十六进制表示法并且不进行压缩。所以 IPv4 地址 10.11.12.13 将变为 0000:0000:0000:0000:0000:ffff:0a0b:0c0d.
几乎所有的数据库都有良好的字符串索引,使用这种表示法您可以轻松地进行子网和范围查询。如果您想要所有 IPv4 地址,只需查询 LIKE '0000:0000:0000:0000:0000:ffff:%'。因为它是在开始时锚定的,所以标准的 btree 索引应该运行良好。您可以使用 < 和 > 运算符对范围进行更复杂的查询,这同样可以从标准索引中受益。这应该会为您提供大多数子网查询。
在您的应用程序中,使用 inet_pton 等解析字符串以将它们转换为您需要的任何内容应该不会太难。
在这种情况下我会避免反规范化。使用我上面描述的内容,您不需要单独的版本或八位字节列。它们只会减慢速度并增加不一致的可能性。
在 "Schema" 下,您尚未提供实际架构。
"IPv4 addresses get converted to IPv6 and prefixed with ..." 暴露你不理解 IPV6 的意图和目的。
"IPv6 addresses get ... lowercased." 表明您不了解值和值表示之间的区别("get lowercased" 可能会影响 表示 的值,但它 永远不会 影响 值本身).
"if a user searches for records in an IPv4 subnet" 表明您不了解 OSI 7 层模型的构思者在构思其网络通信模型时所考虑的关注点分离。 "Searching for records"与IP(v4/v6)不是同层函数。
"Primary key should already be its own unique index." 暴露你不懂关系型数据管理
您可能会觉得这不是您问题的答案,但实际上它是。
背景
我正在构建一个 IPAM 应用程序来跟踪和存储各个 IPv4 和 IPv6 地址的元数据。后端旨在成为一个无聊的、与供应商无关的关系数据库。
IPv6 可以在巨大的可寻址范围内处理大量数据 space,但所讨论的范围本身并不构成大数据,所以如果我的技术存在一些实际缺陷,我不愿意更改后端架构当前的方法最好由时髦的 NoSQL 解决方案提供,但代价是关系和 ACIDity。
(我不是要记录整个地址 space,只是任意客户使用的实时地址。)
架构
规范化给定 IP 地址的字符串表示形式并将其用作主键。 IPv4 地址被转换为 IPv6 并以 ffff
为前缀。 IPv6 地址被压缩和小写。
第二个字段指示相关记录是哪个协议版本——4 或 6。这里的想法是,如果用户在 IPv4 子网中搜索记录,我可以快速排除 IPv6 space ,反之亦然。
接下来的八个字段 (ugh) 都是地址中每个八位字节的整数表示(octet_1
、octet_2
等)。
索引
主键应该已经是它自己的唯一索引。
在 (version, octet_1, ..., octet_8)
上创建一个附加索引。
正在查询
为了搜索任一版本的特定 IP,我可以简单地按照与上述相同的方式规范化 IP 字符串并通过主键搜索。
为了按子网搜索,应用程序计算范围的 start/end 地址,将两者都转换为 IPv6,将两者都转换为八元组,并查询所有包含八元组的记录。
我 运行 使用这种方法可能会遇到什么问题?改进建议?
从 ipv4s casted as ipv6 are not the same thing
到 your index will explode / write performance will suck
的任何内容都是公平的游戏。
我构建了一个测试 POC 来验证此模式的功能,但我担心此模型在生产环境中的任何潜在缺点。
如果你可以选择数据库后端,那就选择 PostgreSQL。它内置了 IP 地址类型,因此提供了出色的性能和功能。
但是您说过您想成为数据库不可知论者,所以让我们专注于此。在那种情况下,我将仅使用以 ::ffff: 为前缀的 IPv4 地址进行字符串表示,但随后仅使用小写十六进制表示法并且不进行压缩。所以 IPv4 地址 10.11.12.13 将变为 0000:0000:0000:0000:0000:ffff:0a0b:0c0d.
几乎所有的数据库都有良好的字符串索引,使用这种表示法您可以轻松地进行子网和范围查询。如果您想要所有 IPv4 地址,只需查询 LIKE '0000:0000:0000:0000:0000:ffff:%'。因为它是在开始时锚定的,所以标准的 btree 索引应该运行良好。您可以使用 < 和 > 运算符对范围进行更复杂的查询,这同样可以从标准索引中受益。这应该会为您提供大多数子网查询。
在您的应用程序中,使用 inet_pton 等解析字符串以将它们转换为您需要的任何内容应该不会太难。
在这种情况下我会避免反规范化。使用我上面描述的内容,您不需要单独的版本或八位字节列。它们只会减慢速度并增加不一致的可能性。
在 "Schema" 下,您尚未提供实际架构。
"IPv4 addresses get converted to IPv6 and prefixed with ..." 暴露你不理解 IPV6 的意图和目的。
"IPv6 addresses get ... lowercased." 表明您不了解值和值表示之间的区别("get lowercased" 可能会影响 表示 的值,但它 永远不会 影响 值本身).
"if a user searches for records in an IPv4 subnet" 表明您不了解 OSI 7 层模型的构思者在构思其网络通信模型时所考虑的关注点分离。 "Searching for records"与IP(v4/v6)不是同层函数。
"Primary key should already be its own unique index." 暴露你不懂关系型数据管理
您可能会觉得这不是您问题的答案,但实际上它是。