当前位置: 首页 > news >正文

反向压力:异步系统中的OOM问题

Lead

异步系统中为什么会出现OOM问题?如何避免?揭秘时刻到啦!今天小编带大家了解异步系统中的OOM问题。

在Java编程中,我们经常使用ExecutorService线程池服务类来处理请求异步执行的问题。在这种方案中,请求的具体逻辑实际上是交给了各个步骤的执行器(executor)进行处理。在这整个过程中没有任何阻塞的地方,各个步骤待处理的任务都被隐式地存放在了各个执行器的任务队列中。如果各执行器处理得足够快,那么它们的任务队列都能被及时消费,这样不会存在问题。但是,一旦有某个步骤的处理速度比不上请求接收线程接收新请求的速度,那么必定有部分执行器任务队列中的任务会不停增长。由于执行器任务队列默认是非阻塞且不限容量的,这样当任务队列里积压的任务越来越多时,终有一刻,JVM的内存会被耗尽,抛出OOM系统错误后程序异常退出。

 

图1: 任务在各个Executor队列中积压

实际上,这也是所有异步系统都普遍存在,而且必须引起我们重视的问题。在纤程里,可以通过指定最大纤程数量来限制内存的使用量,非常自然地控制了内存和流量。但是在一般的异步系统里,如果不对执行的各个环节做流量控制,就很容易出现前面所说的OOM问题。因为当每个环节都不管其下游环节处理速度是否跟得上,不停将其输出塞给下游的任务队列时,只要上游输出速度超过下游处理速度的状况持续一段时间,必然会导致内存不断被占用,直至最终耗尽,抛出OOM灾难性系统错误。

为了避免OOM问题,我们必须对上游输出给下游的速度做流量控制。一种方式是严格控制上游的发送速度,比如每秒控制其只能发1000条消息。但是这种粗糙的处理方案会非常低效。比如如果实际下游能够每秒处理2000条消息,那上游每秒1000条消息的速度就使得下游一半的性能没发挥出来。再比如如果下游因为某种原因性能降级为每秒只能处理500条,那在一段时间后同样会发生OOM问题。

更优雅的一种解决方法是被称为反向压力的方案,即上游能够根据下游的处理能力动态调整输出速度。当下游处理不过来时,上游就减慢发送速度;当下游处理能力提高时,上游就加快发送速度。反向压力的思想,实际上正逐渐成为流计算领域的共识,比如与反向压力相关的标准Reactive Streams正在形成过程中。图2演示了Reactive Streams的工作原理,下游的消息订阅从上游的消息发布者接收消息前,会先通知消息发布者自己能够接收多少消息,消息发布者之后就按照这个数量向下游的消息订阅者发送消息。这样,整个消息传递的过程都是量力而行的,就不存在上下游处理能力不匹配造成的OOM问题了。

图2:Reactive Streams工作原理

那在Java中具体该怎样实现反向压力功能呢?我们继续用ExecutorService线程池来进行说明。由于请求接收线程接收的新请求及其触发的各项任务是被隐式地存放在各步骤的执行器任务队列中,并且执行器默认使用的任务队列是非阻塞和不限容量的。因此要加上反向压力的功能,只需要从两个方面来控制:

第一,执行器任务队列容量必须有限。

第二,当执行器任务队列中的任务已满时,就阻塞上游继续向其提交新的任务,直到任务队列重新有空间可用为止。

 图3: 使用容量有限的阻塞队列实现反向压力

按照上面这种思路,我们可以很容易地实现反向压力。图3展示了使用容量有限的阻塞队列实现反向压力的过程,当process这个步骤比decode步骤慢时,位于process前的容量有限的阻塞队列会被塞满。当decode继续要往其写入消息时,就会被阻塞,直到process从队列中取走消息为止。

 

作者简介:周爽,本硕毕业于华中科技大学,先后在华为2012实验室高斯部门和上海行邑信息科技有限公司工作。开发过实时分析型内存数据库RTANA、华为公有云RDS服务、移动反欺诈MoFA等产品。目前担任公司技术部架构师一职。著有《实时流计算系统设计与实现》一书。

 

扫码了解详情并购买

↓↓↓点击“阅读原文”直达开学季促销专场

相关文章:

  • 一个月读完6本书?这些烧脑神书,你能读完1本,就是学霸!
  • 搜索引擎的竞价排名是怎样实现的?
  • 掌握Java核心技术,看我!
  • 【新书速递】斯坦福算法博弈论二十讲
  • 【直播预告】「甦:知识蓄力2020」编辑讲书智慧接力行动
  • 【一周书讯】网络安全、云计算、人工智能、大数据一网打尽
  • 计算机仿真模拟告诉你,为什么现在还不能开学
  • 物联网领域新计算范式技术、架构、应用方面的前沿指南
  • 无处不在的流计算到底是什么?终于有人讲明白了(附导图)
  • 打破VR-AR的“神话” 揭开VR-AR的“现实”
  • 手绘 | 深入解析风控8大场景中的机器学习应用
  • 新时代的大数据处理方式:实时流计算
  • 中央定调,“新基建” 彻底火了!这七大科技领域要爆发
  • “程序媛”女神节,华章图书备厚礼,快来拿礼物
  • 【直播预告】3月7日|新时代的大数据处理方式——实时流计算
  • 《网管员必读——网络组建》(第2版)电子课件下载
  • 【Linux系统编程】快速查找errno错误码信息
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • 0基础学习移动端适配
  • 3.7、@ResponseBody 和 @RestController
  • Android框架之Volley
  • create-react-app做的留言板
  • es的写入过程
  • ES学习笔记(12)--Symbol
  • Idea+maven+scala构建包并在spark on yarn 运行
  • Java到底能干嘛?
  • js
  • JS 面试题总结
  • js如何打印object对象
  • PHP 的 SAPI 是个什么东西
  • Python进阶细节
  • Ruby 2.x 源代码分析:扩展 概述
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • vue学习系列(二)vue-cli
  • 官方解决所有 npm 全局安装权限问题
  • 近期前端发展计划
  • 理解在java “”i=i++;”所发生的事情
  • 如何编写一个可升级的智能合约
  • 入门到放弃node系列之Hello Word篇
  • 昨天1024程序员节,我故意写了个死循环~
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​2021半年盘点,不想你错过的重磅新书
  • ​渐进式Web应用PWA的未来
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • #在 README.md 中生成项目目录结构
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (C语言)fgets与fputs函数详解
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (NSDate) 时间 (time )比较
  • (Ruby)Ubuntu12.04安装Rails环境
  • (第二周)效能测试
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (定时器/计数器)中断系统(详解与使用)