如何高效存储与访问30亿条IP地理位置数据?
IP地址数据高效内存存储与访问方案咨询
我将30亿条IP地址存储在如下ip_location表中:
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) );
示例JSON数据:
{ "ip": "1.2.3.4", "country": "US", "region_1": "California", "region_2": "San Francisco", "latitude": 37.769700, "longitude": -122.393300 }
我们的服务在全球范围受欢迎,希望对部分API做区域访问限制。每次调用API都查数据库验证位置会加重数据库和网络负载,打算把IP数据预加载到内存降负载。想请教这类数据的高效存储与访问方案,另外原本打算全量加载到Redis,但担心内存占用过高,这个顾虑是否正确?
解决方案建议
关于Redis内存占用的顾虑:完全正确
30亿条IP数据如果直接以字符串IP为键、完整位置信息为值存入Redis,内存占用会非常夸张。按每条数据的最小估算:IP字符串平均15字节,位置信息(国家2字节+地区约30字节+经纬度各8字节)大概48字节,再加上Redis键值对的元数据(至少几十字节),总内存保守估计会超过200GB,显然不现实,全量存Redis的方案不可行。
高效存储与访问方案推荐
1. IP段压缩存储:CIDR聚合+二分查找
IPv4本质是32位整数,绝大多数IP是连续段归属同一区域,没必要存储单个IP:
- 先将数据库中的IP转换为整数形式并排序,把归属同一区域的连续IP聚合为CIDR段记录(包含起始IP整数、结束IP整数、区域信息)。30亿条单IP数据能压缩到几十万甚至十几万条段记录,内存占用骤降。
- 用户请求时,将目标IP转为整数,用二分查找快速定位所属CIDR段,即可获取区域信息。这种方式内存占用仅几十MB级别,查询速度为O(logN),高效且低成本。
2. 内存数据库选型:用紧凑存储结构替代Redis字符串
如果一定要用内存数据库,避免使用Redis的普通字符串结构:
- Redis Sorted Set:将IP整数作为score,序列化后的区域信息作为member。查询时通过
ZRANGEBYSCORE找到第一个小于等于目标IP的记录,再验证是否在段内。聚合后的段数据量小,内存占用可控。 - LevelDB/RocksDB(内存模式):这类嵌入式存储支持高效范围查询,将IP整数作为键、区域信息作为值,查询时做范围匹配,内存占用远低于Redis,适合大规模数据的内存存储。
3. 本地内存缓存+分层架构
- 把聚合后的CIDR段数据直接加载到API服务进程的本地内存(比如用HashMap或自定义前缀树结构),完全避免网络开销,查询速度最快。
- 针对高频访问的热点IP区域,可单独存入Redis做热点缓存,进一步加速查询,但核心依赖仍是本地内存的段数据。
4. 预计算IP整数优化
在数据库中新增ip_int BIGINT字段,提前将IP转换为32位整数存储并建立索引。后续的聚合、查询操作都基于整数进行,比字符串处理速度更快,还能减少存储和计算开销。
内容的提问来源于stack exchange,提问作者nguyendo
相关产品推荐
相关产品推荐

