精华内容
下载资源
问答
  • 2019-08-24 09:48:58

    背景:

    经过实验,每次删除400万条要花1.5 - 3小时,而且是越到后面越慢,正常的话,需要大约102个小时,大约4天半时间。这在生产环境下是不能接受的。

    产生原因:

    每次删除记录,数据库都要相应地更新索引,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的;这是很慢的IO操作,而且后面索引碎片越来越多,就更慢,这就是为什么一开始只花1.5小时,后面要3小时才能删除400万条记录的原因。

    【注意】记得在删除的时候不要在记录日志的模式下面,否则日志文件就要爆了。

    方法一:

    MySQL原文处理方案链接:https://dev.mysql.com/doc/refman/8.0/en/delete.html
    在这里插入图片描述
    简单翻译下:
    删除大表的多行数据时,会超出innod block table size的限制,最小化的减少锁表的时间的方案是:
    1、选择不需要删除的数据,并把它们存在一张相同结构的空表里 :INSERT INTO t_copy SELECT * FROM t WHERE … ;
    2、重命名原始表,并给新表命名为原始表的原始表名: RENAME TABLE t TO t_old, t_copy TO t;
    3、删掉原始表:DROP TABLE t_old;

    方法二:

    在实际操作过程中,如果不在乎时间(利用下班时间定时删除),可以利用limit分批次删除:

    假设有一个表(syslogs)有1000万条记录,需要在业务不停止的情况下删除其中statusid=1的所有记录,差不多有600万条, 直接执行 DELETE FROM syslogs WHERE statusid=1 会发现删除失败,因为lock wait timeout exceed的错误。

    因为这条语句所涉及的记录数太多,因此我们通过LIMIT参数分批删除,比如每10000条进行一次删除,那么我们可以利用MySQL这样的语句来完成:
    DELETE FROM syslogs WHERE status=1 ORDER BY statusid LIMIT 10000;
    然后分多次执行就可以把这些记录成功删除。

    注:

    • 执行大批量删除的时候注意要使用上limit。因为如果不用limit,删除大量数据很有可能造成死锁。
    • 如果delete的where语句不在索引上,可以先找主键,然后根据主键删除数据库。
    • 平时update和delete的时候最好也加上limit 1 来防止误操作。

    ***注:有参考其他论坛,博客,文章仅供自我学习; ***

    更多相关内容
  • 在上一篇文章 《漫谈千亿级数据优化实践:数据倾斜(纯干货)》中,我们分享了一些在千亿级数据优化实践中和数据倾斜相关的内容。本文将分享千亿级数据优化的另个一点:如何使用使用数据! 注意: 本文会限定...

    0x00 前言

    即使没有数据倾斜,千亿级的数据查询对于系统也是一种巨大负担,对于数据开发来说,如何来优化它,既是挑战,也是机遇!

    在上一篇文章 《漫谈千亿级数据优化实践:数据倾斜(纯干货)》中,我们分享了一些在千亿级数据优化实践中和数据倾斜相关的内容。本文将分享千亿级数据优化的另个一点:如何使用使用数据!

    注意:

    1. 本文会限定一些业务场景和技术架构,因此解决方法会局限于此。很多问题可以通过换架构或者引入新的组件来解决,但是成本可能会很高,因此暂不考虑。
    2. 本文不是一篇Hive使用和优化文档,更侧重于梳理笔者的思路,让大家少走些坑。

    文章主题

    在流行的大数据领域中,Hive绝对占据了很大的一片天地,不管是数据仓库和数据分析,还是数据挖掘和机器学习,凡是需要和大数据量打交道的童鞋们,基本上都要接触Hive。因此,本文将侧重于千亿级数据在Hive中的使用,并通过一个典型的数据使用难题来总结一些在大规模数据场景下的优化方式。

    本文主要以一个具体的使用场景为切入点,为了解决该场景下的使用难题,笔者经理了一次次的尝试+失败,最终找到了一种相对比较合适的方式。

    文章结构

    本文可以看过是一种记录和思考,完全还原笔者在遇到问题时的解决方式。因此全文会以事情的发展为主线,每次尝试一种解决方法,失败后继续查找新的方法,中间会穿插一些技术细节。

    文章主线如下:

    1. 明确使用场景和困难。
    2. 如何解决,这是一个不断推翻重来的过程。
    3. 回顾总结

    0x01 问题来了!

    本章作用主要有二:

    1. 明确业务背景和使用场景
    2. 明确困难所在

    1. 业务背景和使用场景

    按照惯例,我又来到了一家电商网站来工作,我们有一张十分重要的表:用户和购买过的商品表。

    如下图,该表只有三个字段,分别是用户ID、商品ID。我们可以简单地理解这是一张事实表。对事实表没印象的可以参考这篇《漫谈数据仓库之维度建模》

    我们暂且不管当初为何这样设计的,现在的情况就是

    列名字段类型
    user_idstring
    product_idstring

    这张表有哪些使用场景呢:

    1. 输入一批用户,找到和他们有相似购买行为的用户
    2. 统计用户购买商品的数据区间
    3. ……

    总之这张表能用到的地方是极多的,相信数据分析和数据挖掘的童鞋们肯定能想到很多场景,这里就不展开讲了。

    问题来了: 数据量太大,随便一个查询就是五六个小时,有没有办法优化?

    2. 困难

    先说明一下问题在哪。

    数据量大

    这张表里面保存了我站来自全球的50亿用户和他们购买过的商品,粗略估计一下,人均会购买60件商品,也就是说这张表有 3000亿 的数据。

    3千亿条记录是什么概念呢,如果存成没有压缩的txt文件的话,大致有30T以上。如果做一个压缩,我们保守一点估计,要有接近10T的数据。

    查询速度慢

    这么大数据量,查询起来的确比较慢。可能随便跑一个数据,就要3到5个小时。

    我们可以大致地分析一下慢的原因:

    1. 扫描数据量大
    2. join的时候时间长
    3. 因为我们的reduce数量右限制,每个reduce需要处理的数据量太多
    4. shuffle的时候效率太低。

    0x02 解决过程

    我们在解决这个难题的时候是围绕一些出发点的:

    1. 减少扫描的数据量
    2. 加快关联查询的速度

    1. 分区

    第一个思路就是分区,我们可以根据用户的账号分布来进行分区,然后在扫描的时候,只扫描部分分区就行。 好,我们做一个设计。

    我们美好的愿望是:假设有一个需求需要查询一定的用户的购买记录,我们不用扫描全量的数据,只扫描其中一部分即可。

    下面我们基于几个设定来设计我们的分区规则:

    • 假设我们的用户id都是数字类型的,如下图。
    • 我们按照账号的id来设计分区函数,比如说前四位相同的放在一个分区中。
    • 写入数据,和查询数据使用相同的分区函数

    这样我们就有了1万个分区,每个分区中有30万用户的购买记录,也就是说每个分区中会有1800万的记录数,总计约1G的文件大小。

    下面就是我们设计出来的分区。

    我们的想法是好的,下面举几个场景:

    1. 比如现在需要查100个用户的数据,不分区的话,我们需要扫描全量的数据,现在我们可能只要扫描10个分区,最多100个分区,也就是我们的速度回提升100倍以上。
    2. 需要查1万个用户的数据,我们假设会命中1000个分区。
    3. 需要查10万个用户的数据,我们假设会命中5000个分区。

    例子我都举不下去了,实际情况是,如果用户分布比较分散的话,超过20万个用户的话,基本上就命中了所有了分区了。 这个感兴趣的可以测一下。

    增加分区数?

    这个方案是可以的,比如我们变成10万个分区,这样当然可以,但是让需要查询的用户多的话,效果照样变弱,而且更多的分区意味着每个分区的数据会变少,这样小文件就会多很多。

    结论

    分区的方式不靠谱!

    2. 索引

    注意: Hive的索引也是个坑,怪不得没人用,但是我们还是要设计一下。

    基于“减少扫描的数据量”这点来讲,索引是一种极妙的方式,有了索引,我们就不必全量扫描所有的数据,速度肯定就快了呀。 但是, Hive的索引是个坑。

    下面讲一下Hive索引的机制就明白了。

    Hive索引机制

    在指定列上建立索引,会产生一张索引表(Hive的一张物理表),里面的字段包括,索引列的值、该值对应的HDFS文件路径、该值在文件中的偏移量。

    如下,是Hive的索引表。其中,索引表中key字段,就是原表中key字段的值,_bucketname 字段,代表数据文件对应的HDFS文件路径,_offsets 代表该key值在文件中的偏移量,有可能有多个偏移量,因此,该字段类型为数组。

    列名字段类型
    user_idstring
    _bucketnamestring
    _offsetarray < bigint >

    在执行索引字段查询时候,首先额外生成一个MR job,根据对索引列的过滤条件,从索引表中过滤出索引列的值对应的hdfs文件路径及偏移量,输出到hdfs上的一个文件中,然后根据这些文件中的hdfs路径和偏移量,筛选原始input文件,生成新的split,作为整个job的split,这样就达到不用全表扫描的目的。

    注意: 按照上面的说明,我们的索引其实就是另一张Hive的表,而且数据量还是很大。 下面从两个点说明Hive的索引方案不能用。

    1. 经过测试,索引表就有4、5T,我们在查询的时候,要先和这张索引表做关联,然后再和原表做关联,损失太大了。
    2. HDFS文件系统的设计问题。会导致最终我们扫描的还是全表。为什么?下面讲解。

    HDFS的设计

    我们默认大家对HDFS原理有所认知。这里只说一下这次我们优化的内容。

    假设我们10T的数据,按照128M一个文件块,那就是我们有七八万个文件块。和前面的分区的情况类似,当需要查询的用户数量到一定程度,基本上还是要扫描所有的文件块。

    结论

    索引的方式不靠谱,至少Hive中不可用。

    索引的使用方式,就不再描述了,看官网还是挺简单的:Hive官网:Index

    3. 分桶

    分桶就不再说了,和前面说的问题类似,也不可用。

    到这里我就绝望了,有打算不解决了。准备用最初的一招:按活跃度区分。

    4. 区分活跃用户

    这也是一种很值得考虑的方式,因为我们大部分对数据的使用都会考虑活跃用户,这里我们把30亿用户中活跃的10亿的用户抽出来放一个分区,这样的话,我们的查询效率能提高3倍左右。

    问题

    1. 活跃用户不好定义,每个业务方的定义不一样。
    2. 运行成本太大,跑这个数据挺耗时间。

    结论

    这是一种方法,如果没有更好的方法就用这个了。

    5. 数据结构

    受大神的指点,我们更换了一种在Hive中的存储方式,现在更新表如下

    列名字段类型
    user_idstring
    product_listarray< string >

    这是一个很简单的转表,我们使用了Hive中的数据结构Array,把一个用户的所有购买过的商品放入到一个字段中,这样的话,我们的总数据量就只有30亿了,在做关联查询的时候速度必然很快。

    实践

    经过实践,这样的存储,只需占用之前存储量的1/2左右,也就是只需要不到5T的大小,查询速度从平均一个任务4个小时缩减到半个小时。

    问题

    这里有两个问题:

    1. 数据更新,数据结构的改变导致在更新数据的时候有一些障碍,这点不再展开,方法总是有的,笔者是保留了两份数据,这一份专门供查询用。

    2. 使用成本增加,因为数据结构变了,相应的查询sql也要调整。 这里就需要用到lateral view explode,详情可看官网

    总结

    总的来接,这种方式还是可行的,目前的反馈还都是正向的,额外的sql复杂度不是很大,大部分童鞋都能接收。

    0xFF 总结

    本文主要是描述了一次千亿级数据量查询优化的过程,回头来看,其实也听简单的,但是身在其中未必能想清楚,这也和经验有关,因此走了很多的弯路。

    总的来讲,笔者尝试了5种方式:分区、索引、分桶、活跃度区分、新的数据结构。最后一种方式基本解决了遇到的问题。

    本文对一些技术细节没有过多描述,比如建索引,建表,这些在官网很容易找到,因此不再过多涉及。思想到位了,其它的问题都不大。

    参考


    作者:木东居士 |简书 | CSDN | GITHUB

    个人主页:http://www.mdjs.info
    也可以关注我:木东居士。

    文章可以转载, 但必须以超链接形式标明文章原始出处和作者信息

    展开全文
  • springboot easyexcel导出百万数据优化

    千次阅读 2020-09-28 19:44:13
    由于某些原因系统jvm内存最大只能给到512,但是要导出百万数据该如何实现呢?传统的一次性导出肯定是不行的 优化 Excel导出基于 springboot , easyexcel 依赖: <dependency> <groupId>...

    说明

    由于某些原因系统jvm内存最大只能给到512,但是要导出百万数据该如何实现呢?传统的一次性导出肯定是不行的

    优化

    Excel导出基于 springboot , easyexcel
    依赖:

    <dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>easyexcel</artifactId>
    			<version>2.2.6</version>
    		</dependency>
    

    导出优化

    基于自增id滚动式查询写入

    @GetMapping("/standard-product-ext/export")
        public void productExtExport(HttpServletResponse response, StandardProductExtQuery query) throws Exception{
    
            String today = DateUtil.today();
            String fileName = "标准商品标签导入模板" + today;
            String fileNameCode = URLEncoder.encode(fileName, "UTF-8");
    
            response.setContentType("application/force-download");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileNameCode + ".xlsx");
            ExcelWriter writer = new ExcelWriterBuilder()
                    .autoCloseStream(true)
                    .file(response.getOutputStream())
                    .head(DscStandardProductExtVO.class)
                    .build();
            Integer lastBatchMaxId = 0;
            query.setLastBatchMaxId(lastBatchMaxId);
            WriteSheet writeSheet = new WriteSheet();
            writeSheet.setSheetName("标准商品标签导入模板" + today);
            List<DscStandardProductExtVO> productExt
            for (; ; ) {
                productExt = dictionaryService.getProductExt(query);
                if (productExt.isEmpty()) {
                    writer.write(productExt, writeSheet);
                    writer.finish();
                    break;
                } else {
                    lastBatchMaxId = productExt.stream().map(DscStandardProductExtVO::getId).max(Integer::compareTo).orElse(Integer.MAX_VALUE);
                    query.setLastBatchMaxId(lastBatchMaxId);
                    writer.write(productExt, writeSheet);
                }
    
    
            }
        }
    
    • dictionaryService.getProductExt(query) 的xml
    SELECT
           *
            FROM
            base_drug
            where
            id > #{lastBatchMaxId}
    

    导入优化

    • 使用 easyexcel 监听器导出
    @PostMapping("/standard-product-ext/import")
        public ResponseResult productExtImport(MultipartFile file) throws IOException {
    
            File localFile = new File(appSettings.getTempdir() + RandomStringUtils.randomAlphanumeric(12) + file.getOriginalFilename());
            // 将上传文件 写入到 localFile  本地文件,后续对 localFile 操作读取
            FileUtils.multipartFileToFile(file, localFile);
            try {
                ExcelUploadResult excelUploadResult = dictionaryService.updateBatchProductExtByFile(localFile);
                return ResponseUtils.success(excelUploadResult);
            } catch (DaoException e) {
                ResponseUtils.fail(ErrorCodeConstants.FAIL, "导入标准商品标签失败");
            }
            return null;
    
        }
    
    

    dictionaryService.updateBatchProductExtByFile(localFile) 方法

    public ExcelUploadResult updateBatchProductExtByFile(File excelFile) throws DaoException{
            StandardProductExtListener listener = new StandardProductExtListener(clearSearchDao,
                    dscStandardProductExtDao, cosUtils, appSettings);
            try {
                EasyExcel.read(excelFile, DscStandardProductExtVO.class, listener).sheet().doRead();
            } catch (Exception e) {
                log.error("[标签导入]读取excel出错", e);
                throw new ServiceException("excel导入失败");
            } finally {
                if (excelFile.exists()) {
                    excelFile.delete();
                }
            }
            int successTotal = listener.getSuccessTotal();
            int total = listener.getTotal();
            int error = listener.getError();
            ExcelUploadResult result =  error > 0 ? new ExcelUploadResult(total, successTotal,error, listener.getErrorFileUrl())
            : new ExcelUploadResult(successTotal, total, 0, null);
            return result;
        }
    
    • StandardProductExtListener

    需要注意的是 StandardProductExtListener 不能被spirng管理,需要手动new,依赖spring的类通过构造方法注入,这里是官方说明的,如果给spirng管理会有什么问题暂时没有尝试

    public class StandardProductExtListener extends AnalysisEventListener<DscStandardProductExtVO> {
    
    
        int successTotal = 0;
        int total = 0;
        int error = 0;
        String errorFileUrl;
    
        List<DscStandardProductExtVO> list = new ArrayList<>();
    
        ClearSearchDao clearSearchDao;
    
        DscStandardProductExtDao dscStandardProductExtDao;
    
        CosUtils cosUtils;
    
        AppSettings appSettings;
    
        List<DscStandardProductExtVO> errorList = Lists.newArrayList();
    
        public StandardProductExtListener(ClearSearchDao clearSearchDao, DscStandardProductExtDao dscStandardProductExtDao,
                                          CosUtils cosUtils, AppSettings appSettings) {
            this.clearSearchDao = clearSearchDao;
            this.dscStandardProductExtDao = dscStandardProductExtDao;
            this.cosUtils = cosUtils;
            this.appSettings = appSettings;
        }
    
    
    
    
        /**
         * 每条数据的解析
         * @param vo
         * @param analysisContext
         */
        @Override
        public void invoke(DscStandardProductExtVO vo, AnalysisContext analysisContext) {
            list.add(vo);
            if (list.size() > 3000) {
                try {
                    doFile(list);
                    total += list.size();
                    list.clear();
                } catch (DaoException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            try {
                total += list.size();
                doFile(list);
                log.info("处理最后数据{}", total);
                errorFileUrl = updateErrorFile();
            } catch (DaoException e) {
                e.printStackTrace();
            }
        }
    
        public void doFile(List<DscStandardProductExtVO> readExcels) throws DaoException{
           // 业务逻辑处理
           }
    
    
    }
    

    总结

    经过测试 导出百万数据 使用这两种优化没什么问题,只是导入速度可能有点慢,但是不会OOM,其次可能系统full gc会相对严重。

    关于我

    觉得文章不错请扫码关注我吧

    weichat

    展开全文
  • Spark处理百亿规模数据优化实战

    万次阅读 多人点赞 2018-07-24 11:15:33
    优化是生产环境下用Spark处理百亿规模数据的一些优化实战,并成功将程序的速度提升一倍(涉及到敏感信息本文在2018-07-04号将其删除,阅读上可能显得不完整)下面介绍一些基本的优化手段 本文于2017-07-16号书写 ...

    本优化是生产环境下用Spark处理百亿规模数据的一些优化实战,并成功将程序的速度提升一倍(涉及到敏感信息本文在2018-07-04号将其删除,阅读上可能显得不完整)下面介绍一些基本的优化手段

    本文于2017-07-16号书写

    Spark任务优化

    本节主要从内存调优、高性能算子、数据结构优化、广播大变量和小表调优、动态并行度调优、Spark文件切分策略调优来介绍Spark处理大规模数据的一些优化实践。

    1 内存调优

    由于任务数据量大且会发生数据膨胀,如果内存参数设置不合理,任务容易出现OOM,分析Spark1.6.2内存管理模型如下图所示,知道Spark如何管理自己的内存我们才能进行更好的调优。

    内存调优详见:Spark统一内存管理:UnifiedMemoryManager

    任务任务内存参数配置:

    spark.driver.memory=6g(存在广播所以Driver设置的较大)
    spark.executor.memory=13G
    spark.memory.fraction=0.4

    内存参数配置计算公式:
    Execution Memory 2.5G =(Heap size(13G)- Reserve Memory(450M))* spark.memory.fraction 0.4 * spark.memory.storageFraction 0.5
    用户主导的空间:User Memory 7.5G =(Heap size(13G)- Reserve Memory(450M))* (1 - spark.memory.fraction 0.4)
    安全因子:0.9,考虑到内存空间使用和预估的准确度,实际应用过程中会考虑加入一个安全因子。
    可用用户主导空间:User Memory * 0.9 = 6.8G(根据实际情况,数据条数 * 每条数据任务后占用内存最大值,基于此评估一个最大值,如果超过这个值就会出现OOM)
    效果:解决程序OOM问题,因为任务过程维护了大的数据结构,其主要使用了User Memory的空间,用Spark默认内存配置会导致用户空间OOM。

    2 高性能算子

    任务是同一个用户的行为数据,分布式处理需要把一个用户的数据抓取到一个节点上处理,有Shuffle操作,如下图所示同源数据采用groupByKey时Shuffle Write数据量3.5T,aggregateByKey时Shuffle Write数据量3T,相比节省时间2~3min。
    分析数据分布的特征,同一个设备的数据一般在一个文件出现的概率较大,将groupByKey算子改成 aggregateByKey,首先进行了一个Map端的聚合,减少了网络传输的数据量。

    模拟代码:
    val initialSeq = mutable.Seq.empty[Row]
    val addToSeq = (s: mutable.Seq[Row], v: Row) => s :+ v // Map端本地聚合
    val mergePartitionSeqs = (p1: mutable.Seq[Row], p2: mutable.Seq[Row]) => p1 ++ p2 // Reduce端聚合
    kv.aggregateByKey(initialSeq)(addToSeq, mergePartitionSeqs)

    效果:减少网络传输数据量,时效性提升了2~5min,降低网络异常导致任务失败的风险。

    3 数据结构优化

    任务代码中,采用更加节省内存的数据结构,例如聚合的key、最短路径中的索引(如下模拟代码所示)等多处采用字符串拼接实现,避免自定义对象封装数据,尽可能使用轻量的Array而不是HashMap等
    效果:节省内存。

    4 广播大变量和小表调优

    任务任务为什么需要广播?我们先看一下广播的原理,如下图Executor端用到了Driver的List,如果广播List则每个Executor中只有一份Driver端的变量副本。如果不广播List,Executor有多少task就有多少Driver端的变量副本。如果对小表广播能实现本地Join,避免sortMergeJoin(如果使用SparkSQL发现不广播可以加上这个参数:spark.sql.statistics.fallBackToHdfs=true)。

    任务过程需要关联一些小的维表或定义一些大的变量,并存在大量task,所以需要广播。
    效果(1)降低网络传输的数据量;(2)降低内存的使用;(3)加快程序的运行速度。
    通过如上四种Spark任务优化,使任务运行更加稳定,同时也节省了内存。

    5 动态并行度调优

    数据量节假日数据量明显增大,是正常值的1~2倍,为了保障数据稳定生产,任务链条包括“数据清洗任务”和“任务任务”,“数据清洗任务”主要是从百亿条数据清洗出任务需要的50亿~100亿数据,并且把上游上万个大小不同的文件合并成固定个数和大小,这个任务产出的文件个数和大小对“任务任务”是有影响的,如何确定这个文件大小和个数?
    在数据量相同且资源配置相同条件下,要保证任务在1h内完成,测试单Task处理不同文件大小或不同数据条数的执行情况:
    (1)处理文件大小200M~256M左右,每个Task处理条数大概60万左右,Task平均执行时长8~10min;如图:每个Task处理文件大小为247M,其中75%的Task执行时长为10min,而且max值为17min,就算max失败,Task失败重新执行也不会影响到任务整体结束时间。


    (2)处理文件大小256~285M左右,每个Task处理条数大概70万左右,Task平均执行时长12min左右;如图:每个Task处理文件大小为271M,其中75%的Task执行时长为12min,而且max值20min,Task失败重新执行对任务整体时效性有影响。

    (3)处理文件大小300M~350M时,每个Task处理数据条数80万左右,Task平均执行时长17min左右。如图:每个Task处理文件大小313M,其中75%的Task执行时长为17min,而且max值太大,这样就拖慢了整个运行过程。

    通过大量测试发现,Task平均执行时长8~10min,每个Task处理条数大概60万左右时任务任务遇到失败Task、慢节点、某台机器故障等在开启慢任务推测情况下表现较优。

    慢任务推测参数配置:
    spark.speculation=true
    spark.speculation.interval=60s
    spark.speculation.multiplier=1.3
    spark.speculation.quantile=0.99

    基于如上测试,对“数据清洗任务”产出文件数量进行动态调整,让文件大小尽量在200M~256M左右,文件数量和大小,可以根据历史数据条数、文件个数、每个文件大小,考虑节假日等情况去预估,当然也可以采用机器学习等算法去预测。比如简单计算:本周日文件个数 = 上周日数据总条数/60万 ,因为数据清洗任务后数据量大概是50亿~100亿条,所以文件个数阈值为[7000,16000]
    依据每个Core处理2~3个Task,每个Task处理60万条数据文件大小为200~256M表现较好,开启了Executor动态资源分配功能如下:

    spark.dynamicAllocation.minExecutors=1000
    spark.dynamicAllocation.maxExecutors=1600

    参数:spark.default.parallelism是控制Shuffle并行度的,从而会影响Spark Task个数,间接影响文件产出个数。
    “数据清洗任务”是一个离线按天执行的任务,通过动态调整spark.default.parallelism的值保证产出文件个数和大小。
    “核心任务”是一个离线按天执行的任务,通过动态调整spark.default.parallelism的值,进一步保证任务过程每个Task处理的文件维持在256M左右,数据条数维持在60万左右。
    效果:避免了节假日任务执行超时/任务失败,保证生产耗时的相对平稳。
    通过如上参数调整,提高并缩短了生产耗时稳定性,主要是扩大Executor个数(资源才是王道),生产耗时缩短到了31min左右,如下图所示

    6 Spark文件切分策略调优

    ORC文件切分详见:spark 读取ORC文件时间太长(计算Partition时间太长)且产出orc单个文件中stripe个数太多问题解决方案

    任务任务上游的“数据清洗任务”,会清洗出任务需要的有效数据,并且对上游上万个小文件进行合并压缩成ORC文件,其文件大小在256M左右。

    1)任务任务遇到问题:作业提交后ApplicationMaster(Driver)启动了,Spark任务长时间占用资源,SparkUI看不到DAG图、Stage、Partition和Task相关的信息。
    2)问题分析:Driver启动,但是Executor没干活,说明问题出在了Driver,Driver干什么呢?定位到Driver在计算Partition,发生了Full GC,于是问题定位到了Spark读取文件的方法OrcInputFormat.java。
    3)通俗描述:老大(Driver)管理小弟(worker)干活,本来是老大把活分给小弟就可以了,但是老大一直在了解小弟的情况,自己很忙小弟很闲。
    4)问题跟踪:查看OrcInputFormat.java发现Spark读取ORC文件有三种策略,默认采用HYBRID策略(HiveConf.java有相关配置信息):Spark Driver启动的时候,会去nameNode读取元数据,根据文件总大小和文件个数计算一个文件的平均大小,如果这个平均值大于默认256M的时候就会触发ETL策略。ETL策略就会去DataNode上读取orc文件的head等信息,如果stripe个数多或元数据信息太大就会导致Driver 产生FUll GC,这个时候就会表现为Driver启动到Task执行间隔时间太久的现象。
    5)解决方案:控制文件大小为256M左右,改变文件切分策略为BI,控制stripe大小。

    // 创建一个支持Hive的SparkSession
    val sparkSession = SparkSession
    .builder()
    .appName("PvMvToBase")
    // 默认64M,即代表在压缩前数据量累计到64M就会产生一个stripe。与之对应的hive.exec.orc.default.row.index.stride=10000可以控制有多少行是产生一个stripe。
    // 调整这个参数可控制单个文件中stripe的个数,不配置单个文件stripe过多,影响下游使用,如果配置了ETL切分策略或启发式触发了ETL切分策略,就会使得Driver读取DataNode元数据太大,进而导致频繁GC,使得计算Partition的时间太长难以接受。
    .config("hive.exec.orc.default.stripe.size", 268435456L)
    // 总共有三种策略{"HYBRID", "BI", "ETL"}), 默认是"HYBRID","This is not a user level config. BI strategy is used when the requirement is to spend less time in split generation as opposed to query execution (split generation does not read or cache file footers). ETL strategy is used when spending little more time in split generation is acceptable (split generation reads and caches file footers). HYBRID chooses between the above strategies based on heuristics."),
    // 如果不配置,当orc文件大小大于spark框架估算的平均值256M时,会触发ETL策略,导致Driver读取DataNode数据切分split花费大量的时间。
    .config("hive.exec.orc.split.strategy", "BI")
    .enableHiveSupport()
    .getOrCreate()

    调整这个参数可控制单个文件中stripe的个数,不配置单个文件stripe过多,影响下游使用,如果配置了ETL切分策略或启发式触发了ETL切分策略,就会使得Driver读取DataNode元数据太大,进而导致频繁GC,使得计算Partition的时间太长难以接受。
    问题根源Driver压力太大,Worker启动了也只能闲等Driver忙完了,进行分配调度。
    效果:提升了任务稳定性。

    7 使用Kryo序列器(真正上线未用,发现有时候表现好有时候表现不好,存在不稳定性)

    使用Kryo序列化类库,来优化序列化和反序列化的性能。Spark默认使用的是Java的序列化机制,也就是ObjectOutputStream/ObjectInputStream API来进行序列化和反序列化。但是Spark同时支持使用Kryo序列化库,Kryo序列化类库的性能比Java序列化类库的性能要高很多。官方介绍,Kryo序列化机制比Java序列化机制,性能高10倍左右。Spark之所以默认没有使用Kryo作为序列化类库,是因为Kryo要求最好要注册所有需要进行序列化的自定义类型,因此对于开发者来说,这种方式比较麻烦。
    以下是使用Kryo的代码示例,我们只要设置序列化类,再注册要序列化的自定义类型即可(比如算子函数中使用到的外部变量类型、作为RDD泛型类型的自定义类型等):

    // 创建SparkConf对象。
    val conf = new SparkConf().setMaster(...).setAppName(...)
    // 设置序列化器为KryoSerializer。
    conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    // 注册要序列化的自定义类型。
    conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))

    算法优化

    优化方案
    核心理念:归因过程数据膨胀,如何以节省内存的方式去归因,是算法优化的关键。
    核心思想:数学分而治之思想+索引技术灵活运用。
    算法描述:不变的字段单独维护且只维护一份,供查询使用(如Array1),任务新增的字段单独封装维护在(Array2),轻量级的Array2参与任务的计算过程,任务完成,通过Array1和Array2之间的索引把数据打通落盘。

    展开全文
  • 倾斜摄影数据的普及伴随着数据量的增加,数据量的增加又导致网络客户端访问三维数据的效率下降,所以不管是在PC端,Web端还是移动端进行倾斜摄影数据的浏览应用都需要对倾斜摄影数据进行优化,以达到最佳的访问效果...
  • 废话不多说直接上代码;mapper文件中:  INSERT INTO tb_vehicle_tag ...list中的数量:2000条一次,循环50次完成插入十万条数据用时:6秒左右 所以建议对数据量过大的情况下可采用分批插入效率会更好;
  • 读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇...
  • mysql亿级数据优化

    千次阅读 2015-09-13 12:15:49
     1.mysql千万级别数据肯定是没问题的,毕竟现在的流向web2.0网站大部分是mysql的  2.合理分表也是必须的,主要涉及横向分表与纵向分表,如把大小字段分开,或者每100万条记录在一张表中等等,像上面的这个表可以考虑...
  • Vue - Table表格渲染上千数据优化

    万次阅读 多人点赞 2019-05-29 18:12:45
    Vue - Table表格渲染上千数据优化 这次项目经验会谈谈经常在项目中,针对成千上万数据渲染优化的不断探索来谈谈自己的体会,其目的就是保证用户浏览上万条数据的时候,UI要很流畅,确保用户操作过程中不会出现UI...
  • 数据分析--优化模型

    千次阅读 2021-12-09 16:50:04
    (1)规划模型(目标规划、线性规划、非线性规划、整数规划、动态规划) (2)排队论模型 ...(4)现代优化算法(遗传算法、模拟退火算法、蚁群算法、禁忌搜索算法) (5)图论模型 (6) 组合优化模型 ...
  • oracle插入大量数据优化方式

    千次阅读 2019-02-19 23:52:46
    1. 使用绑定变量优化插入速度 未优化前代码如下 create table t(x int); create or replace procedure proc1 as begin for i in 1 .. 100000 loop execute immediate 'insert into t values('||i||')'; commit...
  • MySQL千万级数据优化方案

    千次阅读 2020-02-19 21:52:30
    前言 ...千万级大表如何优化,这是一个很有技术含量的问题,通常我们的直觉思维都会跳转到拆分或者数据分区。除此之外,还有其他的思路和解决方案。根据本人多年的工作经验,做了如下总结。 方案 ...
  • 性能之Hibernate大批量保存数据优化

    万次阅读 2017-03-22 15:02:52
    开心一笑【跟我妈说这几天特别郁闷,心情糟透了。...】提出问题真实项目中,批量插入数据性能优化???解决问题1.业务场景1.1 业务描述数据库有一张表(pm_testcase),客户有一份excel数据,里面有3+万条左右案例。
  • C# Dapper批量插入大量数据优化

    万次阅读 2019-07-09 18:19:09
    以三万条数据为例: Dapperr的Excute方法执行插入语句的本质是一条一条的插入,当数据...优化前的批量导入: //_vfsContext.Conn.Open(); //var tran = _vfsContext.Conn.BeginTransaction(IsolationLevel.Seria...
  • 白亿条数据量的Oracle数据库如何优化?

    千次阅读 多人点赞 2022-01-04 06:44:25
    Oracle的SQL性能的方法做了详细阐述!
  • Mysql千万级别数据存储优化

    万次阅读 2020-04-11 12:00:16
    因为公司是做短信业务的,随着数据量的增加每天新增数据将近200w+,数据全部存放至Mongodb中,总数据量将近3.2亿,业务查询相关出现缓慢,于是决定将一周以前的数据存储至Mysql中并对其进行优化处理。 公司内部方案...
  • 前端处理上万条数据优化

    千次阅读 2019-08-19 19:33:24
    最近碰到一面试题给了一个请求接口,没有分页,一共一万条数据,并且让前端渲染在页面上,这个场景一般在实际应用场景不多见,一般后端都会设置分页查询,但是面试官考的就是前端对于大量数据的处理能力。...
  • Mysql - 百万级数据查询优化笔记 (PHP Script) ②

    万次阅读 多人点赞 2020-12-17 11:13:48
    Mysql - 百万级数据查询优化笔记 (PHP Script) ② 说明:要处理的是在一个脚本中统计的年度账单,和上一篇的处理思路完全 不同,先把全量取出,再按字典形式拼接,10w条数据只需要668s! 数据: 测试服:17w 正式服:...
  • 数据库优化 - SQL优化

    万次阅读 多人点赞 2019-11-01 21:00:00
    以实际SQL入手,带你一步一步走上SQL优化之路!
  • 通过上述优化,第一次查询一个从未查过的数据时间为2-3s,之后翻页或者查询第二次,时间均为1s以内。 redis相关命令 运行cmd 然后到redis路径 运行命令: redis-server redis.windows.conf 启动...
  • MYSQL UPDATE 语句求优化(百万+数据

    千次阅读 2019-08-12 10:20:51
    UPDATE t_comment com SET com.create_time=(SELECT finish_time FROM t_order o where o.order_id=com.order_id); t_comment 表中相关索引 : ...执行执行上万条数据的时候就相当慢了 求帮助
  • 当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下: 限定数据的范围:务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的...
  • ES大数据量下查询优化

    千次阅读 2020-09-18 10:43:46
    很多时候数据量大了,特别是有几亿条数据的时候,可能你会懵逼的发现,跑个搜索怎么一下5~10s,坑爹了。第一次搜索的时候,是5~10s,后面反而就快了,可能就几百毫秒。 你就很懵,每个用户第一次访问都会比较慢,...
  • 关于MySQL百万级数据量查询的...开始只是用最普通的方法来查询,当测试数据有19万条的时候,整个查询数据异常的慢,完全查询的汇总甚至要两分多,自此开始了各种优化。 1. 程序的优化 以最简单的一张表,需要...
  • 分区是Oracle数据库中对海量数据存储管理提供的一个应用很广泛的技术,它可以非常方便的加载数据、删除数据和移动数据,特别是对于一个拥有海量数据的OLAP及数据仓库系统的数据库来说,更是如此。 总体看来,分区...
  • 数据库有百万条数据,直接用sql的sum求和很慢,需要6秒,该怎么优化提高速度
  • postgreSQL单表数据量上千万分页查询缓慢的优化方案

    万次阅读 多人点赞 2019-12-26 17:03:08
    postgreSQL单表数据量上千万分页查询缓慢的优化方案
  • 一、数据库性能瓶颈主要原因 1、数据库连接 MySQL数据库默认连接为100,我们可以通过配置initialSize、minIdle、maxActive等进行调优,但由于硬件资源的限制,...普遍观点认为单表数据量超过1000万条时就是出现数...
  • 数据库优化的四大方法

    千次阅读 2021-12-26 10:53:58
    正如上图所示,数据库优化可以从架构优化,硬件优化,DB优化,SQL优化四个维度入手。 此上而下,位置越靠前优化越明显,对数据库的性能提升越高。我们常说的SQL优化反而是对性能提高最小的优化。 接下来我们再看看...
  • 目录: 1. 背景 2. HSSH、 XSSF、SXSSF方案实现 3. HSSH、 XSSF、SXSSF方案对比 4. SXSSF、EasyExcel大...6. 性能优化策略 7. 业界其他方案 8. demo下载地址   背景 • 项目背景 XXXXXXXX项目,数据...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,228,972
精华内容 891,588
关键字:

数据优化

友情链接: 微网PSCAD模型.rar