首页 > IT职业 > IT图书 > 【架构思考】高可用升级-如何处理Stream异常
大家好,我是姚半仙,慕课网《Java架构师成长直通车》课程架构师讲师团成员之一。这篇文章中我们来看一下Stream如何处理异常。
人非圣贤孰能无过,Spring Cloud中哪个组件都不得不面临异常的情况,况且Java的运行期异常在任何时间任何地点都可以发生,真的是防不胜防,那我们在Stream里有什么方法来应对吗?
话说应付异常情况无非就是下面三个思路,放之四海而皆准:
大部分的小型应用系统只会使用第一种方案,也就是重试,能用到降级策略的一般都是有一定规模的应用。对于重试和降级都不能解决的异常情况来说,我们要么直接丢弃,要么就要打上某些特殊标记,然后通知人工介入处理。
在Stream中对以上三个情况都有相应的方案,后面我们会逐一体验这些异常处理策略。
我们先来看一下最简单的重试机制,在Stream中进行重试有两个方法
(1) Consumer端重试
重试只发生在Consumer端,Stream将失败的消息原封不动的发给当前这个Consumer。也就是说,重试只会发生在当前机器,并不会换一个节点进行重试。
当然我们不能让重试无休止的进行下去,Stream默认情况下会进行3次重试,如果我们想增加或减少重试次数,可以给某个Consumer指定重试次数。
(2) Re-queue重试
不同于上一种的重试方式,在Re-queue的方案下Stream会将失败的消息重新发送到消息组件中,这种方式和前面的Consumer端重试有两个不同之处:
Re-queue其实还有一个很大的坑,不小心就容易掉进去,我们在本章后面安排了一个小节专门讲异常处理的注意事项。
降级说白了就是一段自定义的异常处理流程,在Stream中我们可以借助spring-integration的一个注解来完成,相关的配置非常简单,方法级别上的一行搞定一切
@ServiceActivator(inputChannel = "xxxx")
上面这个注解和Hystrix的Fallback有异曲同工之处,都是将异常请求转交给Fallback逻辑进行处理。关于这部分的内容,我们将在稍后的小节通过一个小Demo来详细说明。
人工介入的方式五花八门,但归根结底我要知道在哪里才能找到需要人工介入的数据,这其实就是一个归集异常数据的功能。
在Stream里我们可以通过下面两个常用的方式,将异常消息归集到某个消息队列中,等待人工介入:
在消息到达死信队列后,我们可以人工将消息移动到其他队列中进行重新消费,在稍后的小节里我将带大家配置一个死信队列。
我先和大家分享一下我在新零售业务的商品发布服务里是如何处理异常情况的。

上面例子中的商品发布是借助消息组件完成的,整个发布流程涉及到上下游一大堆服务,为了保证严格的幂等性,我采用了一种简单有效的手段。
整个发布流程被定义成一个工作流,在Consumer(商品中心)接收到商品发布消息后,每做完一个发布阶段的任务都推动商品状态的变化(类似有限状态机的方式进行状态流转),在下次重试的时候,会根据状态标记获取当前商品最近一次的发布进度,然后继续走后面的流程。
在整个流程中我使用了一种重试机制和一种补偿手段:
对于上面提到的无法靠Re-queue重试解决的异常情况(比如商品标题中带有违禁词),会被记录在案,等待人工介入,如果短时间内出现的异常记录超过阈值则触发警报,我就会收到包括短信、钉钉播报和自动电话语音的海陆空警报轰炸。
学习Tips:我们在实际的项目中需要搭配使用多种技术来完成一个需求,就拿商品发布的异常处理来说,就涉及了Re-queue、后台补偿Job、监控报警人工介入三个不同的环节。而对于某些一致性要求较高的场景,其中的异常处理更加复杂(比如TCC架构下的最终一致性方案)。同学们在实际应用中一定要重视异常Case,衡量一个服务的健壮性、可用性的标准不是正向Case走的多快多顺利,而是你是否Hold得住所有异常情况。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/2963/viewspace-2824792/ ,如需转载,请注明出处,否则将追究法律责任。