Как стать автором
Обновить

Hadoop, java MapReduce: запуск из произвольного web/EE контейнера

Время на прочтение2 мин
Количество просмотров5.2K
В интернете есть довольно большое количество примеров о том, как запустить MapReduce из стенделон приложения на джаве.
Но начинающему работать с индийским слоником может быть сложно понять, как запустить джобу из какого-нибудь java контейнера.

Например, в этом туториале, любезно предоставленном ikrumping, содержится такой пример кода:

        Job job = new Job(config, "grep");
        
        /*
         * Для запуска программы из jar-файла необходимо указать любой
         * класс из вашего приложения.
         */
        job.setJarByClass(Grep.class);


Такой код будет работать, если вы запускаете стенделон приложение:

Если же вы запускаете код из JBOSS AS, WebSphere AS, Glassfish AS и тд, то этот код работать не будет.
Почему? Да потому, что контейнер распаковывает ваш JAR файл в разные свои кеши и запускает классы уже оттуда.

Кому интересно, почему метод setJarByClass не работает в случае контейнера - приглашаю под спойлер
Для начала предлагаю взглянуть на имплементацию метода setJarByClass.

public void setJarByClass(Class cls)
  {
    String jar = findContainingJar(cls);
    if (jar != null)
      setJar(jar);
  }

 private static String findContainingJar(Class my_class)
  {
    ClassLoader loader = my_class.getClassLoader();
    String class_file = my_class.getName().replaceAll("\\.", "/") + ".class";
    try {
      Enumeration itr = loader.getResources(class_file);
      while (itr.hasMoreElements()) {
        URL url = (URL)itr.nextElement();
        if ("jar".equals(url.getProtocol())) {
          String toReturn = url.getPath();
          if (toReturn.startsWith("file:")) {
            toReturn = toReturn.substring("file:".length());
          }

          toReturn = toReturn.replaceAll("\\+", "%2B");
          toReturn = URLDecoder.decode(toReturn, "UTF-8");
          return toReturn.replaceAll("!.*$", "");
        }
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return null;
  }


Как видите, метод findContainingJar ожидает, что тип протокола у URL будет «jar».
А в случае каждого каждого контейнера протокол будет свой.
Как результат: метод setJarByClass работает в основном только для стенделон приложений.



Как же запустить мапредьюс джобу универсальным способом, не зависящим от конкретного контейнера приложений?

Для этого нужно выполнить следующее:
  1. создать отдельный JAR, содержащий все классы, используемые из джобы
  2. зааплодить его в файловую систему HDFS худупа, где вы собираетесь запускать MapReduce
  3. добавить JAR архив в classpath запускаемой джобы


В вышеприведенном примере нужно заменить:

       job.setJarByClass(Grep.class);

на
        DistributedCache.addFileToClassPath("/user/UserName/test.jar", config);


Где первый параметр метода addFileToClassPath содержит путь к JAR файлу внутри распределенной файловой системы HDFS.
А второй — конфигурацию хадупа (org.apache.hadoop.conf.Configuration).

Раньше было еще 2 способа подсунуть свою джарку хадупу, но они уже устарели: blog.cloudera.com/blog/2011/01/how-to-include-third-party-libraries-in-your-map-reduce-job
Теги:
Хабы:
Всего голосов 9: ↑6 и ↓3+3
Комментарии2

Публикации