热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MaxCompute最佳实践:计算长尾调优

长尾问题是分布式计算里最常见的问题之一,也是典型的疑难杂症。究其原因,是因为数据分布不均,导致各个节点的工作量不同,整个任务就需要等最慢的节点完成才能完成。处理这类问题的思路就是把工作分

长尾问题是分布式计算里最常见的问题之一,也是典型的疑难杂症。究其原因,是因为数据分布不均,导致各个节点的工作量不同,整个任务就需要等最慢的节点完成才能完成。
处理这类问题的思路就是把工作分给多个Worker去执行,而不是一个Worker单独抗下最重的那份工作。本文分享平时工作中遇到的一些典型的长尾问题的场景及其解决方案。



Join长尾

Join能出现长尾,是因为Join时出现某个Key里的数据特别多的情况。
解法:




  • 排除两张表都是小表的情况,若两张表里有一张大一张小,可以考虑使用Mapjoin,对小表进行缓存。具体语法和说明可以参考此文档。如果是MapReduce作业,可以使用资源表的功能,对小表进行缓存。

  • 但是如果两张表都比较大,就需要先尽量去重。

  • 若还是不能解决,就需要从业务上考虑,为什么会有这样的两个大数据量的Key要做笛卡尔积,直接考虑从业务上进行优化。

Group By长尾

Group By Key 出现长尾的原因是因为某个Key内的计算量特别大。
解法 一:可对SQL进行改写,添加随机数,把长Key进行拆分。如SQL:

  1. Select    Key,Count(*)  As  Cnt  From  TableName  Group  By  Key;

不考虑Combiner,M节点会Shuffle到R上,然后R再做Count操作。对应的执行计划是M->R
但是如果对长尾的Key再做一次工作再分配,就变成:

  1. --    假设长尾的Key已经找到是KEY001

  2. SELECT a.Key

  3.     , SUM(a.Cnt) AS Cnt

  4. FROM (

  5.     SELECT Key

  6.         , COUNT(*) AS Cnt

  7.     FROM TableName

  8.     GROUP BY Key,

  9.         CASE

  10.             WHEN Key = 'KEY001' THEN Hash(Random()) % 50

  11.             ELSE 0

  12.         END

  13. ) a

  14. GROUP BY a.Key;

可以看到,这次的执行计划变成了M->R->R。虽然执行的步骤变长了,但是长尾的Key经过了2个步骤的处理,整体的时间消耗可能反而有所减少。
注意,若数据的长尾并不严重,用这种方法人为地增加一次R的过程,最终的时间消耗可能反而更大
解法二:使用通用的优化策略——系统参数,设置

  1. set    odps.sql.groupby.skewindata=true。

但是通用性的优化策略无法针对具体的业务进行分析,得出的结果不总是最优的。开发人员可以根据实际的数据情况,用更加高效的方法来改写SQL。

Distinct长尾

可以看到,对于Distinct,上述Group By长尾“把长Key进行拆分”的策略已经不生效了。对这种场景,我们可以考虑其他方式解决。
解法:

  1. --原始SQL,不考虑Uid为空

  2. SELECT COUNT(uid) AS Pv

  3.     , COUNT(DISTINCT uid) AS Uv

  4. FROM UserLog;

可以改写成

  1. SELECT SUM(PV) AS Pv

  2.     , COUNT(*) AS UV

  3. FROM (

  4.     SELECT COUNT(*) AS Pv

  5.         , uid

  6.     FROM UserLog

  7.     GROUP BY uid

  8. ) a;

该解法是把Distinct改成了普通的Count,这样的计算压力不会落到同一个Reducer上。而且这样改写后,既能支持前面提到的Group By优化,系统又能做Combiner,性能会有较大的提升。

动态分区长尾

动态分区功能为了整理小文件,会在最后起一个Reduce,对数据进行整理,所以如果使用动态分区写入数据时若有倾斜,就会发生长尾。另外一般情况下滥用动态分区的功能也是产生这类长尾的一个常见原因。
解法:若写入的数据已经确定需要把数据写入某个具体分区,那可以在Insert的时候指定需要写入的分区,而不是使用动态分区。

通过Combiner解决长尾

