Hadoop-0.20.0源代碼分析(01)

Hadoop 框架是兩個模型實現的有機整合,亦即Hadoop分佈式文件系統(HDFS)與MapReduce並行編程模型,也就是說,Hadoop框架要能夠提供的基本功能就是,在存儲系統HDFS上進行MapReduce並行計算,所以,如果想要了解Hadoop框架的工作原理和運行機制,主要從這兩個方面着手。

其實,Hadoop中MapReduce並行計算應該是在HDFS實現的,因此瞭解計算所基於HDFS應該是入口點,當對HDFS有了一定的瞭解,就能夠知道這樣一個並行計算平臺能夠提供哪些進行計算的基礎要素。

當然,在瞭解HDFS之前,應該先熟悉一下Hadoop對文件系統FS是如何實現的,都提供了哪些操作。在org.apache.hadoop.fs包中,提供了文件系統的高層抽象(FileSystem類),基於該抽象的文件系統,可以來實現滿足實際需要的文件系統實現類,例如用來在本地存儲原生文件的文件系統(RawLocalFileSystem),例如一個文件系統之上可以存在其它一些類型的文件系統(基於校驗和的文件系統ChecksumFileSystem類就是這樣的,ChecksumFileSystem extends FilterFileSystem,FilterFileSystem是一個最基本的文件系統實現)。

我在閱讀源代碼的過程中,首先從與org.apache.hadoop.fs包中文件系統相關的其它包org.apache.hadoop.security開始。

org.apache.hadoop.security包中的一些類涉及到文件系統中用戶的信息,例如用戶權限等等。所以,爲了能夠深入瞭解文件系統和方便閱讀源代碼,就應該瞭解與文件系統相關的安全支持,實際上也就是位於Hadoop源代碼中org.apache.hadoop.security包中實現。

下面org.apache.hadoop.security包中類的繼承關係:

[java] view plaincopy
  1. ◦java.lang.Object  
  2.      ◦org.apache.hadoop.security.Group (implements java.security.Principal)   
  3.      ◦org.apache.hadoop.security.SecurityUtil  
  4.      ◦org.apache.hadoop.security.SecurityUtil.AccessControlList  
  5. ◦java.lang.Throwable (implements java.io.Serializable)   
  6.      ◦java.lang.Exception  
  7.           ◦java.io.IOException  
  8.                ◦org.apache.hadoop.fs.permission.AccessControlException  
  9.                     ◦org.apache.hadoop.security.AccessControlException  
  10. ◦org.apache.hadoop.security.User (implements java.security.Principal)   
  11. ◦org.apache.hadoop.security.UserGroupInformation (implements java.security.Principal, org.apache.hadoop.io.Writable)   
  12.      ◦org.apache.hadoop.security.UnixUserGroupInformation  

 

下面分別對其中關鍵類的源代碼進行閱讀分析:

Group類與User類

首先,org.apache.hadoop.security.Group類與org.apache.hadoop.security.User類都是一個實體類,表徵一個屬於HDFS文件系統中存在的一類實體,它們的定義非常相似,下面只拿出Group類來說明。

Group類表示一個組的概念實現,它實現了java.security.Principal接口,也就是說Group類表示一個用來容納一些對象的實體,比如一個組中可以包含多個不同的用戶,一個組中可以包含多種不同的權限,一個組中還可以包含多種授權的證書,等等。這個類比較容易,包含一個final修飾的組名稱的字段,也就是說一個組一旦創建就不能修改組名稱,Group類沒有提供修改組名稱的方法。新創建一個組的時候,需要指定組名稱。該類中比較重要的是equals方法,用來比較某個Object對象(組對象)是夠與該組(this)相互匹配。

 UserGroupInformation抽象類

在Hadoop框架中,分佈式文件系統框架HDFS具有一個用來存儲用戶和組信息的實現,它是通過一個位於org.apache.hadoop.security包中的UserGroupInformation抽象類來抽象這些信息的,如果對於特定的基於用戶和組的操作系統,都可以繼承自該抽象類,用來實現表示用戶與組的一些信息的實體,及其一些簡單的操作。

下面是抽象類的源代碼:

