成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

怎么樣使用 Redis 來(lái)存儲(chǔ)和查詢 ip 數(shù)據(jù)

ygyooo / 1639人閱讀

摘要:今天我的朋友佛手給我打了個(gè)電話,他們網(wǎng)站的業(yè)務(wù)要根據(jù)客戶的地址快速定位客戶的地理位置。其中是我們要查詢的結(jié)果,當(dāng)然你也可以把和包括進(jìn)去。我這里就用來(lái)特指查詢結(jié)果了。這樣我們的查詢就很簡(jiǎn)單了,只需要用查詢出離最近對(duì)應(yīng)的兩個(gè)即可。

今天我的朋友佛手給我打了個(gè)電話,他們網(wǎng)站的業(yè)務(wù)要根據(jù)客戶的 ip 地址快速定位客戶的地理位置。網(wǎng)上已經(jīng)有一大堆類似的 ip 地址庫(kù)可以用,但問題是這些地址庫(kù)的數(shù)據(jù)表結(jié)構(gòu)大多如下所示

+--------------+------------------+------+-----+---------+----------------+
| Field        | Type             | Null | Key | Default | Extra          |
+--------------+------------------+------+-----+---------+----------------+
| ip_id        | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| ip_country   | varchar(50)      | NO   |     | NULL    |                |
| ip_startip   | bigint(11)       | NO   | MUL | NULL    |                |
| ip_endip     | bigint(11)       | NO   | MUL | NULL    |                |
| country_code | varchar(2)       | NO   |     | NULL    |                |
| zone_id      | int(11)          | NO   |     | 0       |                |
+--------------+------------------+------+-----+---------+----------------+

最核心的部分是三個(gè):ip_startip、ip_endip 以及 ip_id。其中 ip_id 是我們要查詢的結(jié)果,當(dāng)然你也可以把 zone_idip_country 包括進(jìn)去。我這里就用 ip_id 來(lái)特指查詢結(jié)果了。

面對(duì)這個(gè)表,沒什么其它辦法,你的查詢語(yǔ)句只能是

sqlSELECT * FROM who_ip WHERE ip_startip <= {ip} AND ip_endip >= {ip}

其中 {ip} 是你要查詢的 ip 地址,為了方便查詢,在 php 中我們一般要用 ip2long 函數(shù)把它轉(zhuǎn)換為一個(gè)整數(shù)?,F(xiàn)在問題來(lái)了,這個(gè)表有 400 萬(wàn)條數(shù)據(jù),無(wú)論你怎么優(yōu)化它的索引結(jié)構(gòu)(實(shí)際上我覺得這沒啥用),在以上查詢語(yǔ)句中都要耗費(fèi) 2 秒以上的時(shí)間,對(duì)于一個(gè)高頻使用的接口,這顯然是不可忍受的。

REDIS 可以解決這個(gè)問題嗎?

實(shí)際上這也是佛手同學(xué)最關(guān)心的問題,因?yàn)槲覀冎繰edis有強(qiáng)大數(shù)據(jù)結(jié)構(gòu)和超快的速度,那么我們能設(shè)計(jì)出適應(yīng)這種查詢場(chǎng)景的結(jié)構(gòu)嗎?

范圍查詢,我首先想到的就是Redis里面的Sorted Sets結(jié)構(gòu),這也是redis中唯一可以指定范圍(SCORE值)查詢的結(jié)構(gòu)了,所以基本上我們的希望都寄托在它身上了。

最簡(jiǎn)單粗暴的方法就是把ip_startipip_endip都轉(zhuǎn)化為Sorted Sets里的Score,然后把ip_id定義為Member。這樣我們的查詢就很簡(jiǎn)單了,只需要用ZRANGESCORE查詢出離ip最近SCORE對(duì)應(yīng)的兩個(gè)ip_id即可。然后再分析,如果這兩個(gè)ip_id是相同的,那么說明這個(gè)ip在這個(gè)地址段,如果不同的話證明這個(gè)ip地址沒有被任何地址段所定義,是一個(gè)未知的ip。

基本邏輯是沒有問題的,但是最大的問題還是性能上的挑戰(zhàn)。根據(jù)我的經(jīng)驗(yàn),一個(gè)SET里面放10萬(wàn)條數(shù)據(jù)以上就已經(jīng)很慢了,如果放到400萬(wàn)這種量級(jí),我非常懷疑它跟mysql相比還有優(yōu)勢(shì)嗎?

我設(shè)計(jì)的存儲(chǔ)結(jié)構(gòu)

我的解決方案是把這個(gè)地址庫(kù)切分,每一片區(qū)最多保存65536個(gè)地址。也就是說如果一個(gè)ip地址段為188.88.77.22 - 188.90.78.10,那么我們就把它切分為

188.88.77.22 - 188.88.77.255
188.89.0.0 - 188.89.255.255
188.90.0.0 - 189.90.78.10

也就是我們保證每一個(gè)ip地址段都被保存在xxx.xxx.0.0 - xxx.xxx.255.255的一個(gè)區(qū)段中,這個(gè)區(qū)段的理論極限是保存65536個(gè)值,實(shí)際上要遠(yuǎn)小于這個(gè)數(shù)字。而這樣的區(qū)段理論上也有65536個(gè),這都是ip地址的設(shè)計(jì)所限,當(dāng)然實(shí)際上也遠(yuǎn)小于這個(gè)值。

因此這樣的設(shè)計(jì)基本上就能滿足我們的性能需要了。以下是我用php寫的數(shù)據(jù)切分程序

phpconnect(REDIS_HOST, REDIS_PORT);
        $redis->select(REDIS_DB);
    }

    $key = "ip:" . $page;
    $redis->zAdd($key, $offset, $value);
}

$page = 0;
do {
    $offset = $page * MYSQL_PAGESIZE;
    $count = 0;

    $res = mysql_query("SELECT * FROM " . MYSQL_TABLE . " LIMIT " . MYSQL_PAGESIZE . " OFFSET {$offset}");

    while ($ip = mysql_fetch_assoc($res)) {
        $start = $ip[MYSQL_COLUMN_START];
        $end = $ip[MYSQL_COLUMN_END];
        $value = $ip[MYSQL_COLUMN_ID];

        $startOffset = $start % 65536;
        $endOffset = $end % 65536;

        $start -= $startOffset;
        $end -= $endOffset;

        $startPage = $start / 65536;
        $endPage = $end / 65536;

        for ($i = $startPage; $i <= $endPage; $i ++) {
            if ($i == $startPage) {
                add_ip($i, $startOffset, "s:" . $value);

                if ($i != $endPage) {
                    add_ip($i, 65535, "e:" . $value);
                }
            }

            if ($i == $endPage) {
                add_ip($i, $endOffset, "e:" . $value);

                if ($i != $startPage) {
                    add_ip($i, 0, "s:" . $value);
                }
            }

            if ($i != $endPage && $i != $startPage) {
                add_ip($i, 0, "s:" . $value);
                add_ip($i, 65535, "e:" . $value);
            }
        }

        echo ($page * MYSQL_PAGESIZE + $count) . "
";
        $count ++;
    }

    $page ++;
} while ($count = MYSQL_PAGESIZE);

查詢程序也非常簡(jiǎn)單

phpconnect(REDIS_HOST, REDIS_PORT);
$redis->select(REDIS_DB);

$ip = ip2long("173.255.218.70");
$offset = $ip % 65536;
$page = ($ip - $offset) / 65536;


// 取出小于等于它的最接近值
$start = $redis->zRevRangeByScore("ip:" . $page, 0, $offset, array(
    "limit" => array(0, 1)
));

// 取出大于等于它的最接近值
$end = $redis->zRangeByScore("ip:" . $page, $offset, 65535, array(
    "limit" => array(0, 1)
));

if (empty($start) || empty($end)) {
    echo "unknown";
    exit;
}

$start = $start[0];
$end = $end[0];

list ($startOp, $startId) = explode(":", $start);
list ($endOp, $endId) = explode(":", $end);

if ($startId != $endId) {
    echo "unknown";
    exit;
}

echo $startId;

轉(zhuǎn)載自我的博客:http://70.io/develop/use-redis-to-store-ip-data.html

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/20618.html

相關(guān)文章

  • 阿里云服務(wù)器 如何處理網(wǎng)站高并發(fā)流量問題?(含教程)

    摘要:阿里云哪個(gè)節(jié)點(diǎn)服務(wù)器好一下看看負(fù)載均衡它是對(duì)多臺(tái)云服務(wù)器進(jìn)行流量分發(fā)的負(fù)載均衡服務(wù),讓整個(gè)服務(wù)器群來(lái)處理網(wǎng)站的請(qǐng)求。負(fù)載均衡支持億級(jí)連接和千萬(wàn)級(jí)并發(fā),可輕松應(yīng)對(duì)大流量訪問,滿足業(yè)務(wù)需求。原文流量大的網(wǎng)站如何處理高并發(fā)流量問題很多平臺(tái)一旦做大了,平臺(tái)的流量就會(huì)陡增,同時(shí)并發(fā)訪問的流量也會(huì)暴增,原本規(guī)劃的硬件配置就無(wú)法滿足當(dāng)下的流量問題。 那么如何處理好高并發(fā)的流量問題呢? 小編將這些分為2個(gè)方...

    waterc 評(píng)論0 收藏0
  • Redis在項(xiàng)目中一個(gè)類分時(shí)圖應(yīng)用場(chǎng)景設(shè)計(jì)

    摘要:需求項(xiàng)目有一個(gè)保存實(shí)時(shí)抓拍圖片的功能需要統(tǒng)計(jì)攝像頭下每個(gè)時(shí)間點(diǎn)比如一分鐘保存的圖片個(gè)數(shù)并通過線型圖顯示到頁(yè)面上這很類似股票的分時(shí)線圖的功能所以我參考了一些網(wǎng)上的文章采用來(lái)實(shí)現(xiàn)這個(gè)功能先交代一下項(xiàng)目里數(shù)據(jù)的一個(gè)情況攝像頭個(gè)數(shù)在個(gè)左右單個(gè)攝像頭 需求: 項(xiàng)目有一個(gè)保存實(shí)時(shí)抓拍圖片的功能,需要統(tǒng)計(jì)攝像頭下每個(gè)時(shí)間點(diǎn)(比如一分鐘)保存的圖片個(gè)數(shù),并通過線型圖顯示到頁(yè)面上.這很類似股票的分時(shí)K...

    kuangcaibao 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<