对于MapRedcuce作业,使用Combiner是一种常见的长尾优化策略。在WordCount的例子里,就已经有提到这种做法。通过Combiner,减少MaperShuffle往Reducer的数据,可以大大减少网络传输的开销。对于MaxCompute SQL,这种优化会由系统自动完成。
需要注意的是,Combiner只是Map端的优化,需要保证是否执行Combiner的结果是一样的。以WordCount为例,传2个(KEY,1)和传1个(KEY,2)的结果是一样的。但是比如在做平均值的时候,就不能在Combiner里就把(KEY,1)和(KEY,2)合并成(KEY,1.5)。

通过系统优化解决长尾

针对长尾这种场景,除了前面提到的Local Combiner,MaxCompute系统本身还做了一些优化。比如在跑任务的时候,日志里突然打出这样的内容(+N backups部分):

  1. M1_Stg1_job0:0/521/521[100%]    M2_Stg1_job0:0/1/1[100%]    J9_1_2_Stg5_job0:0/523/523[100%]    J3_1_2_Stg1_job0:0/523/523[100%]    R6_3_9_Stg2_job0:1/1046/1047[100%]  

  2. M1_Stg1_job0:0/521/521[100%]    M2_Stg1_job0:0/1/1[100%]    J9_1_2_Stg5_job0:0/523/523[100%]    J3_1_2_Stg1_job0:0/523/523[100%]    R6_3_9_Stg2_job0:1/1046/1047[100%]  

  3. M1_Stg1_job0:0/521/521[100%]    M2_Stg1_job0:0/1/1[100%]    J9_1_2_Stg5_job0:0/523/523[100%]    J3_1_2_Stg1_job0:0/523/523[100%]    R6_3_9_Stg2_job0:1/1046/1047(+1    backups)[100%]  

  4. M1_Stg1_job0:0/521/521[100%]    M2_Stg1_job0:0/1/1[100%]    J9_1_2_Stg5_job0:0/523/523[100%]    J3_1_2_Stg1_job0:0/523/523[100%]    R6_3_9_Stg2_job0:1/1046/1047(+1    backups)[100%]

可以看到1047个Reducer,有1046个已经完成了,但是最后一个一直没完成。系统识别出这种情况后,自动启动了一个新的Reducer,跑一样的数据,然后看两个哪个快,取快的数据归并到最后的结果集里。

通过业务优化解决长尾

虽然前面的优化策略有很多,但是实际上还是有限。有时候碰到长尾问题,还需要从业务角度上想想是否有更好的解决方法,比如:

  • 实际数据可能包含非常多的噪音。如,需要根据访问者的ID进行计算,看每个用户的访问记录的行为。需要先去掉爬虫的数据(现在的爬虫已越来越难识别),否则爬虫数据很容易长尾计算的长尾。类似的情况还有根据xxid进行关联的时候,需要考虑这个关联字段是否存在为空的情况。

  • 一些业务特殊情况,如,ISV的操作记录,在数据量、行为方式上都会和普通的个人会有很大的区别。那么可以考虑针对大客户,使用特殊的分析方式进行单独处理。

  • 数据分布不均匀的情况下,不要使用常量字段做Distribute by字段来实现全排序。


   



推荐阅读
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 从Oracle安全移植到国产达梦数据库的DBA实践与攻略
    随着我国对信息安全和自主可控技术的重视,国产数据库在党政机关、军队和大型央企等行业中得到了快速应用。本文介绍了如何降低从Oracle到国产达梦数据库的技术门槛,保障用户现有业务系统投资。具体包括分析待移植系统、确定移植对象、数据迁移、PL/SQL移植、校验移植结果以及应用系统的测试和优化等步骤。同时提供了移植攻略,包括待移植系统分析和准备移植环境的方法。通过本文的实践与攻略,DBA可以更好地完成Oracle安全移植到国产达梦数据库的工作。 ... [详细]
  • 本文介绍了关系型数据库和NoSQL数据库的概念和特点,列举了主流的关系型数据库和NoSQL数据库,同时描述了它们在新闻、电商抢购信息和微博热点信息等场景中的应用。此外,还提供了MySQL配置文件的相关内容。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • mysql-cluster集群sql节点高可用keepalived的故障处理过程
    本文描述了mysql-cluster集群sql节点高可用keepalived的故障处理过程,包括故障发生时间、故障描述、故障分析等内容。根据keepalived的日志分析,发现bogus VRRP packet received on eth0 !!!等错误信息,进而导致vip地址失效,使得mysql-cluster的api无法访问。针对这个问题,本文提供了相应的解决方案。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
author-avatar
ChiuChiuLIN
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有