我在下面的 ip_location 表中存储了 30 亿个 IP。
CREATE TABLE ip_location (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
ip VARCHAR(15) NOT NULL,
country VARCHAR(2),
region_1 VARCHAR(255),
region_2 VARCHAR(255),
latitude DECIMAL(10, 6) NOT NULL,
longitude DECIMAL(10, 6) NOT NULL,
INDEX idx_ip (ip)
);
// example json data
{
"ip": "1.2.3.4",
"country": "US",
"region_1": "California",
"region_2": "San Francisco",
"latitude": 37.769700,
"longitude": -122.393300
}
我们推出的服务受到世界各地人们的欢迎。 我想将我们的一些 API 限制在特定区域。 检查用户的访问位置,每次用户调用时检查数据库中的IP API增加了DB和网络的负担。 因此我想将IP数据预加载到内存中以减少负载。
您能否建议一种存储和访问此类数据的有效方法? 我打算将所有数据加载到 Redis,但我认为它需要大量 RAM,我错了吗?
您可以自己存储 IP 地址,但似乎更好的主意是仅在 Redis 中存储最近使用的 IP 地址,也许是您在最近 30 分钟内收到请求的 IP 地址,并定期清空这些 IP 地址有一段时间没有发送请求了。
您可以通过以下方式查询IP地址所属国家
https://api.country.is/<the IP address>
用你的IP亲自尝试一下。
所以流程是:
您需要更好地规范化该表,并使用更好的数据类型。这将减少数据的大小。
binary(4)
中,否则使用 binary(16)
。id
列,没有必要,因为 ip
列应该是唯一的,而且很小。通常只有当自然键很宽或经常变化时才需要代理键。CREATE TABLE country (
country CHAR(2) PRIMARY KEY
);
CREATE TABLE region_1 (
id bigint PRIMARY KEY,
country CHAR(2) NOT NULL REFERENCES country (code2),
region_1 VARCHAR(255) NOT NULL,
UNIQUE (country, region_1)
);
CREATE TABLE region_2 (
id bigint PRIMARY KEY,
region_1 bigint REFERENCES region_1 (id),
region_2 VARCHAR(255) NOT NULL,
UNIQUE (region_1, region_2)
);
CREATE TABLE ip_location
(
ip binary(4) NOT NULL PRIMARY KEY,
region_2 bigint NOT NULL REFERENCES region_2 (id),
latitude DECIMAL(10, 6) NOT NULL,
longitude DECIMAL(10, 6) NOT NULL,
);
然后您可以使用联接来获取所需的数据。
例如:
SELECT
r1.country,
r1.region_1,
r2.region_2,
il.latitude,
il.longitude
FROM ip_location il
JOIN region_2 r2 ON r2.id = il.region_2
JOIN region_1 r1 ON r1.id = r2.region_1
WHERE il.ip = @someIp;
各种主键索引应该使这些连接非常高效。
可能值得将较小的表预先加载到应用程序内存中,这样您就不需要不断地将其从数据库中加载。