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

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

  •  
  •   Visitor233 · 2020-08-05 12:47:38 +08:00 · 4816 次点击
    这是一个创建于 1353 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

    另外,你说的那个在是否更新标志使用 redis 也是要处理的,而且也需要一个超时
    Pythoner666666
        25
    Pythoner666666  
       2020-08-05 19:59:07 +08:00
    给你说下我们项目的做法吧 简单的一批 直接存 redis 加一个过期时间 用的时候 直接去 redis 取 不存在就主动再去获取并更新 最后加锁 完事了。
    echooo0
        26
    echooo0  
       2020-08-05 23:18:35 +08:00
    redis 就行了
    Visitor233
        27
    Visitor233  
    OP
       2020-08-06 09:17:58 +08:00
    @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  
       2020-08-06 09:54:54 +08:00
    本地文件缓存不香么?每次访问请求 access_token.json,获得这个 token 当时获取的时间戳,然后用当前时间戳计算,>2 小时则重新请求 token 并更新 access_token.json,若<2 小时则直接使用这个 token
    yeept
        29
    yeept  
       2020-08-06 10:48:37 +08:00
    如果不想上 Redis,既然是 .Net Core, 可以用自带的 MemoryCache
    chinvo
        30
    chinvo  
       2020-08-06 11:00:16 +08:00 via iPhone
    @Visitor233 #27 不用 Redis 用 Microsoft.Extensions.Caching.Memory 啊,定时器不是更复杂么
    pierswu
        31
    pierswu  
       2020-08-06 14:47:23 +08:00
    Visitor233
        32
    Visitor233  
    OP
       2020-08-06 20:41:33 +08:00
    @dhssingle
    @quan01994 我没听过 MemoryCache,但能 get 到一个新的知识点也不错,感谢大佬进来指点.jpg
    @yeept
    @chinvo
    dhssingle
        33
    dhssingle  
       2020-08-07 09:08:20 +08:00
    Still4
        34
    Still4  
       2020-08-07 17:02:41 +08:00
    主要还是每个系统做自己擅长的事,没有办法的情况下,手术刀能切西瓜吗,当然可以,但是毕竟不是专业的,用起来会很别扭
    如果担心 redis 崩了会对系统造成影响,那么你的架构可以改为 core - redis - db,优先读取 redis,没有数据再读取 db 更新到 redis,写数据先写 db 再写 redis,这样 redis 宕机对服务不产生影响,一定程度上也让服务变得更健壮,不过这样一来如果因为压力大导致 redis 宕机,大概率压力转移到 db 也会瞬间崩掉
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2828 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 02:19 · PVG 10:19 · LAX 19:19 · JFK 22:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.