Alluxio原始碼分析:RPC框架淺析(二)
Alluxio原始碼分析是一個基於記憶體的分散式檔案系統,和HDFS、HBase等一樣,也是由主從節點構成的。而節點之間的通訊,一般都是採用的RPC通訊模型。Alluxio中RPC是基於何種技術如何實現的呢?它對於RPC請求是如何處理的?都涉及到哪些元件?本文將針對這些問題,為您一一解答。
繼《Alluxio原始碼分析:RPC框架淺析(一)》一文後,本文繼續講解Alluxio中RPC實現。
3、Server端實現:RPC Server埠繫結、傳輸協議等引數設定、Server啟動
AlluxioMaster是Alluxio中Master的實現,那麼RPC服務端server自然就會落在它身上了。我們先看AlluxioMaster程式的啟動main()方法,如下:
/** * Starts the Alluxio master server via {@code java -cp <ALLUXIO-VERSION> alluxio.Master}. * * @param args there are no arguments used */ public static void main(String[] args) { // 啟動master時引數應為空 if (args.length != 0) { LOG.info("java -cp {} alluxio.Master", Version.ALLUXIO_JAR); System.exit(-1); } // validate the conf // 驗證配置資訊 if (!ValidateConf.validate()) { LOG.error("Invalid configuration found"); System.exit(-1); } try { // 呼叫get()方法,返回AlluxioMaster例項master AlluxioMaster master = get(); // 呼叫例項master的start()方法,啟動AlluxioMaster例項master master.start(); } catch (Exception e) { LOG.error("Uncaught exception terminating Master", e); System.exit(-1); } }
它主要乾了兩件事,一個就是呼叫get()方法,返回AlluxioMaster例項master,另一個就是呼叫例項master的start()方法,啟動AlluxioMaster例項master。我們先看下get()方法,如下:
/** * Returns a handle to the Alluxio master instance. * * @return Alluxio master handle */ public static synchronized AlluxioMaster get() { // 靜態AlluxioMaster型別成員變數sAlluxioMaster為空時,通過Factory.create()構造一個,否則返回sAlluxioMaster if (sAlluxioMaster == null) { sAlluxioMaster = Factory.create(); } return sAlluxioMaster; }
而Factory的create()方法,則會根據引數alluxio.zookeeper.enabled確定返回FaultTolerantAlluxioMaster例項還是AlluxioMaster例項,FaultTolerantAlluxioMaster繼承自AlluxioMaster,預設是返回AlluxioMaster例項,程式碼如下:
/** * @return {@link FaultTolerantAlluxioMaster} if Alluxio configuration is set to use zookeeper, * otherwise, return {@link AlluxioMaster}. */ public static AlluxioMaster create() { // 根據引數alluxio.zookeeper.enabled確定返回FaultTolerantAlluxioMaster例項還是AlluxioMaster例項, // FaultTolerantAlluxioMaster繼承自AlluxioMaster,預設是返回AlluxioMaster例項 if (MasterContext.getConf().getBoolean(Constants.ZOOKEEPER_ENABLED)) { return new FaultTolerantAlluxioMaster(); } return new AlluxioMaster(); }
在AlluxioMasterd的構造方法中,涉及RPC相關的,主要是Worker最大和最小執行緒數、服務端Socker的TServerSocket例項mTServerSocket等的構造,關鍵程式碼如下:
Configuration conf = MasterContext.getConf(); // Worker最大和最小執行緒數:分別取引數alluxio.master.worker.threads.max和alluxio.master.worker.threads.min mMinWorkerThreads = conf.getInt(Constants.MASTER_WORKER_THREADS_MIN); mMaxWorkerThreads = conf.getInt(Constants.MASTER_WORKER_THREADS_MAX); // 獲取傳輸提供者mTransportProvider mTransportProvider = TransportProvider.Factory.create(conf); // 構造TServerSocket例項mTServerSocket // port取引數alluxio.master.port=19998 mTServerSocket = new TServerSocket(NetworkAddressUtils.getBindAddress(ServiceType.MASTER_RPC, conf));
再看例項master的start()方法,也就是AlluxioMaster的start()方法,程式碼如下:
/** * Starts the Alluxio master server. * * @throws Exception if starting the master fails */ public void start() throws Exception { startMasters(true); // 啟動服務 startServing(); }
繼續看startServing()方法,如下:
protected void startServing(String startMessage, String stopMessage) { mMasterMetricsSystem.start(); // 啟動web服務 startServingWebServer(); LOG.info("Alluxio Master version {} started @ {} {}", Version.VERSION, mMasterAddress, startMessage); // 啟動RPC服務 startServingRPCServer(); LOG.info("Alluxio Master version {} ended @ {} {}", Version.VERSION, mMasterAddress, stopMessage); }
撇開啟動web服務不說,我們看下啟動RPC服務的startServingRPCServer()方法,如下:
protected void startServingRPCServer() { // set up multiplexed thrift processors // 構造多路複用處理器TMultiplexedProcessor例項processor TMultiplexedProcessor processor = new TMultiplexedProcessor(); // 註冊BlockMaster服務 registerServices(processor, mBlockMaster.getServices()); // 註冊FileSystemMaster服務 registerServices(processor, mFileSystemMaster.getServices()); // 必要的話,註冊LineageMaster服務 if (LineageUtils.isLineageEnabled(MasterContext.getConf())) { registerServices(processor, mLineageMaster.getServices()); } // register additional masters for RPC service // 註冊額外的Masters服務 for (Master master : mAdditionalMasters) { registerServices(processor, master.getServices()); } // Return a TTransportFactory based on the authentication type TTransportFactory transportFactory; try { // 獲得傳輸工廠例項 transportFactory = mTransportProvider.getServerTransportFactory(); } catch (IOException e) { throw Throwables.propagate(e); } // create master thrift service with the multiplexed processor. // 構造TThreadPoolServer例項時需要的引數: // 服務端Socker:TServerSocket型別例項mTServerSocket // 最大Worker執行緒數mMaxWorkerThreads // 最小Worker執行緒數mMinWorkerThreads // 處理器processor // 傳輸工廠transportFactory // 協議工廠TBinaryProtocol:二進位制協議TBinaryProtocol Args args = new TThreadPoolServer.Args(mTServerSocket).maxWorkerThreads(mMaxWorkerThreads) .minWorkerThreads(mMinWorkerThreads).processor(processor).transportFactory(transportFactory) .protocolFactory(new TBinaryProtocol.Factory(true, true)); if (MasterContext.getConf().getBoolean(Constants.IN_TEST_MODE)) { args.stopTimeoutVal = 0; } else { args.stopTimeoutVal = Constants.THRIFT_STOP_TIMEOUT_SECONDS; } // 構造TThreadPoolServer例項mMasterServiceServer mMasterServiceServer = new TThreadPoolServer(args); // start thrift rpc server // 標誌位正在提供服務mIsServing設定為true mIsServing = true; // 啟動時間mStartTimeMs取當前時間 mStartTimeMs = System.currentTimeMillis(); // 啟動TThreadPoolServer服務 mMasterServiceServer.serve(); }
startServingRPCServer()方法主要處理流程如下:
1、構造多路複用處理器TMultiplexedProcessor例項processor;
2、呼叫registerServices()方法,註冊BlockMaster、FileSystemMaster、LineageMaster、額外的Masters等各種服務;
3、呼叫TransportProvider的getServerTransportFactory()方法獲得傳輸工廠例項transportFactory;
4、構造TThreadPoolServer例項時需要的引數:包括:
(1)服務端Socker:TServerSocket型別例項mTServerSocket;
(2)最大Worker執行緒數mMaxWorkerThreads;
(3)最小Worker執行緒數mMinWorkerThreads;
(4)多路複用處理器processor;
(5)傳輸工廠transportFactory;
(6)協議工廠TBinaryProtocol:二進位制協議TBinaryProtocol;
5、構造TThreadPoolServer例項mMasterServiceServer;
6、標誌位正在提供服務mIsServing設定為true;
7、啟動時間mStartTimeMs取當前時間;
8、呼叫mMasterServiceServer的serve()方法啟動TThreadPoolServer服務。
先以FileSystemMaster服務為例,看下RPC服務是如何註冊的,程式碼如下:
private void registerServices(TMultiplexedProcessor processor, Map<String, TProcessor> services) { for (Map.Entry<String, TProcessor> service : services.entrySet()) { processor.registerProcessor(service.getKey(), service.getValue()); } }
註冊很簡單,多路複用處理器processor的registerProcessor()方法即可完成註冊,關鍵是要看註冊的是什麼東西它的服務是通過FileSystemMaster的getServices()方法獲取的,我們跟蹤下:
@Override public Map<String, TProcessor> getServices() { Map<String, TProcessor> services = new HashMap<String, TProcessor>(); // FileSystemMasterClientService服務 services.put( // key為"FileSystemMasterClient" Constants.FILE_SYSTEM_MASTER_CLIENT_SERVICE_NAME, // 可以看出,FileSystemMasterClientService服務Master端實現者是FileSystemMasterClientServiceHandler new FileSystemMasterClientService.Processor<FileSystemMasterClientServiceHandler>( new FileSystemMasterClientServiceHandler(this))); // FileSystemMasterWorkerService服務 services.put( // key為"FileSystemMasterWorker" Constants.FILE_SYSTEM_MASTER_WORKER_SERVICE_NAME, // 可以看出,FileSystemMasterWorkerService服務Master端實現者是FileSystemMasterWorkerServiceHandler new FileSystemMasterWorkerService.Processor<FileSystemMasterWorkerServiceHandler>( new FileSystemMasterWorkerServiceHandler(this))); return services; }
就倆服務:FileSystemMasterClientService和FileSystemMasterWorkerService,它們在Master端的實現者分別是FileSystemMasterClientServiceHandler和FileSystemMasterWorkerServiceHandler,並且是通過各自Service的Processor來構造的,看到這裡,你似乎應該明白什麼了吧!這就是Processor的用途。
再看下獲得傳輸工廠例項transportFactory,它是通過TransportProvider例項mTransportProvider的getServerTransportFactory()方法來獲取的,而mTransportProvider的初始化也是在AlluxioMaster構造方法中,通過TransportProvider.Factory.create(conf)來獲取的,我們看下程式碼:
public static TransportProvider create(Configuration conf) { AuthType authType = conf.getEnum(Constants.SECURITY_AUTHENTICATION_TYPE, AuthType.class); switch (authType) { case NOSASL: return new NoSaslTransportProvider(conf); case SIMPLE: // intended to fall through case CUSTOM: return new PlainSaslTransportProvider(conf); case KERBEROS: throw new UnsupportedOperationException( "getClientTransport: Kerberos is not supported currently."); default: throw new UnsupportedOperationException( "getClientTransport: Unsupported authentication type: " + authType.getAuthName()); } }
它目前僅支援NOSASL和CUSTOM兩種型別,分別對應NoSaslTransportProvider和PlainSaslTransportProvider兩個類。我們以CUSTOM型別的PlainSaslTransportProvider為例來看下getServerTransportFactory()方法,程式碼如下:
@Override public TTransportFactory getServerTransportFactory() throws SaslException { AuthType authType = mConfiguration.getEnum(Constants.SECURITY_AUTHENTICATION_TYPE, AuthType.class); TSaslServerTransport.Factory saslFactory = new TSaslServerTransport.Factory(); AuthenticationProvider provider = AuthenticationProvider.Factory.create(authType, mConfiguration); saslFactory .addServerDefinition(PlainSaslServerProvider.MECHANISM, null, null, new HashMap<String, String>(), new PlainSaslServerCallbackHandler(provider)); return saslFactory; }
剩餘的TThreadPoolServer例項構造、引數選擇等上面解釋的已經很清晰,讀者可自行分析。
未完待續,請關注《Alluxio原始碼分析:RPC框架淺析(三)》!
相關文章
- Dubbo原始碼淺析(一)—RPC框架與Dubbo原始碼RPC框架
- Spark RPC框架原始碼分析(二)RPC執行時序SparkRPC框架原始碼
- RXSwift原始碼淺析(二)Swift原始碼
- Spark RPC框架原始碼分析(一)簡述SparkRPC框架原始碼
- 淺析 及整體分析 Relay 原始碼原始碼
- Spark RPC框架原始碼分析(三)Spark心跳機制分析SparkRPC框架原始碼
- Hadoop3.2.1 【 YARN 】原始碼分析 :AdminService 淺析HadoopYarn原始碼
- quicklink原始碼淺析UI原始碼
- Koa 原始碼淺析原始碼
- 淺析Redux原始碼Redux原始碼
- String原始碼淺析原始碼
- webmagic原始碼淺析Web原始碼
- Lifecycle原始碼淺析原始碼
- Redux原始碼淺析Redux原始碼
- ThreadLocal 原始碼淺析thread原始碼
- redux 原始碼淺析Redux原始碼
- go rpc 原始碼分析GoRPC原始碼
- 以太坊原始碼分析(51)rpc原始碼分析原始碼RPC
- Flutter 原始碼系列:DropdownButton 原始碼淺析Flutter原始碼
- Paging Library原始碼淺析原始碼
- String 原始碼淺析(一)原始碼
- Discuz! Q 原始碼淺析原始碼
- 【QT】QThread原始碼淺析QTthread原始碼
- Guava原始碼淺析——JoinerGuava原始碼
- 比特幣原始碼分析--RPC比特幣原始碼RPC
- 淺析webpack原始碼之convert-argv模組(二)Web原始碼
- 以太坊原始碼分析(13)RPC分析原始碼RPC
- Timer機制原始碼淺析原始碼
- RecyclerView動畫原始碼淺析View動畫原始碼
- react原始碼淺析(三):ReactChildrenReact原始碼
- react原始碼淺析(三):ReactElementValidatorReact原始碼
- react原始碼淺析(三):ReactElementReact原始碼
- Spring-IOC原始碼淺析Spring原始碼
- react-router 原始碼淺析React原始碼
- Android桌面Launcher原始碼淺析Android原始碼
- 【QT】 QThread部分原始碼淺析QTthread原始碼
- react-window 原始碼淺析React原始碼
- Single-spa 原始碼淺析原始碼
- Flutter 之 InheritWidget 原始碼淺析Flutter原始碼