首页 > 数据库 >redis~有序集合处理ip范围的查询问题

redis~有序集合处理ip范围的查询问题

时间:2024-11-25 14:25:03浏览次数:6  
标签:ip time redis 查询 item IP import

目前有两种方式对 IP 以及归属地信息进行缓存:

  • 第一种是将起始 IP,结束 IP 以及中间所有 IP 转换成整型,然后以字符串方式,用转换后的 IP 作为 key,归属地信息作为 value 存入 Redis;
  • 第二种是采用有序集合和散列方式,首先将起始 IP 和结束 IP 添加到有序集合 ip2cityid,城市 ID 作为成员,转换后的 IP 作为分值,然后再将城市 ID 和归属地信息添加到散列 cityid2city,城市 ID 作为 key,归属地信息作为 value。

第一种方式就不多做介绍了,简单粗暴,非常不推荐。查询速度当然很快,毫秒级别,但缺点也十分明显,我用 1000 条数据做了测试,缓存时间长,大概 20 分钟,占用空间大,将近 1G。

下面介绍第二种方式直接看代码

python语言实现

# generate_to_redis.py
# -*- coding:utf-8 -*-
import time
import json
from redis import Redis
def ip_to_num(x):
    return sum([256 ** j * int(i) for j, i in enumerate(x.split('.')[::-1])])
# 连接 Redis
conn = Redis(host='127.0.0.1', port=6379, db=10)
start_time = time.time()
# 文件格式
# 1.0.0.0|1.0.0.255|澳大利亚|0|0|0|0
# 1.0.1.0|1.0.3.255|中国|0|福建省|福州市|电信
with open('./ip.merge.txt', 'r') as f:
    i = 1
    for line in f.readlines():
        item = line.strip().split('|')
        # 将起始 IP 和结束 IP 添加到有序集合 ip2cityid
        # 成员分别是城市 ID 和 ID + #, 分值是根据 IP 计算的整数值
        conn.zadd('ip2cityid', str(i), ip_to_num(item[0]), str(i) + '#', ip_to_num(item[1]) + 1)
        # 将城市信息添加到散列 cityid2city,key 是城市 ID,值是城市信息的 json 序列
        conn.hset('cityid2city', str(i), json.dumps([item[2], item[3], item[4], item[5]]))
        i += 1
end_time = time.time()
print 'start_time: ' + str(start_time) + ', end_time: ' + str(end_time) + ', cost time: ' + str(end_time - start_time)

java语言实现

以下是通过 Java 来实现将 IP 起始值和结束值通过有序集合存储,并根据传入的 IP 返回这个 IP 是否在 IP 范围集合中存在的示例代码:

  • redis中存储的图
  • java代码如下
package com.lind.redis;

import com.lind.redis.config.LettuceRedisAutoConfigure;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 关于ip地址范围检索的测试
 *
 * @author lind
 * @date 2024/3/6 11:14
 * @since 1.0.0
 */
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { LettuceConnectionFactory.class, LettuceRedisAutoConfigure.class })
public class IpRangeTest {

    private static final String IP_RANGE_KEY = "ip_ranges";

    @Autowired
    RedisTemplate redisTemplate;

    // 将 IP 地址转换为 long 类型的分数值
    public static double convertIPToScore(String ip) {
       String[] ipParts = ip.split("\\.");
       if (ipParts.length != 4) {
          throw new IllegalArgumentException("Invalid IP address format");
       }

       long score = 0;
       for (int i = 0; i < 4; i++) {
          long partValue = Long.parseLong(ipParts[i]);
          score = (score << 8) + partValue; // 将每个部分的值左移8位并相加
       }

       return score;
    }

    @Test
    public void testRangeIp() {
       // 存储 IP 范围到 Redis
       storeIPRangeToRedis("103.159.125.66", "103.159.125.177");
       storeIPRangeToRedis("114.250.19.130", "114.250.19.255");

       // 检查用户真实 IP 是否在 IP 集合中
       String userIP = "103.159.125.178";
       boolean inRange = checkIPInRange(userIP);
       if (inRange) {
          System.out.println(userIP + " is in the IP range set.");
       }
       else {
          System.out.println(userIP + " is not in the IP range set.");
       }
    }

    public void storeIPRangeToRedis(String startIP, String endIP) {
       redisTemplate.opsForZSet().add(IP_RANGE_KEY, startIP, convertIPToScore(startIP));
       redisTemplate.opsForZSet().add(IP_RANGE_KEY, endIP, convertIPToScore(endIP));
    }