[java] view plaincopy
  1. package org.apache.hadoop.security;  
  2.   
  3. import java.io.IOException;  
  4. import java.security.AccessController;  
  5. import java.security.Principal;  
  6. import java.util.Set;  
  7.   
  8. import javax.security.auth.Subject;  
  9. import javax.security.auth.login.LoginException;  
  10.   
  11. import org.apache.commons.logging.Log;  
  12. import org.apache.commons.logging.LogFactory;  
  13. import org.apache.hadoop.conf.Configuration;  
  14. import org.apache.hadoop.io.Writable;  
  15.   
  16. /** 該類是一個用來儲存用戶和組信息的抽象類,並且它實現了Hadoop定義的用來實現序列化的接口Writable類,也就是說,用戶和組的信息是可序列化的。 
  17.  */  
  18. public abstract class UserGroupInformation implements Writable, Principal {  
  19.   public static final Log LOG = LogFactory.getLog(UserGroupInformation.class);  
  20.   private static UserGroupInformation LOGIN_UGI = null// 用戶組信息屬性  
  21.     
  22.   private static final ThreadLocal<Subject> currentUser = new ThreadLocal<Subject>(); // 線程局部Subject變量  
  23.     
  24.   /** 獲取當前用戶線程的UserGroupInformation信息 */   
  25.   public static UserGroupInformation getCurrentUGI() {  
  26.     Subject user = getCurrentUser(); // 調用,得到當前用戶線程的Subject  
  27.     if (user == null) { // 如果爲null  
  28.       user = currentUser.get(); // 獲取當前用戶線程當前線程局部變量拷貝的值  
  29.       if (user == null) { // 沒能獲取到當前用戶的Subject,無法認證,直接返回  
  30.         return null;  
  31.       }  
  32.     }  
  33.       
  34.     Set<UserGroupInformation> ugiPrincipals = user.getPrincipals(UserGroupInformation.class); // 獲取用戶身份信息  
  35.       
  36.     UserGroupInformation ugi = null;  
  37.     if (ugiPrincipals != null && ugiPrincipals.size() == 1) {  
  38.       ugi = ugiPrincipals.iterator().next();  
  39.       if (ugi == null) {  
  40.         throw new RuntimeException("Cannot find _current user_ UGI in the Subject!");  
  41.       }  
  42.     } else {  
  43.       throw new RuntimeException("Cannot resolve current user from subject, " +  
  44.                                    "which had " + ugiPrincipals.size() +   
  45.                                    " UGI principals!");  
  46.     }  
  47.     return ugi;  
  48.   }  
  49.   
  50.   /**  
  51.    * 根據構造的UserGroupInformation實例,爲當前線程設置用戶和組信息 
  52.    */   
  53.   @Deprecated  
  54.   public static void setCurrentUGI(UserGroupInformation ugi) {  
  55.     setCurrentUser(ugi);  
  56.   }  
  57.   
  58.   /** 
  59.    * 獲取當前用戶所擁有的Subject實例 
  60.    */  
  61.   static Subject getCurrentUser() {  
  62.     return Subject.getSubject(AccessController.getContext()); // 根據線程當前調用上下文(例如堆棧信息),構造(或者獲取到)當前用戶的Subject實例  
  63.   }  
  64.     
  65.   /** 
  66.    * 設置當前用戶線程所具有的UserGroupInformation的信息 
  67.    * WARNING - This method should be used only in test cases and other exceptional 
  68.    * cases! 
  69.    */  
  70.   public static void setCurrentUser(UserGroupInformation ugi) {  
  71.     Subject user = SecurityUtil.getSubject(ugi); // 根據ugi信息獲取當前用戶的Subject實例  
  72.     currentUser.set(user); // 將當前用戶線程局部變量,當前線程副本中的值設置爲根據ugi獲取到的Subject實例  
  73.   }  
  74.     
  75.   /** 獲取用戶名稱 
  76.    */  
  77.   public abstract String getUserName();  
  78.     
  79.   /** 獲取到一個用戶所屬的組(可能該用戶屬於多個組)的名稱 
  80.    */  
  81.   public abstract String[] getGroupNames();  
  82.   
  83.   /** 登錄系統的方法實現,如果登錄成功則返回登錄用戶的一些信息,包括用戶、組相關信息的一個實例 */  
  84.   public static UserGroupInformation login(Configuration conf) throws LoginException {  
  85.     if (LOGIN_UGI == null) {  
  86.       LOGIN_UGI = UnixUserGroupInformation.login(conf); // 默認使用Hadoop實現的UnixUserGroupInformation來進行登錄  
  87.     }  
  88.     return LOGIN_UGI;  
  89.   }  
  90.   
  91.   /** 從Hadoop的配置Configuration 類實例中讀取UserGroupInformation的信息 */  
  92.   public static UserGroupInformation readFrom(Configuration conf) throws IOException {  
  93.     try {  
  94.       return UnixUserGroupInformation.readFromConf(conf, UnixUserGroupInformation.UGI_PROPERTY_NAME); // 默認使用UnixUserGroupInformation實現類來讀取Hadoop配置類實例,獲取用戶和組信息  
  95.     } catch (LoginException e) {  
  96.       throw (IOException)new IOException().initCause(e);  
  97.     }  
  98.   }  
  99. }  

 該類中使用到javax.security.auth.Subject類,該類的實例包含了一個實體的兩種信息:一個是用來認證的身份信息,另一個與該用戶安全相關的信息,例如許可證書。

UserGroupInformation類實現了org.apache.hadoop.io.Writable接口,該接口是Hadoop框架基於DataInput和DataOutput定義的一個序列化協議,實現該接口的類支持序列化操作。org.apache.hadoop.io.Writable接口定義如下所示:

[java] view plaincopy
  1. package org.apache.hadoop.io;  
  2.   
  3. import java.io.DataOutput;  
  4. import java.io.DataInput;  
  5. import java.io.IOException;  
  6.   
  7. public interface Writable {  
  8.   /**  
  9.    * 將對象(this)的屬性字段序列化到輸出流DataOuput out中。 
  10.    */  
  11.   void write(DataOutput out) throws IOException;  
  12.   
  13.   /**  
  14.    * 從輸入流DataInput in中讀取屬性字段信息,重組爲(this)對象,這是一個反序列化操作。 
  15.    */  
  16.   void readFields(DataInput in) throws IOException;  
  17. }  

總結一下,UserGroupInformation抽象類主要定義的操作如下:

1、獲取當前用戶線程的用和組信息(UGI),通過getCurrentUGI()方法實現的;

2、獲取用戶名和組名,分別通過抽象方法getUserName()和getGroupNames()方法實現的;

3、根據Hadoop的配置類Configuration實例,登錄系統後返回一個UserGroupInformation 類的實例,通過方法login(Configuration conf)實現的;

4、讀取Hadoop的配置類Configuration實例,返回一個UserGroupInformation 類的實例,通過方法readFrom(Configuration conf)實現的。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章