V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
xshwy
V2EX  ›  Python

如何存储、获取随机 100 个页面的状态呢?

  •  
  •   xshwy · 2018-03-23 12:12:22 +08:00 · 3113 次点击
    这是一个创建于 2431 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求:获取排名前 100 个 url 的 HTTP 状态码存储,前台要显示排名前 100 个 url 非 200 状态码的页面有哪些。

    目前想法:

    1. 获取排名前 100 的 url
    2. 轮询 100 个 url 状态码
    3. 删除之前的数据库数据
    4. 保存获取到的状态码

    目前数据库设计:

    数据库

    遇到的难题:

    1. 在第 3 步删除之前数据的时候,需要一定的时间,前台用户查询的时候会显示没有数据,体验不好。
    2. 因为是获取排名前 100 的 url,所以每次查询的 url 可能不一样,无法在之前的数据上更新

    请教: 有没有更优雅的存储方式? 后续可能会扩展到 1000 个、10000 个 url,遇到类似情况该如何解决呢?

    先提前感谢各位大佬的回复了,感谢!

    24 条回复    2018-03-29 02:50:54 +08:00
    twistoy
        1
    twistoy  
       2018-03-23 12:25:41 +08:00
    写进去的时候,加个时间戳,每次页面展示的时候,都请求最近的时间戳的。
    pathbox
        2
    pathbox  
       2018-03-23 12:35:51 +08:00 via iPhone
    @twistoy 直接 id 排序是否可行
    xshwy
        3
    xshwy  
    OP
       2018-03-23 12:38:37 +08:00
    #1 @twistoy 感谢提供解决方案,目前是可以解决这个问题,定期删除之前旧的记录就可以。

    数据库这样设计:



    #2 @pathbox id 排序是指什么样呢?求更详细


    还会有更优雅的解决方案嘛?
    wplct
        4
    wplct  
       2018-03-23 12:46:17 +08:00
    为啥要删除啊。覆盖啊
    xshwy
        5
    xshwy  
    OP
       2018-03-23 12:49:14 +08:00
    #4 @wplct 因为是获取排名前 100 的 url,所以每次查询的 url 可能不一样,无法在之前的数据上更新

    比如我上次获取的前 100 个 url 是 a1 ~ a100,最后一次获取的是 a1~a50、b1~b50,前台只要显示最后一次获取的数据,如果要覆盖的话,还需要检查更新 a51~a100 的数据……
    honeycomb
        6
    honeycomb  
       2018-03-23 12:56:02 +08:00 via Android
    用 loading cache ?设定好阈值后,读写过程中会自动 evict 旧数据
    stabc
        7
    stabc  
       2018-03-23 13:04:52 +08:00
    直接把非 200 的都用数组放到 Redis 里。
    SlipStupig
        8
    SlipStupig  
       2018-03-23 13:27:00 +08:00
    加上一个时间戳就可以解决
    1.要是检测非 200 的
    select url from your_table where status_code != 200 order by last_modified DESC limit 0, 100

    2. 用你的程序获取状态码

    3.直接 update 时间戳和状态码就完事了,根本不需要去删除老的数据
    734506700qq
        9
    734506700qq  
       2018-03-23 13:39:24 +08:00
    可以先将 100 条数据插入库中,然后设置初始状态,等待查询更新,添加更新时间戳字段,等待回写状态;若用户来查时,发现是初始状态,则直接逻辑中去查询一次这个 url,查询其状态,并将状态写入到数据库;
    GoLand
        10
    GoLand  
       2018-03-23 13:47:58 +08:00
    主键自增 ID,直接存进去取的时候直接 select * from xxx order by id desc limit 100 不就行了?时间戳都不要。
    porrat
        11
    porrat  
       2018-03-23 13:48:26 +08:00
    redis
    xshwy
        12
    xshwy  
    OP
       2018-03-23 14:37:03 +08:00
    #6 @honeycomb 感谢提供解决方案,我搜一下 python 相关的操作方式

    #7 @stabc 感谢提供方案,因为只需要展示最后获取的 100 个 url 的 200 状态,如果方式 redis 的话也还是要清空之前的记录,清空期间担心用户访问的时候会显示数据为空。

    #8 #9 #10 @SlipStupig @734506700qq @GoLand 感谢提供方案,需要获取最后一次获取到 100 个 url 的 200 状态,所以不能用 limit 0,100,因为可能最后查询到的 100 个 url 只有 20 个 url 是 200 状态,总数也不止 100 个,每次获取到的都是随机 100 个,所以 update 感觉也不太可行…


    #11 @porrat 感谢提供思路,请问有更详细的解决方案嘛?
    SlipStupig
        13
    SlipStupig  
       2018-03-23 15:27:59 +08:00
    @xshwy 用时间排序有什么不行的
    honeycomb
        14
    honeycomb  
       2018-03-23 17:01:28 +08:00 via Android
    @xshwy Java 里有 guava cache (以及很多同类工具)正好可以限制 cache 的大小的同时,又能监听 cache evict 事件(用来回调把抛弃的数据持久化到数据库),Python 肯定有类似的轮子。
    honeycomb
        15
    honeycomb  
       2018-03-23 17:04:59 +08:00 via Android
    @xshwy 随手搜了一下,有一个叫 beaker 的模块,应该能满足需要
    chairuosen
        16
    chairuosen  
       2018-03-23 17:18:59 +08:00
    关键信息没说:
    是否要求某次排名更新后,所有 url 的 status 都查询一遍,前端才刷?
    xshwy
        17
    xshwy  
    OP
       2018-03-23 17:24:23 +08:00
    #15 @honeycomb 感谢提供解决方案,我去搜搜相关模块的文档

    #16 @chairuosen 每 5 分钟获取一次排前面 100 的 url,然后获取这 100 个 url 的状态,存储,前端由用户手动刷新即可
    chairuosen
        18
    chairuosen  
       2018-03-23 17:32:30 +08:00
    @xshwy 你还是没回答啊。排名出来了,状态查了 50 个,50 个没查呢,现在前端要数据,给什么?
    kennylam777
        19
    kennylam777  
       2018-03-23 17:33:53 +08:00
    redis 的 ZADD/ZRANK 似乎可以解決這種問題, 才 100 個 url 這種小型 dataset 應該是適合的
    xshwy
        20
    xshwy  
    OP
       2018-03-23 17:45:53 +08:00
    #18 @chairuosen 所有 url 状态查完统一存储发出,设置的 5 分钟轮询就是想着 5 分钟应该足够 100 个 url 的状态查询了;没有查询完毕之前,继续返回上次的查询结果

    #19 @kennylam777 好的 我查一下资料,非常感谢,不过后续可能会适配到 1000、10000 …
    kennylam777
        21
    kennylam777  
       2018-03-23 17:52:29 +08:00
    @xshwy 放心吧, 1000 及 10000 還是很小

    我有一個類似的, 3500 多 URL 佔用 10MB 不到 RAM
    rrfeng
        22
    rrfeng  
       2018-03-23 17:53:36 +08:00 via Android
    es kibana 啥代码也不要写
    xshwy
        23
    xshwy  
    OP
       2018-03-24 01:01:00 +08:00
    #22 @rrfeng 我搜索一下相关技术,感谢提供解决方案

    #21 @kennylam777 哇 非常感谢,发现 ZADD/ZRANK 太好用了,可以实现我大部分的需求,可以自动更新已存在的数据,还可以直接排序好实用,也可以直接分页查询太好了!

    不过有一点问题就是无法设置过期时间,查了一圈也没找到相关的解决方案,继续求教一下

    第一次轮训查到三个状态码为非 200 的,按照排名顺序插入,排名也是必须的,所以 score 无法设置时间戳…
    > ZADD urls 1 xxx.com/001
    > ZADD urls 3 xxx.com/002
    > ZADD urls 25 xxx.com/003

    前台可以展示出排名第几的 url 是非 200 状态,第二次轮训的时候只查到 1 个状态码为非 200 状态
    > ZADD urls 23 xxx.com/001

    问题来了,如何清空之前存储的 002、003 两个数据呢?或者如何设置自动清理超过 10 分钟没更新的数据呢?
    baojiwei
        24
    baojiwei  
       2018-03-29 02:50:54 +08:00
    redis 的 zrank 就可以了
    多使用缓存,这类问题不需要使用数据库
    如果需要的话也是异步的,非高频操作
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2650 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 05:29 · PVG 13:29 · LAX 21:29 · JFK 00:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.