    public boolean checkIPInRange(String userIP) {
       Long count = redisTemplate.opsForZSet().count(IP_RANGE_KEY, convertIPToScore(userIP), convertIPToScore(userIP));
       return count > 0;
    }

}

标签:ip,time,redis,查询,item,IP,import
From: https://www.cnblogs.com/lori/p/18567439

相关文章

  • Vue3+Typescript+Axios+.NetCore实现导出Excel文件功能
    前端代码//导出ExcelconstexportMaintenanceOrderSettlementItemExcelClick=async()=>{leturl=`${VITE_APP_API_URL}/api/app/maintenance/settlement-service-item/${currentMaintenanceOrderId.value}/${currentMaintenanceOrderSettlementRow.value.id}`;......
  • Ubuntu 桥接模式下 固定IP地址
    相关背景Ubuntu20.04.2桥接模式下安装系统,会自动配置IP,减少了繁琐的配置;但有时候这个自动分配的ip地址会发生变化,导致相关程序的安装无法正常进行。 解决方案注:不同版本的操作方式尽不相同,本次操作演示为Ubuntu20.04.2 修改配置文件//文件名可能需要根据实际情况进......
  • [赛记] 【MX-S7】梦熊 NOIP 2024 模拟赛 3 && 2025炼石计划NOIP 模拟赛 #20
    HappyCard70pts大样例乱搞都能过。。。可以将“炸”看成“三带一”,那么我们最优是先出“三带一”;首先分别算出原序列中每个数包含$3$的个数$cnt$,以及模$3$余$1,2$的个数$s1,s2$,然后进行判断,如果$cnt\geqs1+2s2$,那么我们可以看做将原序列所有数......
  • wevtutil 是一个命令行工具,主要用于管理和操作 Windows 事件日志。它是 Windows 操作
    wevtutil|MicrosoftLearn wevtutil是一个命令行工具,主要用于管理和操作Windows事件日志。它是Windows操作系统内置的一个工具,可以通过命令行来查询、导出、清除、存档事件日志等。wevtutil可以帮助系统管理员和开发者对事件日志进行更高效的管理和诊断。wevtutil 的......
  • TypeScript很麻烦,不想使用! 转载
    原文链接:https://juejin.cn/post/7344282440725577765本文已经授权【稀土掘金技术社区】官方公众号独家原创发布。前言最近,我们部门在开发一个组件库时,我注意到一些团队成员对使用TypeScript表示出了抵触情绪,他们常常抱怨说:“TypeScript太麻烦了,我们不想用!”起初,我对此感到困......
  • JavaScript有几种类型值?能否画出它们的内存图?
    JavaScript有七种原始数据类型和一种引用类型:原始数据类型(PrimitiveDataTypes):存储在栈(Stack)内存中,值直接存储在变量访问的位置。Boolean:true或falseNull:只有一个值null,表示空或不存在的值。Undefined:变量声明了但未赋值时的默认值undefined。Number:所......
  • 解决国外代理IP频繁掉线的技巧
    在互联网和经济全球化迅猛发展的今天,国外IP代理服务已成为国内用户关注的焦点。然而,许多用户在使用国外代理IP时常常遭遇到频繁掉线的问题。在本文中,我们将分享一些解决这一问题的方法,确保您能够更加顺畅地使用国外代理IP服务。解决方法一:检查网络连接要确保国外代理IP服务......
  • node + Redis + svg-captcha 实现验证码
    目录前提说明Redis链接与封装svg-captcha使用步骤封装中间件验证前端接收扩展【svgAPI】svgCaptcha.create(options)svgCaptcha.createMathExpr(options)svgCaptcha.loadFont(url)svgCaptcha.optionssvgCaptcha.randomText([size|options])svgCaptcha(text,opti......
  • 自建动态IP代理为何无法使用及解决方法
    在网络使用中,有时候我们会尝试自建动态IP来实现一些特定的需求,例如访问受限内容或保护隐私。然而,有时我们会遇到无法使用的情况。本文将探讨无法使用的可能原因,并提供相应的解决方法。1. 可能原因a.网络配置问题自建动态IP通常需要正确的网络配置才能运行。如果网络配置......
  • 【分享】这篇教程助力你成为 JavaScript 糕手!(十一)
    第十一章:异步编程11.1异步编程的概念在JavaScript中,异步编程是一种非常重要的编程模式,它用于处理那些不会立即完成的操作,而是在一段时间后才会返回结果的任务。传统的同步编程模式下,代码是按照从上到下的顺序依次执行的,每一行代码都必须等待前一行代码执行完毕后才会......