IP地址定位区间的问题分析(r13笔记第9天)

   以前写过一篇Oracle中关于IP地址定位的问题分析,最后引申出了一系列的问题。当时问题紧急严峻,抓取了10053事件定位源头,想出了一个解决妙法,还自鸣得意了下,结果忙活完之后看看行业里的解决方案都大体如此,我的心凉了半截。

   我总是希望找到一些与众不同的点来解读这一类问题,结果在偶然的一天从MySQL这里找到了一些思路。

    我先来分析下之前问题和一些收获。

    需求是输入一个IP,能够根据IP从一个数据字典表里查询IP区段,返回IP对应的区域,这就是一个看起来很简单的IP地址定位的问题。

   从系统负载方面,CPU的负载较高,而其中很大的一方面代价就是IP地址和数字(IP地址转换为数字)之间的转换和映射。

  
Buffer
Gets指标极高,这个部分其实和整个语句的查取效果有关,如果没有找到匹配的数据,就会扫描更多的块。这个部分一个立竿见影的效果就是使用rownum的方式来截断,在这个基础上,和Oracle的朋友聊,其实也有一些改进措施的,这个部分对于极限优化来说可以参考,所以暂且放一放。

  从索引的角度来考虑,Range Scan的方式总是会有优点和缺点,不可能把它同时结合起来达到一个最优的效果,换做那一个数据库都是如此,只能说有些回表的数据处理Oracle隐式(比如使用rowid))做好了,而MySQL里面可能需要单独处理。

   问题就交代到这里,我今天想再次讨论这个问题是想从几个基础的问题开始来聊聊MySQL在这方面的优势,没错,是相比于Oracle的优势的地方。

    首先我们来说说表结构的设计,如果在Oracle里面,当时设计的地址信息如下:

COLUMN_ID COLUMN_NAME                    DATA_TYPE       DATA_LENGTH NULLABLE  
---------- ------------------------------ --------------- ----------- ----------
         1 IP_ID                          NUMBER(10,0)             22 N
         2 IP_LEFT_LINE                   VARCHAR2(15)             15 N
         3 IP_RIGHT_LINE                  VARCHAR2(15)             15 N
         4 IP2NUM_LEFT_LINE               NUMBER(10,0)             22 N
         5 IP2NUM_RIGHT_LINE              NUMBER(10,0)             22 N
         6 COUNTRY                        VARCHAR2(20)             20 Y
         7 PROVINCE                       VARCHAR2(20)             20 Y
         8 CAPITAL                        VARCHAR2(20)             20 Y

  里面对IP地址和IP地址转换后的数字都做了持久化,查询的逻辑相对就比较别扭了。

比如下面:B1是传入的IP地址,即一个字符串,会先转换为数字,然后做Range Scan。

SELECT IP_ID,COUNTRY,PROVINCE,CAPITAL
FROM SWD_IP2COUNTY
WHERE STRIPTOINT(:B1 ) BETWEEN IP2NUM_LEFT_LINE AND IP2NUM_RIGHT_LINE

如果换做MySQL,有哪些点需要考虑呢。

第一个考虑点还是数据类型,IP地址是一个字符串,我们是考虑使用varchar类型还是char呢。

  假设一个IP地址为10.127.133.199,字符串的长度就是14位,最高设置为3*4+3=15位,这是第一点。

  而如果我们存储了一个IP,则意味着这个工作还没有完成,我们还需要转换,所以还不如直接转换为数值,所以综合起来,其实我们实现这个需求,从简化的角度来看,其实不需要一个字符型,而是需要一个数值型即可。

  
那么问题来了,数值型数据类型其实是很丰富的,这一点和Oracle大大不同,Oracle里面很多开发,DBA都懒了,或者说Oracle内部已经做好了这种适配,数值精度也不需要更多考虑了,长度也不需要区别对待了,直接一个number类型,想调精度,就直接在这个基础上改,比如number(10,3),可以定义长度和精度。MySQL在这方面就分得比较轻,有支持0-128以内的tiny
int,32767的smallint等,每一个数据类型都抠的很细。

   所以在Oracle里面的豪气在这里就是粗放了,一定需要认真区别对待。

   因为我们打算使用数值类型,最后我们选择了int(11),没有留出很富余的值是因为我们从设计的角度来考虑尽可能按需分配。

> create table ip_range(ip int(11) );
Query OK, 0 rows affected (0.01 sec)

我们插入两行值:

> insert into ip_range values(inet_aton('127.0.0.1')),(inet_aton('192.168.1.1'));
ERROR 1264 (22003): Out of range value for column 'ip' at row 2结果发现竟然溢出了,SQL_Mode是严格模式。

好吧,看来我们太过于乐观了。逐个击破。

> insert into ip_range values(inet_aton('127.0.0.1'));               

Query OK, 1 row affected (0.00 sec)

原来是这里的问题:

> insert into ip_range values(inet_aton('192.168.1.1'));
ERROR 1264 (22003): Out of range value for column 'ip' at row 1

这是因为int的数值类型其实分为有符号和无符号两种,区间分别是2147483647和4294967295,所以IP地址的需求我们只需要考虑无符号的情况,修改字段类型。

> alter table ip_range modify ip int(11) unsigned;
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0然后再次插入就没有问题了。

> insert into ip_range values(inet_aton('192.168.1.1'));
Query OK, 1 row affected (0.00 sec)这里需要提一下,就是对于IP地址的转换,MySQL已经提供了这个转换的方法,可以互相转换。分别是inet_ntoa(数值转为IP),inete_aton(IP转为数值)

