Skip to content
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

WxMpServiceImpl.executeInternal 方法阻塞导致服务器宕机的问题 #23

Closed
wesleywu opened this issue Aug 16, 2016 · 10 comments
Closed
Labels

Comments

@wesleywu
Copy link

目前方法的签名是这样的:

protected synchronized <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {...}

里边执行了一个超耗时的https的阻塞请求,直到微信官方网站返回了执行结果,才会结束这个方法。

所以,如果有多个线程通知执行 execute (然后 executeInternal),比如通过16个线程同时发送100万个模板消息,早晚都一定会发生一大堆线程阻塞在这个方法的起始处。

我们就遇到了这个情况,用 jstack 查看我们的 jvm 的线程状况,大部分都这样:
"http-nio-8081-exec-188" #1201 daemon prio=5 os_prio=0 tid=0x00007f99f0498000 nid=0x4822 waiting for monitor entry [0x00007f99c6ef4000]
java.lang.Thread.State: BLOCKED (on object monitor)
at me.chanjar.weixin.mp.api.WxMpServiceImpl.executeInternal(WxMpServiceImpl.java:729)
- waiting to lock <0x00000000c7332ed8> (a me.chanjar.weixin.mp.api.impl.WxMpServiceImpl)
at me.chanjar.weixin.mp.api.WxMpServiceImpl.execute(WxMpServiceImpl.java:705)

于是,整个jvm的线程数量耗尽,导致tomcat假死,服务器资源消耗基本为0。

所以我的问题如下:
1、这里的这个 synchronized 关键字为什么一定要加?
2、可以去掉不?
3、如果去掉,会导致什么严重问题?

感谢。

@binarywang
Copy link
Member

@wesleywu
Copy link
Author

谢谢,看了这篇博文。对我们目前的帮助似乎不是特别大,思路有借鉴,关键是要降低同步块的执行时间。目前这个方法的同步关键词似乎是为了解决token过期以后的重取
token问题,那只需要在刷新token的地方加同步即可,而没必要在这个方法上加,不知我的理解是否对。

另外,我建议把底层的http库换成okhttp,并且需要加入一些并发压力测试的用例。

这些工作我可以帮忙做。

@binarywang
Copy link
Member

没问题,你可以做相关调整直接提交代码并做好测试,感谢帮忙共同维护好这个SDK

@chanjarster
Copy link
Collaborator

时间比较久远已经忘记了,不过似乎和刷新access token有关。

如果在access token失效的时候有大量请求发出,那么就会造成并发刷新access token,导致access token的单日刷新次数用尽,以及程序不断得刷新access token。

https://github.com/chanjarster/weixin-java-tools/issues/323#issuecomment-240055919@zxkane 说的思路不错,应该采用异步的方式,使用队列比较好,比如弄个100个队列,取模让队列处理。

不过还是要考虑如何避免并发刷新access token的问题,而且这个问题也同时存在于集群环境。没想过怎么搞。

@bysunexus
Copy link

http://mp.weixin.qq.com/wiki/11/0e4b294685f817b95cbed85ba5e82b8f.html

2、目前access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器对外输出的依然是老access_token,此时公众平台后台会保证在刷新短时间内,新老access_token都可用,这保证了第三方业务的平滑过渡;

刷新时可以短期保证新老token均有效

中秋期间有时间提交一个pr修改一下这里的实现

@binarywang
Copy link
Member

@kakotor 期待你的新代码

@binarywang binarywang added the bug label Oct 27, 2016
@yigubigu
Copy link

#1 使用redis,把access_token
#2 中控服务器定期刷新,拿到后立即更新
#3保 证刷新的线程是高优先级,能够始终执行

@biageng888
Copy link

中控access_token还是缓存中处理好些,请求大时,线程控制是个问题,不知有无更好解决方案。

@anjia0532
Copy link

可以考虑增加分布式缓存 Hazelcast 比 redis 轻量

@binarywang
Copy link
Member

时间太长,暂时关闭此issue,如果使用新版本发现有此问题,请开启新issue单独讨论。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants