本文共 2426 字,大约阅读时间需要 8 分钟。
将本文以行表形式存储于关系型数据库中的IP信息库,通过转换,存储到key-value型的Redis库中,以加快查询的速度。本文通过使用Redis的散列类型和有序集合类型来实现这种需求。
在工程中常有这样的需求,即给定IP(本文一律考虑将点分十进制的ip转为无符号整型),从(全球)IP库中查找相关信息。若将IP库存储于关系型数据库中(本文仅截取部分字段用于阐明),其形式大概如下:
TAGID | FROMIP | TOIP | INFO1 | INFO2 |
---|---|---|---|---|
TAG01 | 1779830784 | 1779831039 | 湖南省 | 电信 |
TAG02 | 987332096 | 987332351 | 江苏省镇江市 | 电信 |
TAG03 | 2026831104 | 2026831359 | 江西省南昌市 | 移动 |
TAG04 | 2059661056 | 2059661311 | 江苏省淮安市 | 联通 |
TAG05 | 832214272 | 832214527 | 江苏省南京市 | 广电网 |
假设要查询给定IP的INFO1和INFO2信息,SQL语句如下:
SELECT INFO1,INFO2 WHERE IP >= FROMIP AND IP <= TOIP;
这样的语句查询关系型是数据库是比较耗时的。下面设法将上述数据存储到Redis中,主要借助Redis的散列类型和有序集合类型。
建表过程:
1. 将表中的每一个行以TAGID作为key,其余值作为value,以散列类型作为value的数据结构进行存储; 2. 将FROMIP和TAGID的映射关系(以FROMIP作为score),以有序集合的形式进行存储,这样所有的FROMIP将从小到大的顺序存储在Redis中;查询过程(以java客户端jedis为例):
1. 将ip转换为无符号整型 2. 从redis有序集合类型中查找全球库中小于该ip的最大fromip,即确定该IP所在的起始区间;jedis.zrevrangeByScore(key, max, min, offset, count);key:有序集合类型的key值,目前为"fromipscore"max:待查询的无符号整型IPmin:置为-1offset:置为0,返回结果集的起始偏移量count:置为1,只返回符合条件的第一条
如果查找不到,则直接返回,即该IP在库中查找不到;否则进行步骤3操作
3. 将步骤2返回的结果,作为新的key,查找redis散列类型的数据结构,并进行比较以确定该IP是否在上一步确定的区间内Mapval = jedis.hgetAll(key);val中包含的示例如下:{INFO2=联通, INFO1=江苏省南京市, TOIP=1910858495, FROMIP=1910858240}从val中取出toip的值,转换为整型,并与待查找的ip进行比较;如果待查询ip <= toip;则 val即为查询的结果集;否则查找不到
由于有序集合使用散列表和跳跃表实现,因此确定IP所在的起始区间时间复杂度不超过O(lgn);其次查找散列表的时间复杂度,在不发生冲突时是常数。下面在shell端,对上面过程进行演示,加深理解。
127.0.0.1:6379> hmset TAG01 FROMIP 1779830784 TOIP 1779831039 INFO1 湖南省 INFO2 电信OK127.0.0.1:6379> hmset TAG02 FROMIP 987332096 TOIP 987332351 INFO1 江苏省镇江市 INFO2 电信OK127.0.0.1:6379> hmset TAG03 FROMIP 2026831104 TOIP 2026831359 INFO1 江西省南昌市 INFO2 移动OK127.0.0.1:6379> hmset TAG04 FROMIP 2059661056 TOIP 2059661311 INFO1 江苏省淮安市 INFO2 联通OK127.0.0.1:6379> hmset TAG05 FROMIP 832214272 TOIP 832214527 INFO1 江苏省南京市 INFO2 广电网OK
127.0.0.1:6379> zadd fromip:score 1779830784 TAG01(integer) 1127.0.0.1:6379> zadd fromip:score 987332096 TAG02(integer) 1127.0.0.1:6379> zadd fromip:score 2026831104 TAG03(integer) 1127.0.0.1:6379> zadd fromip:score 2059661056 TAG04(integer) 1127.0.0.1:6379> zadd fromip:score 832214272 TAG05(integer) 1
IP为1779830785,该IP的tagid为TAG01127.0.0.1:6379> zrevrangebyscore fromip:score 1779830785 -1 limit 0 11) "TAG01"127.0.0.1:6379> hgetall TAG011) "FROMIP"2) "1779830784"3) "TOIP"4) "1779831039"5) "INFO1"6) "\xe6\xb9\x96\xe5\x8d\x97\xe7\x9c\x81"7) "INFO2"8) "\xe7\x94\xb5\xe4\xbf\xa1"127.0.0.1:6379> 比较1779830785和结果集中的TOIP即可判断
转载地址:http://ykbmb.baihongyu.com/