本文由 importnew - royce wong 翻译自 cloudera。如需转载本文,请先参见文章末尾处的转载要求。 大家都知道,apache hadoop的一个关键思想就是移动计算比移动数据更廉价。所以只要可能,我们就乐忠移动计算到数据地方。因此,hdfs通常使用许多的本地读,在
本文由 importnew - royce wong 翻译自 cloudera。如需转载本文,请先参见文章末尾处的转载要求。
大家都知道,apache hadoop的一个关键思想就是移动计算比移动数据更廉价。所以只要可能,我们就乐忠移动计算到数据地方。因此,hdfs通常使用许多的本地读,在本地机器构造读对象读出数据。
最初,hdfs本地读其实和远程读使用的同一种方式:client端通过tcp 连接dn,并通过datatransferprotocol传输数据。该方法简单,但是有一些不好的地方。例如,dn需要维护一个线程运行,并为每个client打开的tcp套接字建立连接传输数据。在linux内核中tcp协议是有开销的,同时datatransferprotocol本身也有开销。这里有优化空间。
本文大家将会了解到一项hdfs新的优化,叫做“secure short-circuit local reads”,学习该优化如何实现并怎样提速本地读的。
hdfs-2246 曾经实现的short-circuit localreadshdfs-2246,ndrew purtell, suresh srinivas, jitendra nath pandey, and benoy antony等人添加了一项称为“short-circuit local reads”优化。
其关键思想如下:因为客户端和数据在同一个节点,所以没必要再去和dn交互。客户端本身直接就从本地磁盘读出数据。这个性能优化被加入了cdh3u3。
hdfs-2246实现的short-circuit local read 是一个好的开始,但其带来了许多配置上麻烦。系统管理员必须改变dn数据目录权限,允许客户端打开相关文件。还需要定义一个白名单用户,可以使用这个特性。其他用户不允许。通常,这些用户被搞到一个特殊的unix 用户组里。
不幸的是,这种权限改变带来了安全漏洞。有这种权限的用户就可以直接浏览所有数据了,不仅是他们需要的数据。简直就是超级用户啊!这个在一些场景下可以接受,比如 hbase用户,但是一般来讲,它还是带来了问题。这不是一个通用的方式。
hdfs-347:让short-circuit local reads 安全hdfs-2246的主要问题就是它将dn的所有数据路径直接开放给了客户端。其实,客户端只是想要几个其关心的数据文件。
幸亏unix提供了可以这样做的机制,文件描述符。hdfs-347使用该机制实现安全的short-circuit local reads. 客户端向dn请求数据时,dn简单地打开blockfile和元数据文件,并直接传给客户端,而不是将路径传给客户端。因为文件描述符是只读的,客户端不能修改接收到的文件。同时不支持对block所在路径的访问,所以也就不能访问其他数据。
windows 有类似的机制允许将文件描述符在进程间传递。cdh目前还不支持该特性,同时windows用户可以配置dfs.cient.use.legacy.blockreader.local为true使用legacy block reader。
cache 文件描述符hdfs客户端经常多次读取相同的block文件(y尤其对hbase而言)。为了提高这种场景下的本地读,hdfs-2246实现的机制中有一个block 路径的cache。cache允许客户端重新打开block文件,而不需要再去访问dn。
相对于路径cache,新机制实现了一个fileinputstreamcache,缓存文件描述符。优点在于不需要客户端重新打开数据文件。该处实现性能优于老的读取机制。
cache的大小可以通过dfs.client.read.shortcircuit.stream.cache.size调整,cache超时时间通过dfs.client.read.shortcircuit.streams.cache.expiry.ms设定。也可以关掉该cache,设置cache大小为0即可。大多数情况下,默认配置就可以了。如果你面对的是特殊的大规模的工作集和高文件描述符限制,你可以试着提高参数值。
hdfs-347配置hdfs-347实现的新机制,所有hdfs用户都可以使用该特性,而不是局限于配置的几个用户。也没有必要去修改unix用户组来设定谁可以访问dn路径。然而,java标准库并不包含支持文件描述符传递的库,所以该特性需要使用jni。同时需要安装libhadoop.so库.
hdfs-347也需要一个unix域套接字路径,可通过dfs.domain.socket.path设置。该路径必须安全地阻止无优先级进程进行中间人攻击(mitm攻击,man-in-the-middle attack)。每个套接字路径必须是root拥有或者dn用户拥有,不能使用人人都可以写或者用户组可写方式的路径。
如果你安装cloudera包 rpm,deb,cloudera会创建一个默认的安全的unix域套接字路径。同时会讲libhadoop.so安装到正确路径下。
详细配置信息可以参考 the upstream documentation
性能新实现到底咋样呢?作者使用 hio_bench程序获取到一些性能统计数据。hiobench github 地址 https://github.com/cmccabe/hiotest。
测试案例运行在8核 intelxeon 2.13 12块磁盘服务器上,集群使用cdh4.3.1,底层使用ext4文件系统。 下图每个值是运行三次的平均值。
在所有测试案例中,hdfs-347实现是最快的,可能归功于fileinputstreamcache.相反hdfs-2246实现会重复打开ext4 块文件多次,打开文件是一个重操作。
short-circuit实现在随机读场景下比顺序读相对于hdfs初始的读取机制有相对优势。部分原因是为short-circuit local reads场景的 高速预读(readahead)还未实现。可以参考hdfs-4697参与相关讨论。
结论scr (short-circuit local reads)是hadoop模型下优化的一项极好的案例。他们也有如何解决规模不断增长的挑战,cloudera目前正挑战在集群中获取每个节点更多性能方向的研究。
如果你正使用cdh4.2 或以上版本,用下新的实现把!
colin mccabe is a software engineer on the platform team, and a hadoop committer.
原文地址:如何提高hadoop中short-circuit local reads时的性能及安全性, 感谢原作者分享。