• 请不要在回答技术问题时复制粘贴 AI 生成的内容
Loyalsoldier
V2EX  ›  程序员

针对用户 IP,返回随机 URL,并需要存储 URL 到数据库,这个随机 URL 数据可以每天清空一遍,用什么方案性能最好?

  •  
  •   Loyalsoldier · Oct 11, 2017 · 3894 views
    This topic created in 3165 days ago, the information mentioned may be changed or developed.

    RT,例如假设,每天有 50W IP 的访问,用户进入网站,会随机返回一个 302 的响应,然后跳转到一个随机的 URL。用户第二次进来,会查询数据库中是否存在该 IP,存在,则跳转到第一次访问的随机 URL。

    也就是说,要做一个 IP 和 随机 URL 的映射关系表,这个表数据量很大,假设是 50W,这些数据可以在一天后清除的。怎么做才能尽可能实现高性能,不影响网站用户体验?

    目前想到 Redis,但是好像 Redis 每秒只能查询 20W 次?那要遍历 50W 次的话,好像挺久的……

    非科班设计师出身,轻喷……

    Supplement 1  ·  Oct 12, 2017

    我原本以为 Redis 的 Hash 是遍历完成查询的,基础不行啊……

    最终采用的方案是 Redis。就用 Redis 里简单的 HSET 和 HGET 就好了。过期时间的话,设置了一个定时任务每次自动清理数据。

    27 replies    2017-10-12 21:30:03 +08:00
    qiayue
        1
    qiayue  
    PRO
       Oct 11, 2017
    “ Redis 每秒只能查询 20W 次”
    这个结论哪里来的?
    187j3x1
        2
    187j3x1  
       Oct 11, 2017
    hash table 原理嘛? 50 万 50 亿都是差不多速度的,吃内存而已
    Loyalsoldier
        3
    Loyalsoldier  
    OP
       Oct 11, 2017
    @qiayue #1

    http://www.runoob.com/redis/redis-intro.html

    我还说高了…………之前看过一个文档写着,但是一时间找不到了
    yankebupt
        4
    yankebupt  
       Oct 11, 2017
    为什么要遍历?由于 ip 地址特性 int32(ipv4)可以加速不用遍历的。
    一提到这个就想起最近的动态路由屏蔽表...估计规则数也比你那个不少...那个是真的大访问量...我一直在想那个是怎么跑起来的...有可能是特殊硬件吧?...
    我看到第一个回复查询 20W 次,还以为 20W+访问量.....
    yankebupt
        5
    yankebupt  
       Oct 11, 2017
    总有股维和感,我总觉得楼主的意思是不是反过来,是不是想根据 url 记录如果没有随机返回一个 ip 并绑定。
    Loyalsoldier
        6
    Loyalsoldier  
    OP
       Oct 11, 2017
    @yankebupt #5

    不是,就是根据 IP,返回一个随机 URL 并存进数据库。当天的后续访问,就查询数据库,取出该随机 URL,跳转到该 URL
    yankebupt
        7
    yankebupt  
       Oct 11, 2017
    我觉得楼主如果之后回帖:
    我发现一个好方法,把库分成两部分,一部分存国内 ip 和 url,一部分存国外 ip 和 url...根据访问热度和管理要求实现不同查询性能......实现 90%以上的满意度...
    的话
    我会后悔在这个主题回帖的.....

    所以楼主,稍微详细一点说明你的实际使用情况?
    还有为什么就选定 redis 了
    yankebupt
        8
    yankebupt  
       Oct 11, 2017
    不要误解我。我是说大多数情况下技术人员会根据热度,分不同的使用用户,高频用户给一个很小的高速查询库,响应极其迅速,查不到再查之外的逐步扩大。但是涉及你这种情况如果这样做实际上是违背网络公平性的,会加大非高频用户的延迟,加之我 redis 基本没碰过,所以完全不能给出有效建议,请见谅。
    xmcp
        9
    xmcp  
       Oct 11, 2017   ❤️ 1
    二分查找是 O(logN) 级别的,50W 肯定没问题呀。楼主要是挨个遍历强行卡成 O(N) 肯定就 gg 了呀……

    另外不知道你的需求是什么,如果你只需要“清空所有映射”,不需要“删除特定映射”的话,不妨直接弄个 hash 的算法,URL=hash(salt+IP),想要清空的话换个 salt 就行了,查询 O(1),岂不美哉?
    Loyalsoldier
        10
    Loyalsoldier  
    OP
       Oct 11, 2017
    @yankebupt #7

    用户从 a.com (入口域名) 访问网站,后端拿到该用户的 IP 地址(假设是 1.1.1.1),随机从可选的 URL 中返回一个给该用户,假设返回 b.com (目标域名),这时候 1.1.1.1 就对应 b.com 。在当天内,用户 1.1.1.1 再次从 a.com 访问进行访问,为了保证用户在当天内看到同样的页面内容,这时候需要给用户返回跟第一次访问时一样的 URL。查询数据库发现,1.1.1.1 对应 b.com ,这时候给用户 1.1.1.1 返回 b.com

    但是当一天内访问的用户量足够大的时候,查询“目标域名”的操作就会很慢了吧,所以问,用什么技术方案来实现这个需求,用户能最快访问到目标 URL
    Loyalsoldier
        11
    Loyalsoldier  
    OP
       Oct 11, 2017
    @xmcp #9

    用户从 a.com (入口域名) 访问网站,后端拿到该用户的 IP 地址(假设是 1.1.1.1),随机从可选的 URL 中返回一个给该用户,假设返回 b.com (目标域名),这时候 1.1.1.1 就对应 b.com 。在当天内,用户 1.1.1.1 再次从 a.com 访问进行访问,为了保证用户在当天内看到同样的页面内容,这时候需要给用户返回跟第一次访问时一样的 URL。查询数据库发现,1.1.1.1 对应 b.com ,这时候给用户 1.1.1.1 返回 b.com

    但是当一天内访问的用户量足够大的时候,查询“目标域名”的操作就会很慢了吧,所以问,用什么技术方案来实现这个需求,用户能最快访问到目标 URL
    lianyue
        12
    lianyue  
       Oct 11, 2017
    这需要 考虑这么多干嘛 动态网页 基本每次打开都会有查询 正常 以内

    其实普通数据库 什么的
    id, ip date
    就好了 多一个字段超过 24 小时自动过期 根本不需要什么删除

    或者每天一个新表 为什么非要操作 删除旧的数据


    表名比如
    access_2017_10_11
    access_2017_10_12
    access_2017_10_13

    结构
    id, ip


    实现方式很多
    binux
        13
    binux  
       Oct 11, 2017
    随机选一个域名是 O(1) 的,查询一个 ip 对应的域名也是 O(1) 的,不管用户量有多大,就算 13 亿它也是一样的速度。
    syhsyh9696
        14
    syhsyh9696  
       Oct 11, 2017
    为何不是根据当前的时间和 ip 地址生成当天的 temp url ?
    xmcp
        15
    xmcp  
       Oct 11, 2017   ❤️ 1
    @Loyalsoldier 这用什么数据库呀?直接用 IP 地址做种子生成随机数呀。伪(?)代码如下:

    SALT='foo' # 改这个数来重置所有用户访问到的网址
    WEBSITES=['b.com','c.com','d.com']

    def get_url(ip):
    ___ r=random.Random()
    ___ r.seed(SALT+str(ip))
    ___ return r.choice(WEBSITES)

    如果真要上数据库的话 redis 也不是不行,人家 redis 也有 hash 数据结构: http://www.runoob.com/redis/redis-hashes.html,O(logN) 肯定能满足正常网站的速度要求的。
    yankebupt
        16
    yankebupt  
       Oct 11, 2017
    @Loyalsoldier 但是 ip 可以 hash 的...
    不懂 hash 会加速的道理也没关系,这么解释一下,假设你为 0.0.x.x-255.255.x.x 的 ip 建 65536 张表,则每张表最多也就是 65536 个记录(实际每个记录都会很少会更快,因为需要访问一次才有记录)。只查对应的表只需遍历很少的记录....

    不过我愈发觉得楼主可能是在钓鱼...专门钓我们这种不懂 memcached/LRU 的...
    yankebupt
        17
    yankebupt  
       Oct 11, 2017
    @xmcp 也好,但我看到楼主说了每天数据可以清空,可能意味着楼主想在 SALT 里加入当前日期或者有自己的生成算法,咱们继续看看楼主怎么发展吧....
    bydmm
        18
    bydmm  
       Oct 11, 2017   ❤️ 1
    楼主你逗我把,

    ip 到一段字符串的映射关系根本不用遍历整个 redis 空间啊。 他们之间是 hash 映射的关系。

    你用 ip 作为 key,url 作为 value,再多 ip 都是一次好吗。。
    dbw9580
        19
    dbw9580  
       Oct 11, 2017 via Android
    for ip in seen_ips: if ip != remote_ip, continue; else return ip2urltable[ip]

    op 的思考方式
    0ZXYDDu796nVCFxq
        20
    0ZXYDDu796nVCFxq  
       Oct 11, 2017 via iPhone   ❤️ 1
    用 IP 做 key 查询不是 O(n)的,是 O(1)
    50 万数据小得可怜,估计几百 M 内存搞定
    nazor
        21
    nazor  
       Oct 11, 2017
    每秒查询 20W 是指每秒遍历数据 20 次,不是说一秒只能遍历 20W 的一次……
    Finest
        22
    Finest  
       Oct 11, 2017   ❤️ 1
    这种情况 redis 单机就能处理得过来,才 50w
    set ip domain NX EX 24*60*60

    get ip
    基本只要这两个命令就能解决你的问题
    johnnie502
        23
    johnnie502  
       Oct 12, 2017
    这不是一个存放在客户端的 24 小时过期 cookie 吗?除非有特殊的要求必须放在服务器端,不然放在客户端不就完事了
    LeoSocks
        24
    LeoSocks  
       Oct 12, 2017 via iPhone
    那文章写的 11 万次每秒是并发吧!可以支持并发 11 万个用户同时读。而不是 11 万条记录
    blaxmirror
        25
    blaxmirror  
       Oct 12, 2017   ❤️ 2
    直接用 IP+一个每天变化的 seed 做映射不就好了吗?为啥要存储下来呢?
    你应该不需要通过 URL 反向查询 IP 的吧?
    (并不了解技术细节,仅供参考)
    Loyalsoldier
        26
    Loyalsoldier  
    OP
       Oct 12, 2017
    @xmcp #9
    @binux #13
    @yankebupt #16
    @bydmm #18
    @dbw9580 #19
    @gstqc #20
    @hand515 #22
    @blaxmirror #25

    我原本以为 Redis 的 Hash 是遍历完成查询的,基础不行啊……

    最终采用的方案是 Redis。就用 Redis 里简单的 HSET 和 HGET 就好了。过期时间的话,设置了一个定时任务每次自动清理数据。
    Finest
        27
    Finest  
       Oct 12, 2017
    @Loyalsoldier #26 别用 hashtable,直接用 set 和 get 命令,配合 expire 设置自动过期,还剩了定时任务
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1269 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 58ms · UTC 23:44 · PVG 07:44 · LAX 16:44 · JFK 19:44
    ♥ Do have faith in what you're doing.