大数据常用优化记录

1,095 阅读5分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

大数据常用优化记录

Hadoop-小文件

HDFS

  • 合并文件到本地
hadoop fs -getmerge /user/hive/warehouse/ods.db/xxxx ./
  • 合并文件并上传到hdfs
hadoop dfs -cat /user/hive/warehouse/ods.db/xxxx/staticdate=2019-06-05/ | hadoop dfs -put - /user/hive/warehouse/ods.db/xxxx/staticdate=2019-06-05/0000.merge

Hive小文件合并

  • 每个Map最大输入大小,决定合并后的文件数
set mapreduce.input.fileinputformat.split.maxsize=100000000;
  • 每个Map最小输入大小,决定合并后的文件数
set mapreduce.input.fileinputformat.split.minsize=100000000;
  • 一个节点上split的至少的大小 ,决定了多个data node上的文件是否需要合并
set mapreduce.input.fileinputformat.split.minsize.per.node=100000000;
  • 一个交换机下split的至少的大小,决定了多个交换机上的文件是否需要合并
set mapreduce.input.fileinputformat.split.minsize.per.rack=100000000;
  • mapred.min.split.size.per.node和mapred.min.split.size.per.rack,含义是单节点和单机架上的最小split大小。如果发现有split大小小于这两个值(默认都是100MB),则会进行合并。
  • 设置 reduce 端输出进行合并,默认为 false
set hive.merge.mapfiles=true
  • 执行 map 前进行小文件合并
set hive.merge.mapredfiles=true
set hive.input.format=org.apache.Hadoop.hive.qi.io.CombineHiveInputFormat 
  • 减少 reduce 的数量
set mapreduce.job.reduces=N
  • 在 Spark 作业结束时合并小文件。如启用,将创建 map-only 作业以合并目标表/分区中的文件
hive.merge.sparkfiles
  • 当作业的平均输出文件大小小于此属性的值时,Hive 将启动额外的 map-only 作业来将输出文件合并成大文件。仅当 hive.merge.mapfiles 为 true 对map-only 作业执行,当 hive.merge.mapredfiles 为 true 时对 map-reduce 作业执行,以及当 hive.merge.sparkfiles 为 true 时对 Spark 作业执行
hive.merge.smallfiles.avgsize
  • 合并后所需的文件大小。应大于 hive.merge.smallfiles.avgsize
hive.merge.size.per.task

SparkSQL

  • 是否开启调整partition功能,如果开启,spark.sql.shuffle.partitions设置的partition可能会被合并到一个reducer里运行。默认开启,同时强烈建议开启。理由:更好利用单个 executor 的性能,还能缓解 小文件问题
set spark.sql.adaptive.enabled=true
  • 和 spark.sql.adap tive.enabled 配合使用,当开启调整 partition 功能后,当 mapper 端两个 partition 的数据合并后数据量小于 targetPostShuffleInputSize 时,Spark 会将两个 partition 进行合并到一个 reducer 端进行处理。平台默认为 67108864(64M),用户可根据自身 作业的情况酌情调整该值
set spark.sql.adaptive.shuffle.targetPostShuffleInputSize=67108864
  • 使用 distribute by 把同一分区的记录哈希到同一个分区,由一个 SparkTask 进行 写入,这样每个分区下只会有一个小于 128M 的文件,当数据量过大的时候这种方式会 导致倾斜 key 的时间长,任务跑的慢,可以改为: distribute by dt cast(rand()*n as int) 每个分区下只产生 n 个文件,打散数据防止造成倾斜 这种方式建议增加 reduce 端端内存,防止 oom
insert overwrite table xx partition(dt)  select*from xx distribute by dt 

Hbase

预分区

  1. 手动分区
create 'device_action_history', {NAME => 'cf', COMPRESSION => 'SNAPPY' , VERSIONS => 10}
,SPLITS => ['10','15','20','25','30','35','40','45','50']
  1. 算法分区
create ‘t3’,{NAME => ‘f1’,COMPRESSION => ‘snappy’ }, { NUMREGIONS => 50, SPLITALGO =>HexStringSplit’ }
  • 其中 NUMREGIONS 为 region的个数,一般按每个region 6~8GB左右来计算region数量,集群规模大,region数量可以适当取大一些
  • SPLITALGO 为 rowkey分割的算法:Hbase自带了三种pre-split的算法,分别是 HexStringSplit、DecimalStringSplit 和 UniformSplit。
    • HexStringSplit: rowkey是十六进制的字符串作为前缀的
    • DecimalStringSplit: rowkey是10进制数字字符串作为前缀的
    • UniformSplit: rowkey前缀完全随机

关闭AutoFlush

  • 默认情况下,AutoFlush是开启的,当每次put操作的时候,都会提交到HBase server,大数据量put的时候会造成大量的网络IO,耗费性能在大数据量并发下,AutoFlush设置为false,并且将WriteBufferSize设置大一些(默认是2MB)(WriteBufferSize只有在AutoFlush为False情况下起作用)则需要通过调用HTable.setAutoFlushTo(false)方法可以将HBaseClient写客户端自动flush功能关闭,这样可以批量的将数据写入到HBase中,而不是一条put就执行一次更新!但是这样也有一个弊端,就是当出现故障的时候,比如宕机事故,缓冲区的数据还没有来得及flush落盘,则会丢失

批量读写

  • 建议使用List来写入hbase数据而不是put。HBase通过Put操作来将RowKey信息写入数据,如果在并发度比较高的情况下,频繁的Put会造成网络IO,HBase提供了另一种put操作,可以调用HTable.put(List)可以批量的写入多条记录,这样就只有一次网络IO操作同样,HBase也提供一种可以批量读的方式,通过HTable.get(list)方式,可以根据给定的rowkey列表返回多个rowkey结果的集合,这样在通过list方式请求时,只会有一次网络IO,可以减少网络阻塞情况提供网络传输性能

启用压缩

HBase创建表时要启用压缩,HBase支持的几种压缩算法分别为:GZIP、LZO、SNAPPY、Zippy.

  1. GZIP的压缩率最高,但它是CPU密集型的,对CPU的消耗较多,压缩和解压速度也慢
  2. LZO的压缩率居中,比GZIP要低一些,但是压缩和解压速度明显要比GZIP快很多,其中解压速度快的更多
  3. Zippy/Snappy的压缩率最低,而压缩和解压速度要稍微比LZO要快一些所以在通常情况下使用Snappy和Zippy压缩算法 启用压缩的两种方式:
  4. 在创建表时指定压缩算法
create 'test', {NAME => 'info', VERSIONS => 1, COMPRESSION => 'snappy'}
  1. 创建表后修改
  • disable 'test'
  • 使用alter语句进行修改,alter 'test', NAME => 'info', COMPRESSION => 'snappy'enable 'test'
  • 对表进行major_compact操作,使压缩生效,major_compact 'test'

BloomFilter

布隆过滤器是hbase中的高级功能,它能够减少特定访问模式(get/scan)下的查询时间(简单来说就是提高随机读的效率)。不过由于这种模式增加了内存和存储的负担,所以被默认为关闭状态。

hbase支持如下类型的布隆过滤器:

1、NONE 不使用布隆过滤器

2、ROW 行键使用布隆过滤器

3、ROWCOL 列键使用布隆过滤器

其中ROWCOL是粒度更细的模式,值得注意的是基于row的scan指令是没办法走Bloom Filter的。因为布隆过滤器是需要事先知道过滤项的。对于顺序scan指令是没有事先办法知道rowkey的。而get指令是指明了rowkey所以可以用布隆过滤器,scan指明column同理

内存规划

image.png