-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
并发下access_token存在脏写隐患 #696
Comments
嗯,稍后我来搞定它 |
除了在并发这个问题外。 再补充一个问题(现象),微信 AccessToken 可能会在规定时间(目前是两小时)内出现异常失效的情况(当时为了确认这个问题,专门做了一些测试,并且把服务器上面的日志进行了详细地对比分析,发现的确有这种可能),所以建议提供一种 AcessToken 过期的反馈接口,当业务调用返回 AccessToken 错误的时候,能够进入重新获取 AccessToken 的流程,在这个流程里面统一实现重新获取、高并发脏写的问题 。 |
@odirus $token = $accessToken->getToken($force_refresh); |
可以搞个服务,专门去请求token。弄个消息队列啥的。 |
脏写其实不存在,我去研究了缓存组件的代码,它其实不会出现锁的问题,> https://github.com/doctrine/cache/blob/master/lib/Doctrine/Common/Cache/FileCache.php#L251-L260 现在的问题其实只是读不到的时候导致的重试增加了 API 调用,这个我考虑增加一个配置,可配置重试次数来解决。 |
配置项增加:
|
超哥,脏写隐患还是存在的,缓存组件保证了单次写是原子操作,但还是不够的。 |
其实这里有个问题,就是为什么会有三个php进程去同时拿token呢。应该只交给一个进程去做这件事。 我相信如果请求量大了,做这么一个进程不是问题。请求量小的话,不用管 所谓脏写问题,其实单个组件是没法解决的,因为没法确定使用的缓存类型,也就无法确保缓存的读取和写入是原子的。还是要从架构上解决这个问题。 |
@greedying nginx php-fpm模式三个php进程同时去拿token,在并发量稍微大点的时候应该很正常。所以单个组件确实解决不了问题,要从构架上改变。 |
@dawniii 如果量大的情况就调整重试次数吧,完全不想重试就改成 0 |
我的想法是写一个AccessToken子类,并重写getToken方法,再覆盖到容器里。这样就可以使用自己独立的token服务,这个服务单线维护token的获取更新。这样就算是在多台机器部署也不是问题了。 当然流量很小的项目就不用这么做了,或者超哥直接做个接口能重写getToken方法?这样可能更方便。 |
getToken & setToken 本来就是 public 的,$app->access_token->getToken(); 即可,重写的话直接创建一个你自己的 AccessToken 类就好了,有这几个方法就好了,3.1 就不打算增加接口了: public function getToken($forceRefresh = false)
public function getAppId()
public function getSecret()
public function getQueryName() |
我也建议是在 cron 里,单进程方式定期更新 AccessToken。而 middleware 的检查只是多一重保险。 |
@greedying gre @overtrue 还有微信会文档就有说,微信有可能主动让token失效,这样的话任何使用token的地方都应该处理token失效然后重新请求这件事,不能单纯依靠缓存时间没过就有效. 并且这中情况的错误响应都是固定的40014,invalid access_token这种.所以是不是? |
AccessToken类中getToken方法。如果token缓存过期了,就从服务端获得并存到缓存。
假如有三个请求同时发现token已过期,都去微信服务器拿新的token。因为网络是有延迟的,并不能保证最后一个请求就刚好是最后一个存到缓存里。所以有脏写隐患。导致后面的带的都是脏token请求失败。
继续看了下retryMiddleware这个请求中间,如果发现token错误就再去重新获得token。。。感觉这是脏写的无限循环,请求量小了 可能没啥。但是并发多了,很有可能爆出这个隐患。
The text was updated successfully, but these errors were encountered: