关于 token 穿透的问题 感觉 PHP 只能靠锁 Java 的话可以用 synchronized 来保证

2018-09-25 17:22:35 +08:00
 0576coder

最近项目上线 有点小流量 峰值差不多 600-800qps 吧 遇到了一个微信 accesstoken 穿透问题

问题描述

在并发高的时候 这时候缓存里面的 token 失效了 那么这时候我们会去请求微信的接口来刷这个 token 这时候因为有网络 io 然后各个请求得到的 accesstoken 互相覆盖 导致获取到的 token 不一定是最新有效的 token 所以就会陷入要不断去刷这个微信 token 的死循环当中 要是没及时发现 差不多要把微信 token 的当日获取次数用完

目前我的做法 业务代码带上个参数可以直接请求微信接口去刷新这个 token 然后还有务去刷新这个 token


目前暂时解决思路

用 redis 的 setnx 锁 只有竞争到锁的才会去请求 accesstoken 然后在存到缓存里之后 再把锁释放掉 当然我会设置这个锁的最长过期时间的

这样做了之后可以防止 token 穿透 但是比如 10 个并发请求 只有一个竞争到锁 其它的请求是不是要等待一会儿再去竞争锁 这样难道不会导致前端用户体验不好吗

还有搜了下 搜到了二级缓存 可以缓存两个 key 防止穿透 但是具体实现的话 是不是还是要用到 setnx


我搜了下 java 直接一个 synchronized 就能保证了- - 我是不是可以用 java 实现一个 token 中控

4061 次点击
所在节点    PHP
38 条回复
blindpirate
2018-09-25 17:27:12 +08:00
语死早系列
leoleoasd
2018-09-25 17:29:40 +08:00
缓存的 accesstoken 加上过期时间 快到过期时间了的时候每一个进程都有一定概率刷新 token
leoleoasd
2018-09-25 17:30:37 +08:00
或者 php 跑一个后台进程 定时刷新 token
linauror
2018-09-25 17:36:27 +08:00
计划任务定时执行刷新
liuxu
2018-09-25 17:37:35 +08:00
synchronized 也是锁啊。。。
allanzhuo
2018-09-25 17:39:05 +08:00
setnx 的方法应该是一种比较常用的方法了吧,感觉楼主说的这个已经很完善了,只不过可以给竞争失败的用户一个友好的提示。还有种办法就是起个线程主动刷新即将过期的缓存。
FreeEx
2018-09-25 17:39:13 +08:00
如果你的应用是单节点的话可以使用 java 的 ReentrantReadWriteLock
,在 api 文档中搜索这个类会有一个 CacheData 的例子,可以完美解决你说的这个问题。
mortonnex
2018-09-25 17:39:42 +08:00
"峰值差不多 600-800qps"

楼主的项目日 pv 是千万级的?
0576coder
2018-09-25 17:41:23 +08:00
@mortonnex
日 pv 刚百万左右
0576coder
2018-09-25 17:42:19 +08:00
在你计划任务刷新的时候 假如有正常请求呢
mortonnex
2018-09-25 17:43:11 +08:00
@0576coder 那么你们的接口响应速度还是很快了
loveCoding
2018-09-25 17:46:22 +08:00
获取 token 时加锁可行
loveCoding
2018-09-25 17:48:41 +08:00
@0576coder #10 并不是刷新时就清除 token ,而是获取到了后覆盖原值, 刷新 token 要比 token 过期时间小
yushiro
2018-09-25 17:52:41 +08:00
重新申请 accesstoken 专门分配一个线程或者进程去操作,这样就没并发的问题了。
janxin
2018-09-25 17:57:56 +08:00
所以 synchronized 是怎么实现的呢?
baiy
2018-09-25 18:01:50 +08:00
#3 三楼正解 业务仅读取 token, token 的维护交给其他程序负责 ,我记得微信的 token 过期时间是 7200, 起一个计划任务每 3600 主动刷新 token
0576coder
2018-09-25 18:23:35 +08:00
@janxin
Java 的 synchronized 也是一种线程互斥机制而已
一个大佬告诉我的
sampeng
2018-09-25 18:37:24 +08:00
synchronized 和 redis 的锁是一回事?后者处理分布式一致性问题。前者只处理本机一致性问题。两码事好吗
mmdsun
2018-09-25 18:39:41 +08:00
Redis 锁是 cas。Java synchronized 比较重量级吧
fcten
2018-09-25 18:42:35 +08:00
另起一个定时任务定期刷新 token 不行吗。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/492439

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX