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

使用ArrayList.removeAll(List list)导致的机器重启

背景

先说一下背景,博主所在的业务组有一个核心系统,需要同步两个不同数据源给过来的数据到redis中,但是每次同步之前需要过滤掉一部分数据,只存储剩下的数据。每次同步的数据与需要过滤掉的数据量级大概在0-100w的数据不等。

由于是两个数据源,虽然拿到数据后存数据的代码能共用,但是从数据源拿数据由于协议不同所以还是需要分开写,就安排了两位同事完成这个任务。

重启现象

项目上线大半年,线上运行一直很平稳,突然在某一天ops开始报警该系统的两台机器一直在重启,cpu也一直报警,线上cpu监控如下所示:

机器也处于不断重启中:

两台机器表现几乎一致,于是马上重启一台机器,同时联系ops运维同学帮助临时扩容机器,另外一台机器抓取一下当时的运行详情。直接用下面的火线图更明显:

问题分析

可以看到几乎80%的cpu都在做一件事情:ArrayList.removeAll(),根据线程栈找到了线上的代码大致如下:

protected void updateMeta(String redisField, List<String> oldHotels, List<String> newHotels) {//1.diff两次数据涉及的酒店//2.从老数据中删除新数据oldHotels.removeAll(newHotels);
}

可以看到其实cpu大部分的时间都在执行一行代码oldHotels.removeAll(newHotels),所以可以定位到问题所在。

前面提到我们同步数据其实是有两个数据源的,前面任务堵塞的数据源成为数据源1,另一个数据源称为数据源2,那么为什么数据源2没有阻塞呢?经过定位,发现关于数据源2更新数据的代码大致如下:

    private List<String> calculateNeedDeleteHotelSeqByRedis(String tableName, Set<String> thisHotelSeqs) {List<String> saveHotelSeqs = queryHotelSeqs(STRING_OLD_SEQ_TABLE_PREFIX + tableName);if (CollectionUtils.isNotEmpty(saveHotelSeqs)) {// 删除diff数据saveHotelSeqs.removeAll(thisHotelSeqs);return saveHotelSeqs;}

其实两个方法要做的事情都是一样,只是各自的实现方式不一样,但是都有一个关键的步骤就是从新数据集合中批量删除掉老数据。第一个数据源调用的api是ArrayList.removeAll(List list),第二个数据源调用的api是ArrayList.removeAll(Set set),其实两个api都是同一个api,他的定义为:

//java.util.ArrayList#removeAllpublic boolean removeAll(Collection<?> c) {Objects.requireNonNull(c);return batchRemove(c, false);}

所以,可以看出来其实区别就在于传参类型不同,接下来就需要深究为什么传参类型为List集合时会导致cpu上涨。

通过查询相关资料可以得知:在集合数据比较多的情况下, ArrayList.removeAll(Set)的速度远远高于ArrayList.removeAll(List)!从1百万数据中remove掉30万数据,前者需要0.031秒,后者需要1267秒!

结合以下类图:

从图中可以看到,图中相关的集合类(HashSetLinkedListArrayList),除了ArrayList自己实现了removeAll()方法外,其他两个集合都是借助父类(或超父类)的Iterator迭代器进行删除。接下来再来看一下ArrayList类的removeAll()方法的实现。

    private boolean batchRemove(Collection<?> c, boolean complement) {final Object[] elementData = this.elementData;int r = 0, w = 0;boolean modified = false;try {for (; r < size; r++)if (c.contains(elementData[r]) == complement)elementData[w++] = elementData[r];} finally {// Preserve behavioral compatibility with AbstractCollection,// even if c.contains() throws.if (r != size) {System.arraycopy(elementData, r,elementData, w,size - r);w += size - r;}if (w != size) {// clear to let GC do its workfor (int i = w; i < size; i++)elementData[i] = null;modCount += size - w;size = w;modified = true;}}return modified;}

从火线图中可以看出,主要是卡在执行contains()方法,而contains()方法则是调用入参自身的方法,因此需要对比的是HashSet.contains() vs ArrayList.contains()。

ArrayList.contains()

实现很简单,即调用indexOf(),一个一个地遍历查找。最坏时间复杂度为O(总数据量)

HashSet.contains()

我们知道,HashSet的底层是HashMap,因此,实际也就是调用map.containKey()方法。

大家都知道,HashMap的查找速度非常快!因此,到这里,我们也就解释题目的问题。

 解决方案

在数据量比较大的的情况下,使用arrayList.removeAll(subList)时,可以更改为:

  • subList封装为HashSetarrayList.removeAll(new HashSet(subList))
  • arrayList改为LinkedListnew LinkedList(arrayList).removeAll(subList)

最终我们将数据源一的代码修改如下,解决问题:

protected void updateMeta(String redisField, List<String> oldHotels, List<String> newHotels) {//1.diff两次数据涉及的酒店//2.从老数据中删除新数据// 包装为set集合Set<String> newHotelSet = Sets.newHashSet(newHotels);oldHotels.removeAll(newHotels);
}

相关文章:

使用ArrayList.removeAll(List list)导致的机器重启

背景 先说一下背景&#xff0c;博主所在的业务组有一个核心系统&#xff0c;需要同步两个不同数据源给过来的数据到redis中&#xff0c;但是每次同步之前需要过滤掉一部分数据&#xff0c;只存储剩下的数据。每次同步的数据与需要过滤掉的数据量级大概在0-100w的数据不等。 由…...

如何在项目中使用uni-ui组件库

1、安装uni-ui npm i dcloudio/uni-ui 2、组件自动引用 配置easycom 使用 npm 安装好 uni-ui 之后&#xff0c;需要配置 easycom 规则&#xff0c;让 npm 安装的组件支持 easycom 打开项目根目录下的 pages.json 并添加 easycom 节点&#xff1a; // pages.json {"e…...

redis的过期策略和内存淘汰机制(redis篇)

分享并学习一下redis的过期策略和内存淘汰机制 在平时的工作或者学习中&#xff0c;即便自己没有实打实的用过redis。但是能有对这方面的思考&#xff0c;再结合一些实际场景和理论&#xff0c;那么我相信自己或者你都会越来越厉害的。 首先&#xff0c;我们需要认清为啥redis要…...

Java中Runnable和Callable有什么不同?(企业真题)

Java中Runnable和Callable有什么不同&#xff1f; 与之前的方式的对比&#xff1a;与Runnable方式的对比的好处 call()可以有返回值&#xff0c;更灵活 call()可以使用throws的方式处理异常&#xff0c;更灵活 Callable使用了泛型参数&#xff0c;可以指明具体的call()的返回值…...

图机器学习导论

图&#xff1a;描述关系数据的通用语言&#xff0c;起源于哥尼斯堡七桥问题 传统的机器学习&#xff1a;数据样本之间独立同分布&#xff0c;简单拟合数据边界&#xff0c;在传统的机器学习中&#xff0c;每个数据样本彼此无关。传统的神经网络&#xff0c;只能处理简单的表格、…...

地推网推拉新平台哪家强?一文清楚告诉你

在当今这个充满副业的时代&#xff0c;地推网推拉新平台的寻找与对接成为了许多人关注的焦点。那么&#xff0c;我们应该如何找到那些既靠谱又有潜力的拉新项目呢&#xff1f; 经过深入研究和全网检索&#xff0c;我为大家盘点了5个值得一试地推网推拉新平台。 尤其是“聚小推…...

Day:004(4) | Python爬虫:高效数据抓取的编程技术(数据解析)

XPath工具 浏览器-元素-CtrlF 浏览器-控制台- $x(表达式) Xpath helper (安装包需要科学上网) 问题 使用离线安装包 出现 程序包无效 解决方案 使用修改安装包的后缀名为 rar&#xff0c;解压文件到一个文件夹&#xff0c;再用 加载文件夹的方式安装即可 安装 python若使用…...

(80) 只出现一次的数字(81)反转字符串

文章目录 1. 每日一言2. (80) 只出现一次的数字2.1 解题思路2.2 代码 3. (81)反转字符串3.1 解题思路3.2 代码 4. 结语 1. 每日一言 生活是一场即兴表演&#xff0c;值得庆幸的是我们总是有所感受&#xff0c;并且将一直感受下去。 2. (80) 只出现一次的数字 题目链接&#x…...

基于拉格朗日分布算法的电动汽车充放电调度MATLAB程序

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 程序简介 该模型主要做的是基于拉格朗日分布算法的电动汽车充放电调度模型。利用蒙特卡洛模拟法模拟出电动汽车负荷曲线&#xff0c;并求解出无序充电功率曲线和有序充电曲线&#xff0c;该模型在电动汽车个…...

【Linux 学习】进程优先级和命令行参数!

1. 什么是优先级? 指定进程获取某种资源&#xff08;CPU&#xff09;的先后顺序&#xff1b; Linux 中优先级数字越小&#xff0c;优先级越高&#xff1b; 1.1 优先级和权限的区别&#xff1f; 权限 &#xff1a; 能不能做 优先级&#xff1a; 已经能了&#xff0c;但是获…...

Git删除未跟踪的文件Untracked files

在 Git 中&#xff0c;要删除未跟踪的文件&#xff08;Untracked files&#xff09;&#xff0c;你可以使用 git clean 命令。请注意&#xff0c;这个命令会从你的工作目录中永久删除这些文件&#xff0c;因此在执行之前请确保你不再需要这些文件或已经妥善备份。 以下是如何使…...

S7-1200PLC控制V90伺服通过FB284实现位置控制的方法

S7-1200PLC控制V90伺服通过FB284实现位置控制的方法 通过西门子报文111和FB284功能块 在V-ASSISTANT中将V90 PN设置控制模式为"基本位置控制(EPOS)" V90 PN与PLC采用PROFINET RT通信方式并使用西门子报文111。 在博途中V90 PN的设备视图中更改报文为:报文111 安装…...

2024年阿里云优惠券领取和使用方法

阿里云优惠代金券领取入口&#xff0c;阿里云服务器优惠代金券、域名代金券&#xff0c;在领券中心可以领取当前最新可用的满减代金券&#xff0c;阿里云百科aliyunbaike.com分享阿里云服务器代金券、领券中心、域名代金券领取、代金券查询及使用方法&#xff1a; 阿里云优惠券…...

工业项目中你连PLM系统都没见过?

什么是 PLM 软件&#xff1f; PLM 软件是用于管理全球供应链中产品或服务全生命周期环节的解决方案。它包括从物料、零部件、产品、文档、规定、工程变更单到质量工作流的数据管理。 PLM 的发展历史 从最初的产品设计管理到如今的数字化转型和智能化生产&#xff0c;PLM 在不断…...

【QT入门】 Qt自定义控件与样式设计之QPushButton实现鼠标悬浮按钮弹出对话框

往期回顾&#xff1a; 【QT入门】 Qt自定义控件与样式设计之qss选择器-CSDN博客 【QT入门】 Qt自定义控件与样式设计之QLineEdit的qss使用-CSDN博客 【QT入门】Qt自定义控件与样式设计之QPushButton常用qss-CSDN博客 【QT入门】 Qt自定义控件与样式设计之QPushButton实现鼠标悬…...

C盘变红怎么办?免费的系统C盘清理方法,C盘空间占用克星

百夫说&#xff1a;分享免费又好用的工具&#xff0c;是一件快乐的事情。 正文&#xff1a; 起因&#xff1a;C盘报警&#xff0c;系统变慢 立即下载XX系统清理大师&#xff0c;搜索出垃圾数据近30G&#xff0c;开心的点击“一键清理”&#xff0c;结果提示要收费&#xff1a…...

简述VPS 与 Apache 搭建网站方式对比:新手科普指南

在互联网时代&#xff0c;拥有一个网站对于个人、企业以及组织来说已经成为了必备的一项资源。然而&#xff0c;对于新手来说&#xff0c;如何搭建一个网站可能是一个挑战。在这篇文章中&#xff0c;我将探讨两种常见的搭建网站的方式&#xff1a;使用虚拟专用服务器&#xff0…...

js获取年月份

一、date 如何使用、如何获取年月日时分秒、时间戳、如何获取指定日期的时间戳或周几 1..Date 对象用于处理日期和时间。 创建 Date 对象的语法&#xff1a; var myDatenew Date() 获取年月日时分秒&#xff1a; // 格式化日对象 const getNowDate () > {let date new …...

Promise常用方法及区别

一、实例方法 let _fun new Promise((resolve, reject) > {reject("失败&#xff01;"); }); /* resolve&#xff1a;异步操作成功时调用的回调函数。 reject&#xff1a;异步操作失败时调用的回调函数。 */ _fun.then(res > { // 成功console.log(res: , re…...

pyqt 标题栏设置

在PyQt中&#xff0c;可以通过QWidget或其子类&#xff08;如QMainWindow或QDialog&#xff09;的setWindowTitle()方法来设置窗口的标题栏。以下是一个简单的例子&#xff0c;展示了如何为应用程序的主窗口设置标题&#xff1a; import sys from PyQt5.QtWidgets import QApp…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

GeoServer发布PostgreSQL图层后WFS查询无主键字段

在使用 GeoServer&#xff08;版本 2.22.2&#xff09; 发布 PostgreSQL&#xff08;PostGIS&#xff09;中的表为地图服务时&#xff0c;常常会遇到一个小问题&#xff1a; WFS 查询中&#xff0c;主键字段&#xff08;如 id&#xff09;莫名其妙地消失了&#xff01; 即使你在…...

C++ 类基础:封装、继承、多态与多线程模板实现

前言 C 是一门强大的面向对象编程语言&#xff0c;而类&#xff08;Class&#xff09;作为其核心特性之一&#xff0c;是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性&#xff0c;包括封装、继承和多态&#xff0c;同时讨论类中的权限控制&#xff0c;并展示如何使用类…...