关注公众号【1024个为什么】,及时接收最新推送文章!
背景
由于最近上线比较频繁,就遇到了一个小概率的数据不一致的问题。
具体过程如下:
很明显,是服务没有做到优雅停机,导致的两个服务的数据不一致。
优雅停机、优雅重启,本质到底是什么?
优雅重启涵盖了优雅停机、优雅启动。
优雅停机:就是 JVM 进程杀掉之前,要做好各项收尾工作;
常说的优雅停机一般是指 RPC 框架的工作线程 和 Spring 容器的销毁(容器中可能包含各种连接池对象的管理)。但服务复杂了之后,除了上面两种线程之外,难免会有其他的工作线程,在服务重启的时候被忽略掉。就会造成这些线程还在努力工作,突然被重启信号强制中断,产生各种意外的结果。
优雅启动:就是在各项必要的预备工作准备完成之后,才能对外暴露服务。
拿一个餐馆场景举例
优雅停机
餐馆到点要关门了
1)迎宾要在门口挂上闭店的通知,新的顾客就不能进来了
对比我们的服务,就是通知注册中心,告知客户端,本节点要下线了,不再接受新请求了
2)等店内现有就餐人员用餐完毕离开后,正式闭店
对比我们的服务,就是等待 RPC 框架的工作线程执行结束后,停掉 JVM 进程
但是,等待现有就餐人员用餐完毕之前,厨房、收银员等人员不能先下班,可能还需要加菜、热菜什么的。
对比我们的服务,就是 Spring 管理的 bean 对象等其他工作线程需要的资源不能提前被清理。
还有其他非 RPC 框架的工作线程,如果不能直接被中断,也要保证不能先于 RPC 框架的工作线程结束,也要保证这些线程能够正常执行完毕。
优雅启动(大体是优雅停机的逆向)
餐馆早上要开门营业了
1)餐馆的点菜系统、卫生、桌椅等等,必须在开门前准备到位
对比我们的服务,就是必须把 Spring、数据库、redis 等工作线程干活必须要用的资源准备好
2)开门营业,可以接待顾客
对比我们的服务,就是通知注册中心,我这个节点可以对外提供服务了,保证有请求过来时能有相应的工作线程干活。
其他一些不太紧急的事情,比如菜单、餐具等等,可以等开门后或者有顾客进来后再提供。
对比我们的服务,比如获取配置信息、慢热数据等等,都可以等有请求过来再慢慢处理。
解决方案
本质搞清楚后,解决这个问题就变的很简单了。
通过 RPC 框架提供的 shutdown 钩子(由于我们是自研框架,主流开源框架在网上都能找到方案,这里就不赘述了)。
1)停掉 MQ 客户端,不再接收新消息;
2)强制等待 5 秒后(前提是要评估出 MQ 客户端待消费队列中的消息是否能在 5 秒内处理完毕),再杀掉 JVM 进程。
优雅停机处理不好,可能会造成数据不一致的问题。
优雅启动处理不好,可能会给调用方带来很多异常。
原创不易,多多关注,一键三连,感谢支持!