项目: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
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; |
2
soulzz 2020-08-05 13:03:50 +08:00
这个用 java 来写就很方便,引入 guava
设定 key 两小时失效 没有 token 直接 callable 里调用申请新的 |
3
teawithlife 2020-08-05 14:39:34 +08:00
不知道微信对获取 token 的频率有没有什么限制,如果没有限制的话,单独开个进程,每隔 90 分钟刷一次 token,需要用到的时候直接用就行了
|
4
pagepancn 2020-08-05 15:00:28 +08:00
@teawithlife 获取 token 每个月是有次数上限的,不能这么干
|
5
useben 2020-08-05 15:23:37 +08:00
考虑到瞬时大量请求刚好赶上. token 不放缓存, 单纯 mysql 扛不住...
直接 token 存 redis, 过期时间设为将近 2 小时, 过期再去请求一个就行了. 期间所有应用共用. 均摊下来时间复杂度还是 O(1) |
6
iyangyuan 2020-08-05 15:39:01 +08:00
根本就不需要入库,用 Java 的话,放内存,加一个读写锁就搞定了。如果是微服务项目,单独做一个接口
|
7
kanezeng 2020-08-05 16:00:55 +08:00
@pagepancn 单独一个进程 90 分钟刷一次不会碰到频率上限的(每天 2000 次),只不过存在一点小风险,就是当业务进程取到老 token 还没使用时,刷新线程刷新了 token 导致老 token 失效,这时候业务进程使用老 token 会失败。不过按微信的说法,新老 token 能同时有效 5 分钟,所以应该也没问题
|
8
dhssingle 2020-08-05 16:21:47 +08:00
简单问题复杂化,单体应用的话 MemoryCache 足够用了,甚至静态变量也不是不可以。
|
10
huobazi 2020-08-05 16:33:11 +08:00
这个? 没看懂做什么用的啊? 或者, 为什么做这个呢?
|
11
sunmoon1983 2020-08-05 16:44:34 +08:00
redis 不行吗?
|
12
quan01994 2020-08-05 17:05:51 +08:00
MemoryCache
|
13
unnamedhao 2020-08-05 17:11:26 +08:00
其实为了保险还需要做一个检测,
比如不小心在其他地方(例如测试环境)申请了 token,会导致当前 token 失效。 所以需要在当前环境使用 token 调用接口时检测返回的错误码, 如果错误码是 token 错误, 则需要设置标志重新获取 token |
14
tcfenix 2020-08-05 17:12:22 +08:00 2
不是很明白为什么把这么简单的事情搞得这么复杂,
拿到了 access token 直接放 redis,设置 2 小时超时 每次请求过来去 redis 找, 如果有的话,对比一下就过了,没有的话就说明过了两小时,重新去微信找咯 追求性能的话弄个一分钟之类的内存缓存不就好了.... 你弄个数据库什么一堆架构真是何苦? |
15
h82258652 2020-08-05 17:13:20 +08:00
不需要多线程。直接用 asynclock ( nito.asyncex 这个包)。反正把请求微信开始到写入存储包起来就行了。(内存存储、磁盘存储、数据库存储都行)
减 xx 分钟也不需要,一般这种会有 slide time 。 |
16
xcstream 2020-08-05 17:27:29 +08:00
定时请求 入库 结束了
|
17
Visitor233 OP 很抱歉,一开始写的时候就想写这是个中台(学校、医院、还有个啥系统三个合一起的),访问量有点多,我不知道是什么概念,就定 100W 吧。但刚看了一遍,发现没写明这一点。
|
18
Visitor233 OP @tcfenix 抱歉,是我没写明白,项目想减少依赖,所以 redis 能不用就不用,但今天跟经理一看代码好像写的更麻烦了= =
|
20
killergun 2020-08-05 19:03:17 +08:00
定时,每两个小时向微信申请一次,将 token 放到 redis,过期时间是两个小时+一分钟。用了很多年没什么问题
|
21
340244120w 2020-08-05 19:04:35 +08:00 via iPhone
静态变量完全够了 失效前五分钟提前更新
|
22
tcfenix 2020-08-05 19:07:36 +08:00
@Visitor233
....这都 2020 年了....没接触过 c# 不过现在大部分写业务语言的从加个 redis 包到 pingpong 都是几分钟的事情....c#难道这么坑么... 而且就算为了你自己,也一定要上 redis,外部招聘 redis mysql,消息队列这些都是默认服务端开发一定用过的,面试问题的时候,从 redis 如何做独占锁到底层数据结构通常都会问,而且真正工作中也基本都会用到 你经理可能用过了,嫌麻烦不想用,或者怕你搞不定,但是你自己不能放弃任何一个提高自己的机会 |
23
Still4 2020-08-05 19:30:46 +08:00
你把 redis 和 psql 都看作是存储,redis 天然支持你的业务需求,同时还满足高并发,随着业务增长 psql 读写更容易到达系统瓶颈
建议不要为了省事将就用现有系统 |
24
xylophone21 2020-08-05 19:54:52 +08:00
说 redis 的,其实和你的方案没有本质区别,都是找一个地方存储,当然 redis 可能更合适,因为
1. 超时不需要你处理了,天然支持 2. 性能更好,但实际上估计你也跑不满 另外,你说的那个在是否更新标志使用 redis 也是要处理的,而且也需要一个超时 |
25
Pythoner666666 2020-08-05 19:59:07 +08:00
给你说下我们项目的做法吧 简单的一批 直接存 redis 加一个过期时间 用的时候 直接去 redis 取 不存在就主动再去获取并更新 最后加锁 完事了。
|
26
echooo0 2020-08-05 23:18:35 +08:00
redis 就行了
|
27
Visitor233 OP @useben
@sunmoon1983 @chinvo @killergun @tcfenix @Still4 @xylophone21 @Pythoner666666 么,大家都说 redis,其实我也认为 redis 很爽,直接 StringSet ( xx,xx,TimeSpan.FromMinutes(90))多舒服,上头担心 redis 崩了会对系统造成影响(我认为系统崩,redis 都不会崩)。昨晚和经理聊,决定加个定时服务,更新 token,再不行就上 redis 吧(这个用过),队列倒是没用过(我收集过一篇基于 k8s 和 rabbitMQ 的文章,这两个还没学会= =)。非常感谢大佬们解惑,鞠躬.jpg |
28
pytth 2020-08-06 09:54:54 +08:00
本地文件缓存不香么?每次访问请求 access_token.json,获得这个 token 当时获取的时间戳,然后用当前时间戳计算,>2 小时则重新请求 token 并更新 access_token.json,若<2 小时则直接使用这个 token
|
29
yeept 2020-08-06 10:48:37 +08:00
如果不想上 Redis,既然是 .Net Core, 可以用自带的 MemoryCache
|
30
chinvo 2020-08-06 11:00:16 +08:00 via iPhone
@Visitor233 #27 不用 Redis 用 Microsoft.Extensions.Caching.Memory 啊,定时器不是更复杂么
|
31
pierswu 2020-08-06 14:47:23 +08:00
不会 c#,写了个 java 的实现
https://gist.github.com/pierswu/84dda20ce2f3f42b96844a74e6cb81fc |
32
Visitor233 OP |
33
dhssingle 2020-08-07 09:08:20 +08:00
|
34
Still4 2020-08-07 17:02:41 +08:00
主要还是每个系统做自己擅长的事,没有办法的情况下,手术刀能切西瓜吗,当然可以,但是毕竟不是专业的,用起来会很别扭
如果担心 redis 崩了会对系统造成影响,那么你的架构可以改为 core - redis - db,优先读取 redis,没有数据再读取 db 更新到 redis,写数据先写 db 再写 redis,这样 redis 宕机对服务不产生影响,一定程度上也让服务变得更健壮,不过这样一来如果因为压力大导致 redis 宕机,大概率压力转移到 db 也会瞬间崩掉 |