1. 配置Job属性
在MapReduce执行过程中,task可以读取Job的属性。基于这个特性,我们可以在任务启动之初利用Configuration类中的set(String name,String value)将一些简单的全局数据封装到作业的配置属性中,然后task再利用Configuration中的get(String name)获取配置到属性中的全局数据。
这种方法的优点是简单,资源消耗小,但是对量比较大的共享数据显得比较无力。更多用于配置信息;
注:hdfs上的配置文件也可以在创建job前读取,并通过Configuration共享, 然后在map/reduce的setup方法中读取;适合小数据量,如几兆;
2. 使用DistributedCache
DistributedCache是MapReduce为应用提供缓存文件的只读工具,它可以缓存文本文件,压缩文件和jar文件等。在使用时,用户可以在作业配置中使用本地或HDFS文件的URL来将其设置成共享缓存文件。在作业启动之后和task启动之前,MapReduce框架会将可能需要的缓存文件复制到执行任务节点的本地。
这种方法的优点是每个Job共享文件只会子啊启动之后复制一次,并且它适用与大量的共享数据,而缺点是它是只读的。
注:该方法也可以缓存路径,会将该路径下所有文件全部共享到节点;程序运行成功后,会将该路径的数据删除,创建的目录不会被删除;如果程序运行失败,且数据已经共享,则这份数据不会被删除;
创建job后,提交job前:
job.addCacheFile(new Path(cacheFilePath).toUri());
在map中的setup方法中(reduce也可以):
context.getLocalCacheFiles();
3. 读写HDFS文件
在MapReduce框架中,Map Task和Reduce Task都运行在Hadoop集群的节点上,所以Map和Reduce Task、甚至不同的Job都可以通过读写HDFS中预定好的同一文件来实现全局共享数据。具体实现是利用Hadoop 的Java API来完成,需要注意的是,多个Map或Reduce的写操作会产生冲突,覆盖原有数据。
这种方法的优点是能够实现读写,也比较直观,但是缺点是需要共享一些很小的全局数据也需要使用IO,这将占用系统资源,增加作业完成的资源消耗。
注: 一般该方法用在map中的setup方法中,当并发量很大时,性能会大幅衰减,导致程序整体运行时长增加,甚至timeout;该方法可以结合方法1,方法2一起使用;
使用DistributedCache缓存数据,在获取本地路径时(context.getLocalCacheFiles()
),系统会默认为hdfs路径导致报java.io.FileNotFoundException,增加前缀"file://"即可解决该问题;
参考文档:
http://dongxicheng.org/mapreduce-nextgen/hadoop-distributedcache-details/
https://blog.youkuaiyun.com/minglaihan/article/details/23591351