接上篇:https://developer.aliyun.com/article/1228230?spm=a2c6h.13148508.setting.31.62774f0e61109O
二、 多线程使用不正确
多线程最主要目的就是“最大限度地利用CPU资源”,可以把串行过程变成并行过程,从而提高了程序的执行效率。
1. 一个慢接口案例
假设在用户登录时,如果是新用户,需要创建用户信息,并发放新用户优惠券。例子代码如下:
其中,绑定优惠券(bindCoupon)是给用户绑定新用户优惠券,然后再给用户发送推送通知。如果随着优惠券数量越来越多,该函数也会变得越来越慢,执行时间甚至超过1秒,并且没有什么优化空间。现在,登录(login)函数就成了名副其实的慢接口,需要进行接口优化。
2. 采用多线程优化
通过分析发现,绑定优惠券(bindCoupon)函数可以异步执行。首先想到的是采用多线程解决该问题,代码如下:
现在,在新线程中执行绑定优惠券(bindCoupon)函数,使用户登录(login)函数性能得到很大的提升。但是,如果在新线程执行绑定优惠券函数过程中,系统发生重启或崩溃导致线程执行失败,用户将永远获取不到新用户优惠券。除非提供用户手动领取优惠券页面,否则就需要程序员后台手工绑定优惠券。所以,用采用多线程优化慢接口,并不是一个完善的解决方案。
3. 采用消息队列优化
如果要保证绑定优惠券函数执行失败后能够重启执行,可以采用数据库表、Redis队列、消息队列的等多种解决方案。由于篇幅优先,这里只介绍采用MetaQ消息队列解决方案,并省略了MetaQ相关配置仅给出了核心代码。
1) 消息生产者代码
注意:
可能出现发生消息不成功,但是这种概率相对较低。
2) 消息消费者代码
3) 解决方案优点
采集MetaQ消息队列优化慢接口解决方案的优点:
• 如果系统发生重启或崩溃,导致消息处理函数执行失败,不会确认消息已消费;由于MetaQ支持多服务订阅同一队列,该消息可以转到别的服务进行消费,亦或等到本服务恢复正常后再进行消费。
• 消费者可多服务、多线程进行消费消息,即便消息处理时间较长,也不容易引起消息积压;即便引起消息积压,也可以通过扩充服务实例的方式解决。
• 如果需要重新消费该消息,只需要在MetaQ管理平台上点击“消息验证”即可。
接下篇:https://developer.aliyun.com/article/1228227?groupCode=java