乐趣区

关于java:千万别强制停机我嘴都气歪了

你晓得强制停机的结果有多重大吗!

有一天,我正在欢快地写技术文章,后果电脑啪地一下就蓝屏了!

哦豁,完蛋,写了几千字,忘了保留!

我盲猜很多同学都有这种体验,可能因为一些突发意外,导致本人的电脑强制停机了,失落了本人以后的工作。

同样,对于企业,所有的网站、利用、数据、服务都是挂在服务器上的,一旦意外产生,比方被挖断了电线、遭逢了自然灾害,会导致服务器被强制停机,使得机器上 所有进行中的程序被强制中断 ,结果不堪设想!

有同学就笑了,不就是程序被强制中断么,咱们本人偶然也会用工作管理器或者 kill -9 命令杀个过程啊,放松重新启动程序不就好了,有啥大不了的?

确实,我以前也是通过强杀过程来下线和降级服务的,干脆利落爽。但直到起初有一次,因为强杀过程导致了线上事变,造成了经济损失和加班,把我嘴都气歪了!我才意识到本人之前太粗犷、想法太简略了。

其实,一个程序被强制中断,除了无奈提供服务外,还有很多重大的结果!

1. 申请失落

对于一个 web 服务器,比方 Java Web 开发中支流的 Tomcat。当承受到申请时,会开启一个线程来解决该申请。而如果申请数较多,线程解决不过去,就会将此申请放入期待队列中,排队期待闲暇线程。

假如 web 服务过程忽然中断,会导致所有在内存队列中期待执行的申请失落,等了半天,等了个空!

2. 业务中断

一旦过程中断,会导致 所有 正在执行的业务中断,会导致很多意想不到的结果。

比方有一个检查数据的工作,要查看所有数据库中状态为 0 的数据是否正确,代码流程如下:

// 开始查看,数据状态由 0 置为 1
startCheck();
// 查看
doCheck();
// 完结查看,将正确的数据状态置为 2
endCheck();

假如刚把数据的状态置为 1,示意正在查看中。而后程序就中断了,会导致当前这条数据的状态始终为 1,再也不会被查看。

同理,如果曾经查看完,并且数据正确,原本应该将数据状态置为 2,但这时程序中断,也会导致 数据的状态和预期不统一

以上只是一个简略的例子,但理论的业务场景中,业务中断可能间接影响收益,尤其是波及交易的领取转账业务,如果用户曾经付款,却因为程序的中断,没有存储付款记录,那这个领取业务不是真要凉凉?

3. 事务中断

数据库事务是指对数据库的一系列 不可分割 的操作,具备一致性,每次执行必须使数据库从一个一致性状态变到另一个一致性状态。

比方转账业务中,用户 A 要给用户 B 转账 1 元,用户 A 扣除 1 元,用户 B 就要减少 1 元。

但如果用户 A 已扣除 1 元后,应用程序或者数据库系统忽然挂了,导致事务尚未实现就被迫中断,后果用户 B 的总金额并没有变动。这时数据库就处于不统一状态。同理,即便在程序中设计了回滚,回滚过程也可能会被中断!

除了数据不统一外,事务中断还可能导致锁行、锁表,使得这部分 数据的可用性受到影响

4. 文件损坏

假如程序正在向一个文件进行写操作,还未实现,就被中断了,可能会导致文件的不残缺、甚至损坏。

这让我想起小时候,电脑配置不高,有时玩游戏会卡住,而后我就强制杀了过程,后果导致游戏文件损坏,只能从新下载游戏。

5. 工作失落

咱们在编写业务代码时,常常会将比拟耗时的工作异步化,将工作提交到线程池后立刻返回胜利。线程池会从工作队列中顺次读取并执行工作。

而一旦程序中断,线程池中的工作就会失落, 如同他素来没有被提交过一样 。这种感觉就像你许可他人要做一件事,他人对你很释怀,但你最初却放了鸽子跑路了。

6. 数据失落

有时,咱们会先将数据长期放在内存中,而后定期、定时、或者分批地长久化到数据库或本地磁盘中。

比方 Redis 数据库的 RDB 机制,每隔一段时间,会将内存中的数据进行本地备份,从而升高大量数据并发写入时的负载,晋升性能。

但就像下面提到的工作失落一样,一旦程序中断,可能会导致很多 未长久化的数据失落 ,比方缓存、分批提交数据等。

7. 音讯失落

在分布式系统中,各个节点间常常通过音讯来进行交互和合作,而程序的中断可能会在不同状况下导致音讯失落。

1. 音讯未收回

假如某领取业务中,曾经扣除了用户的账户余额,并更新了数据库,接下来要向客户端返回应答音讯。

然而音讯正在发送队列中排队期待发送时,因为过程被强制退出导致音讯未收回,从而导致应答音讯失落。客户端久久接管不到音讯后,可能会发动重试,导致反复更新。

2. 音讯未确认

比如说某段业务代码从音讯队列中取出了一个音讯,进行生产解决,代码流程如下:

// 获取下一个音讯
Message msg = getNextMsg();
// 解决音讯
int res = handleMsg(msg);
// 解决胜利?if(res == 0) {
    // 确认音讯
  ack();} else {
  // 回绝确认音讯
  nack();}

无论音讯解决胜利与否,都必须要给音讯队列一个回复!如果解决胜利,要通知他这条音讯曾经被我解决实现啦,请给我下一条音讯;即便解决失败,也要通知音讯队列,请给我重发本条音讯。

而一旦程序中断,这条音讯的处理结果便无人知晓,可能导致音讯队列的 阻塞或者有限重发 (依据具体音讯队列来决定)。

8. 资源占用

程序的强制中断可能会导致很多资源的占用未被开释。比方:

  1. 空间占用:如已调配的内存未回收,临时文件未被删除等。
  2. 端口占用:会导致这个端口无奈被其余应用程序应用。很多同学在本地调试时,应该也会遇到因为强退导致的 3000、8080 端口未被开释的问题。
  3. 连贯占用:比方和近程的服务建设了 Http 连贯,因为连贯未被开释,会节约一个连接数,就像买了电影票却不去一样。

9. 服务未下线

在微服务场景下,服务通常由集中的注册核心进行对立的服务发现和治理。

比方 Eureka 注册核心,服务生产者向注册核心注册服务,服务消费者从注册核心获取服务地址,而后近程调用:

而一旦某个服务过程还没有即时告诉注册核心它要下线,就中断了,会导致服务消费者仍能获取到该服务的路由,从而调用失败。

此外,服务下线时如果未向上游(该服务调用方)告诉,还可能导致上游的继续调用,重大时会产生雪崩效应,整条服务链路中断!

尤其是在分布式场景下,呈现过程强制中断对集群的影响(比方数据一致性)十分大。正如 FLP 不可能定理 的形容:在异步通信场景,即便只有一个过程失败,也没有任何算法能保障非失败过程达到一致性。


其实,相比起这些问题,更可怕的是,如果没有欠缺的数据监控和检测机制,你甚至齐全不晓得在强制停机后有没有呈现问题?呈现了哪些问题?哪些数据失落?哪些数据不统一?哪些工作须要弥补?看不见的危险才最可怕啊!

因而,预防大于医治。一方面要养成良好习惯,无论是对本人的电脑还是服务器,都千万不要再被动强制停机了;另一方面,也要在程序设计时,做好应答意外停机的防控措施。不要等到失去了,才追悔莫及。

退出移动版