HDFS优化之实战经验
Linux系统优化
一、禁止文件系统记录时间
Linux文件系统会记录文件创建、修改和访问操作的时间信息,这在读写操作频繁的应用中将带来不小的性能损失。在挂载文件系统时设置noatime和nodiratime可禁止文件系统记录文件和目录的访问时间,这对HDFS这种读取操作频繁的系统来说,可以节约一笔可观的开销。可以修改/etc/fstab文件中noatime和nodiratime来实现这个设置。
如对/mnt/disk1使用noatime属性,可以做如下修改:
$ vim /etc/fstab
/ ext4 defaults 1 1
/mnt/disk1 ext4 defaults,noatime 1 2
/mnt/disk2 ext4 defaults 1 2
/mnt/disk3 ext4 defaults 1 2
修改完成后,运行下述命令使之生效:
$ mount –o remount /mnt/disk1
二、预读缓冲
预读技术可以有效的减少磁盘寻道次数和应用的I/O等待时间,增加Linux文件系统预读缓冲区的大小(默认为256 sectors,128KB),可以明显提高顺序文件的读性能,建议调整到1024或2048 sectors。预读缓冲区的设置可以通过blockdev命令来完成。下面的命令将/dev/sda的预读缓冲区大小设置为2048 sectors。
$ blockdev –setra 2048 /dev/sda
注意:预读缓冲区并不是越大越好,多大的设置将导致载入太多无关数据,造成资源浪费,过小的设置则对性能提升没有太多帮助
HDFS配置及相关优化
根据业务需求和服务器配置合理设置这些选项可以有效提高HDFS的性能
配置项 |
优化原理 |
推荐值 |
dfs.namenode.handler.count |
NameNode中用于处理RPC调用的线程数,默认为10。对于较大的集群和配置较好的服务器,可适当增加这个数值来提升NameNode RPC服务的并发度。 |
64 |
dfs.datanode.handler.count |
DataNode中用于处理RPC调用的线程数,默认为3。可适当增加这个数值来提升DataNode RPC服务的并发度。 |
10 |
dfs.replication
|
数据块的备份数。默认值为3,对于一些热点数据,可适当增加备份数。 |
3 |
dfs.block.size |
HDFS数据块的大小,默认为64M。数据库设置太小会增加NameNode的压力。数据块设置过大会增加定位数据的时间。 |
128 |
dfs.datanode.data.dir
|
HDFS数据存储目录。将数据存储分布在各个磁盘上可充分利用节点的I/O读写性能。 |
设置多个磁盘目录 |
hadoop.tmp.dir |
Hadoop临时目录,默认为系统目录/tmp。在每个磁盘上都建立一个临时目录,可提高HDFS和MapReduce的I/O效率。 |
设置多个磁盘目录 |
dfs.data.dir
|
HDFS数据存储配置 提高I/O效率 |
以逗号隔开 |
dfs.name.dir
|
HDFS元数据存储配置, 要想提升hadoop整体IO性能,对于hadoop中用到的所有文件目录,都需要评估它磁盘IO的负载,对于IO负载可能会高的目录,最好都配置到多个磁盘上,以提示IO性能 |
-- |
Io.file.buffer.size
|
HDFS文件缓冲区大小,默认为4096(即4K) |
131072(128K) |
fs.trash.interval |
HDFS清理回收站的时间周期,单位为分钟。默认为0,表示不使用回收站特性。为防止重要文件误删,可启用该特性 |
1440(1day) |
dfs.datanode.du.reserved |
DataNode保留空间大小,单位为字节。默认情况下,DataNode会占用全部可用的磁盘空间,该配置项可以使DataNode保留部分磁盘空间工其他应用程序使用。 |
视具体应用而定 |
RAID
|
独立硬盘冗余阵列(RAID, Redundant Array of Independent Disks) 软件RAID管理工具:mdadm | 支持的RAID级别:LINEAR、RAID0、1、4、5、6、10 |
配置使用【作业 1】 |
机架感应 |
对于较大的集群,建议启用HDFS的机架感应功能。启用机架感应功能可以使HDFS优化数据块备份的分布,增强HDFS的性能和可靠性。 |
配置使用【作业 2】 |
小文件合并 具体操作已实操
SSD存储介质
注意:在全SSD机型的服务器上,如果应用使用的HDFS客户端jar包版本与服务端不一致,会导致无法写入数据的问题。
该问题是由于HDFS客户端ABI不兼容导致的,在HDFS 2.5.x版本中,对存储策略的编号与HDFS 2.6.x版本的编号不一致,在全SSD机型中,客户端写入数据的策略被定义为HOT,而在服务端,该策略被解析为DISK,因为全SSD机型中不存在SATA盘,所以无法获取可行的磁盘,导致无法写入数据。
HDFS异构存储解决冷热数据问题 **
Hadoop从2.6.0版本开始支持异构存储功能。我们知道HDFS默认的存储策略,对于每个数据块,采用三个副本的存储方式,保存在不同节点的磁盘上。异构存储的作用在于利用服务器不同类型的存储介质(包括HDD硬盘、SSD、内存等)提供更多的存储策略(例如三个副本一个保存在SSD介质,剩下两个仍然保存在HDD硬盘),从而使得HDFS的存储能够更灵活高效地应对各种应用场景。
随着数据量的不断增长积累,数据也会呈现出访问热度不同的巨大差异。例如一个平台会不断地写入最新的数据,但通常情况下最近写入的数据访问频率会比很久之前的数据高很多。如果无论数据冷热情况,都采用同样的存储策略,是对集群资源的一种浪费。如何根据数据冷热程度对HDFS存储系统进行优化是一个亟待解决的问题。
拓展》》》
调度延迟和可移植性【涉及到后时代的3驾马车,了解即可】
1、调度延迟
关于调度延迟主要是发生在两个阶段:
a) tasktracker上出现空余的slot到该tasktracker接收到新的task;
b) tasktracker获取到了新的Task后,到连接上了datanode,并且可以读写数据。
之所以说这两个阶段不够高效,因为一个分布式计算系统需要解决的是计算问题,如果把过多的时间花费在其它上,就显得很不合适,例如线程等待、高负荷的数据传输。
下面解释下会经历上边两个阶段发生的过程:
a) 当tasktracker上出现slot时,他会调用heartbeat方法向jobtracker发送心跳包(默认时间间隔是3秒,集群很大时可适量调整)来告知它,假设此时有准备需要执行的task,那么jobtracker会采用某种调度机制(调度机制很重要,是一个可以深度研究的东东)选择一个Task,然后通过调用heartbeat方法发送心跳包告知tasktracker。在该过程中,HDFS一直处于等待状态,这就使得资源利用率不高。
b) 这个过程中所发生的操作都是串行化的:tasktracker会连接到namenode上获取到自己需要的数据在datanode上的存储情况,然后再从datanode上读数据,在该过程中,HDFS一直处于等待状态,这就使得资源利用率不高。
若能减短hdfs的等待时间;在执行task之前就开始把数据读到将要执行该task的tasktracker上,减少数据传输时间,那么将会显得高效很多。未解决此类问题,有这样几种解决方案:重叠I/O和CPU阶段(pipelining),task预取(task prefetching),数据预取(data prefetching)等。
2可移植性
Hadoop是Java写的,所以可移植性相对较高。由于它屏蔽了底层文件系统,所以无法使用底层api来优化数据的读写。在活跃度较高的集群里(例如共享集群),大量并发读写会增加磁盘的随机寻道时间,这会降低读写效率;在大并发写的场景下,还会增加大量的磁盘碎片,这样将会大大的增加了读数据的成本,hdfs更适合文件顺序读取。
对于上述问题,可以尝试使用下面的解决方案:
tasktracker现在的线程模型是:one thread per client,即每个client连接都是由一个线程处理的(包括接受请求、处理请求,返回结果)。那么这一块一个拆分成两个部分来做,一组线程来处理和client的通信(Client Threads),一组用于数据的读写(Disk Threads)。
想要解决上述两个问题,暂时没有十全十美的办法,只能尽可能的权衡保证调度延迟相对较低+可移植性相对较高。
优化策略:Prefetching与preshuffling
a) Prefetching包括Block-intra prefetching和Block-inter prefetching:
Block-intra prefetching:对block内部数据处理方式进行了优化,即一边进行计算,一边预读将要用到的数据。这种方式需要解决两个难题:一个是计算和预取同步,另一个是确定合适的预取率。前者可以使用进度条(processing bar)的概念,进度条主要是记录计算数据和预读数据的进度,当同步被打破时发出同步失效的通知。后者是要根据实际情况来设定,可采用重复试验的方法来确定。
Block-inter prefetching:在block层面上预读数据,在某个Task正在处理数据块A1的时候,预测器能预测接下来将要读取的数据块A2、A3、A4,然后把数据块A2、A3、A4预读到Task所在的rack上。
b) preshuffling
数据被map task处理之前,由预测器判断每条记录将要被哪个reduce task处理,将这些数据交给靠近reduce task的map task来处理。