V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
GeekHub
Visitor233
V2EX  ›  程序员

白嫖方案:微信 Access_token 时效 2 小时的管理问题

  •  
  •   Visitor233 · 46 天前 · 3348 次点击
    这是一个创建于 46 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目:net core3.1, PostgreSQL12

    注:目前没有考虑队列和 redis,定时任务这个没办法再说吧

    如题,现在是把获取到的 token,直接存在 psql 库一个单独放各种 token 的表里。有 appid 、token 类型、过期时间(当前时间+2 小时-xx 分钟)、是否更新这四个关键字段。

    目前我分了五种情况,代码不方便发,我文字描述吧。

    前提:通过参数查到对应的 token 信息,没有就第一种情况处理,有则判断后面四种 一:库没有,申请到新的直接插表 二:库有,且请求在有效期内,直接返回 token 三:库有,但已经到了 xx 分钟时间段内且是否更新字段为 false,需要更新 token 。于是先将字段改为 true,直接 context.savechanges 。然后再申请新的 token,局部更新旧 token,并将字段改为 fasle,再 save,返回新 token 四:库有,也到了 xx 分钟,但是否更新为 true 。直接返回 token (注意:我想这里可能会有脏读,但没关系,微信说了,token 更新期间,旧 token 仍有 5 分钟有效期) 五:库有,但有效期已经过了 xx 分钟,需要更新,考虑到瞬时大量请求刚好赶上,我直接 lock 申请的函数,再更新 token 。

    目前就这样,单一请求各个阶段都试了,没问题,但没做压测(我不会,下了 jmeter 没用过) 现在回想起来,我入行一年半还不会多线程很 low 啊,这种单一资源竞争还得写 5 个 if else,罪过罪过。 还请各位大佬在评论区指点一番,先在次谢谢各位。鞠躬.jpg

    34 条回复    2020-08-07 17:02:41 +08:00
    encro
        1
    encro   46 天前
    $token = $cache->get($app_token_key);
    if(!$token){
    $token = $app->getToken();
    $cache->set(app_token_key,$token,$expire-5*60);
    }
    return $token;
    soulzz
        2
    soulzz   46 天前
    这个用 java 来写就很方便,引入 guava
    设定 key 两小时失效
    没有 token 直接 callable 里调用申请新的
    teawithlife
        3
    teawithlife   46 天前
    不知道微信对获取 token 的频率有没有什么限制,如果没有限制的话,单独开个进程,每隔 90 分钟刷一次 token,需要用到的时候直接用就行了
    pagepancn
        4
    pagepancn   46 天前
    @teawithlife 获取 token 每个月是有次数上限的,不能这么干
    useben
        5
    useben   46 天前
    考虑到瞬时大量请求刚好赶上. token 不放缓存, 单纯 mysql 扛不住...
    直接 token 存 redis, 过期时间设为将近 2 小时, 过期再去请求一个就行了. 期间所有应用共用. 均摊下来时间复杂度还是 O(1)
    iyangyuan
        6
    iyangyuan   46 天前
    根本就不需要入库,用 Java 的话,放内存,加一个读写锁就搞定了。如果是微服务项目,单独做一个接口
    kanezeng
        7
    kanezeng   46 天前
    @pagepancn 单独一个进程 90 分钟刷一次不会碰到频率上限的(每天 2000 次),只不过存在一点小风险,就是当业务进程取到老 token 还没使用时,刷新线程刷新了 token 导致老 token 失效,这时候业务进程使用老 token 会失败。不过按微信的说法,新老 token 能同时有效 5 分钟,所以应该也没问题
    dhssingle
        8
    dhssingle   46 天前
    简单问题复杂化,单体应用的话 MemoryCache 足够用了,甚至静态变量也不是不可以。
    lovesky
        9
    lovesky   46 天前
    @pagepancn 获取 access_token,每日限额 2000 次,90 分钟刷一次完全没问题。
    huobazi
        10
    huobazi   46 天前
    这个? 没看懂做什么用的啊? 或者, 为什么做这个呢?
    sunmoon1983
        11
    sunmoon1983   46 天前
    redis 不行吗?
    quan01994
        12
    quan01994   46 天前
    MemoryCache
    unnamedhao
        13
    unnamedhao   46 天前
    其实为了保险还需要做一个检测,
    比如不小心在其他地方(例如测试环境)申请了 token,会导致当前 token 失效。
    所以需要在当前环境使用 token 调用接口时检测返回的错误码,
    如果错误码是 token 错误,
    则需要设置标志重新获取 token
    tcfenix
        14
    tcfenix   46 天前   ❤️ 2
    不是很明白为什么把这么简单的事情搞得这么复杂,
    拿到了 access token 直接放 redis,设置 2 小时超时

    每次请求过来去 redis 找, 如果有的话,对比一下就过了,没有的话就说明过了两小时,重新去微信找咯

    追求性能的话弄个一分钟之类的内存缓存不就好了....
    你弄个数据库什么一堆架构真是何苦?
    h82258652
        15
    h82258652   46 天前
    不需要多线程。直接用 asynclock ( nito.asyncex 这个包)。反正把请求微信开始到写入存储包起来就行了。(内存存储、磁盘存储、数据库存储都行)
    减 xx 分钟也不需要,一般这种会有 slide time 。
    xcstream
        16
    xcstream   46 天前
    定时请求 入库 结束了
    Visitor233
        17
    Visitor233   46 天前
    很抱歉,一开始写的时候就想写这是个中台(学校、医院、还有个啥系统三个合一起的),访问量有点多,我不知道是什么概念,就定 100W 吧。但刚看了一遍,发现没写明这一点。
    Visitor233
        18
    Visitor233   46 天前
    @tcfenix 抱歉,是我没写明白,项目想减少依赖,所以 redis 能不用就不用,但今天跟经理一看代码好像写的更麻烦了= =
    killergun
        20
    killergun   46 天前
    定时,每两个小时向微信申请一次,将 token 放到 redis,过期时间是两个小时+一分钟。用了很多年没什么问题
    340244120w
        21
    340244120w   46 天前 via iPhone
    静态变量完全够了 失效前五分钟提前更新
    tcfenix
        22
    tcfenix   46 天前
    @Visitor233
    ....这都 2020 年了....没接触过 c#
    不过现在大部分写业务语言的从加个 redis 包到 pingpong 都是几分钟的事情....c#难道这么坑么...

    而且就算为了你自己,也一定要上 redis,外部招聘 redis mysql,消息队列这些都是默认服务端开发一定用过的,面试问题的时候,从 redis 如何做独占锁到底层数据结构通常都会问,而且真正工作中也基本都会用到

    你经理可能用过了,嫌麻烦不想用,或者怕你搞不定,但是你自己不能放弃任何一个提高自己的机会
    Still4
        23
    Still4   46 天前
    你把 redis 和 psql 都看作是存储,redis 天然支持你的业务需求,同时还满足高并发,随着业务增长 psql 读写更容易到达系统瓶颈
    建议不要为了省事将就用现有系统
    xylophone21
        24
    xylophone21   46 天前
    说 redis 的,其实和你的方案没有本质区别,都是找一个地方存储,当然 redis 可能更合适,因为
    1. 超时不需要你处理了,天然支持
    2. 性能更好,但实际上估计你也跑不满

    另外,你说的那个在是否更新标志使用 redis 也是要处理的,而且也需要一个超时
    Pythoner666666
        25
    Pythoner666666   46 天前
    给你说下我们项目的做法吧 简单的一批 直接存 redis 加一个过期时间 用的时候 直接去 redis 取 不存在就主动再去获取并更新 最后加锁 完事了。
    echooo0
        26
    echooo0   46 天前
    redis 就行了
    Visitor233
        27
    Visitor233   45 天前
    @useben
    @sunmoon1983
    @chinvo
    @killergun
    @tcfenix
    @Still4
    @xylophone21
    @Pythoner666666 么,大家都说 redis,其实我也认为 redis 很爽,直接 StringSet ( xx,xx,TimeSpan.FromMinutes(90))多舒服,上头担心 redis 崩了会对系统造成影响(我认为系统崩,redis 都不会崩)。昨晚和经理聊,决定加个定时服务,更新 token,再不行就上 redis 吧(这个用过),队列倒是没用过(我收集过一篇基于 k8s 和 rabbitMQ 的文章,这两个还没学会= =)。非常感谢大佬们解惑,鞠躬.jpg
    pytth
        28
    pytth   45 天前
    本地文件缓存不香么?每次访问请求 access_token.json,获得这个 token 当时获取的时间戳,然后用当前时间戳计算,>2 小时则重新请求 token 并更新 access_token.json,若<2 小时则直接使用这个 token
    yeept
        29
    yeept   45 天前
    如果不想上 Redis,既然是 .Net Core, 可以用自带的 MemoryCache
    chinvo
        30
    chinvo   45 天前 via iPhone
    @Visitor233 #27 不用 Redis 用 Microsoft.Extensions.Caching.Memory 啊,定时器不是更复杂么
    pierswu
        31
    pierswu   45 天前
    不会 c#,写了个 java 的实现
    Visitor233
        32
    Visitor233   45 天前
    @dhssingle
    @quan01994 我没听过 MemoryCache,但能 get 到一个新的知识点也不错,感谢大佬进来指点.jpg
    @yeept
    @chinvo
    Still4
        34
    Still4   44 天前
    主要还是每个系统做自己擅长的事,没有办法的情况下,手术刀能切西瓜吗,当然可以,但是毕竟不是专业的,用起来会很别扭
    如果担心 redis 崩了会对系统造成影响,那么你的架构可以改为 core - redis - db,优先读取 redis,没有数据再读取 db 更新到 redis,写数据先写 db 再写 redis,这样 redis 宕机对服务不产生影响,一定程度上也让服务变得更健壮,不过这样一来如果因为压力大导致 redis 宕机,大概率压力转移到 db 也会瞬间崩掉
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1169 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 18:16 · PVG 02:16 · LAX 11:16 · JFK 14:16
    ♥ Do have faith in what you're doing.