> select (inet_ntoa(ip)) from ip_range;
+-----------------+
| (inet_ntoa(ip)) |
+-----------------+
| 127.0.0.1       |
| 192.168.1.1     |
+-----------------+
2 rows in set (0.00 sec) 有了这些铺垫,结合索引信息,实现这个需求问题 不大。

时间: 2024-10-22 10:35:10

IP地址定位区间的问题分析(r13笔记第9天)的相关文章

ThinkPHP 3.1快速入门:IP地址定位

在WEB应用中,根据IP地址定位和记录相关访问日志也是非常常见的需求,在ThinkPHP中你可以轻松的实现IP地址获取和定位. 获取扩展类库 可以在官网的http://www.thinkphp.cn/extend/223.html下载IP定位扩展类库,或者下载扩展包(http://www.thinkphp.cn/down/253.html)里面也已经包含该扩展类了.如果是单独下载的上传类库,把解压后的IpLocation.class.php 放入ThinkPHP/Extend/Library/O

php读取qqwry.dat ip地址定位文件的类实例代码

实例如下: <?php // +---------------------------------------------------------------------- // | // +---------------------------------------------------------------------- // | // +---------------------------------------------------------------------- cla

IP地址定位的原理问题

问题描述 通过输入某个域名或者是IP地址,就可以将这个地址具体定位在某个国家或城市,例如输入"www.xiaonei.com"可以定位到在天津市,我想知道这个是如何做到这样的具体定位的,即其中的原理是什么? 解决方案 解决方案二:有ip地址对应城市表啊,直接读的解决方案三:IP地址库下载:能定位到某某网吧

PHP获取客户端真实IP地址的5种情况分析和实现代码_php实例

在PHP获取客户端IP中常使用 $_SERVER["REMOTE_ADDR"] . (1) 但如果客户端是使用代理服务器来访问,那取到的是代理服务器的 IP 地址,而不是真正的客户端 IP 地址.要想透过代理服务器取得客户端的真实 IP 地址,就要使用 $_SERVER["HTTP_X_FORWARDED_FOR"] 来读取. (2) 但只有客户端使用"透明代理"的情况下,$_SERVER["HTTP_X_FORWARDED_FOR&q

分析DDNS的工作原理及检测IP地址变化的实现

本文通过分析 DDNS 的工作原理,简单演示了其在 Linux 网络协议栈的内核空间及用户空间创建 netlink 套接字.进行数据交换.并最终通过 nsupate 工具将更新消息发送给 DNS 服务器的过程. DDNS 的实现最根本的一点是当主机的 IP 地址发生变化的时候,实现 DNS 映射信息的及时更新,应用程序需要及时地获得这一信息,主要的方法可分为两大类: 一类是轮询机制,即:应用程序每隔一定的时间,去从查询主机当前的 IP 地址,并与之前的进行比较,从而判断网络地址是否发生了变化.显

[原创]分析解决lvs fullnat模式下后端服务器获取真实IP地址异常问题

摘要 分析解决lvs fullnat模式下少量的请求记录client IP不是用户真实的IP地址问题. 原创文章:来自分析lvs fullnat模式下后端服务器获取真实IP地址异常问题 问题背景 lvs fullnat模式下观察后端服务器realserver http/https业务运行系统日志,有时候可以发现有少量的请求记录的client IP不是用户真实的IP地址(存在但出现的概率很小,增加了问题排查的难度),而是属于lvs主机私有的IP地址.关于fullnat的简介可以参考http://w

使用MaxMind 根据IP地址对访问者定位

有时你需要知道你的站点访问者来自哪个国家--比如如果你正打算执行针对地理区域的广告计划.本文将对此方法进行介绍.    有时你需要知道你的站点访问者来自哪个国家--比如如果你正打算执行针对地理区域的广告计划.这正是象MaxMind's GeoIP一类的工具大显身手的地方--它可以让你从访问者的IP地址轻松获取其确切的地理位置信息.     MaxMind提供了商业数据库和免费数据库.前者更为精确,精度可以达使用者所在城市信息一级,而后者则只能确定国家和地区.在本文中,我们将演示免费版的使用方法.

无线网络IP地址冲突的分析

无线网络IP地址冲突是我们最为常见的网络故障之一,经常禁用然后启用.那么有时候这个方法就不管用了,那么如何解决呢?当无线接入点作为DHCP服务器工作时,它们可能会引起两个主要问题. 第一是增加IP地址冲突的可能性.市场上的大多数无线接入点是通过默认配置来分配客户端无线网络IP 地址,其范围是192.168.0.x.这是一个问题,因为在一个网段中包含多个无线接入点是相当普遍的情况.如果这些接入点每个都分配了相同的DHCP 作用域,那么无线网络IP冲突将在所难免.请记住,这些地址分配可能不仅局限于无

使用MaxMind 根据IP地址对访问者定位_php基础

    有时你需要知道你的站点访问者来自哪个国家--比如如果你正打算执行针对地理区域的广告计划.本文将对此方法进行介绍.     有时你需要知道你的站点访问者来自哪个国家--比如如果你正打算执行针对地理区域的广告计划.这正是象MaxMind's GeoIP一类的工具大显身手的地方--它可以让你从访问者的IP地址轻松获取其确切的地理位置信息.     MaxMind提供了商业数据库和免费数据库.前者更为精确,精度可以达使用者所在城市信息一级,而后者则只能确定国家和地区.在本文中,我们将演示免费版的