2. Introduzione
• Il progetto Apache ™ Hadoop® sviluppa software open-source per il calcolo
affidabile, scalabile e distribuito.
• La libreria software Apache Hadoop è un framework che permette
l'elaborazione distribuita di grandi insiemi di dati nei cluster di computer
facendo uso di semplici modelli di programmazione.
• La libreria stessa è stata progettata per rilevare e gestire gli errori a livello di
applicazione.
• Il framework Hadoop è scritto per la maggior parte in Java
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
3. Introduzione
• Il progetto prevede questi macro-moduli:
• Hadoop Common: I programmi comuni di utility a supporto di tutti gli altri moduli di
Hadoop.
• HadoopYARN: Un framework per il job scheduling e per la gestione delle risorse del
cluster.
• Hadoop MapReduce: Un sistemaYARN-based per l'elaborazione parallela di grandi
insiemi di dati.
• Hadoop Distributed File System (HDFS ™): Un file system distribuito che fornisce un
accesso high-throughput ai dati delle applicazioni.
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
5. Processo di ricostruzione della documentazione
architetturale
• processo a cascata con una tecnica semi-automatica
• approccio bottom-up attraverso Non-Architecural Inputs
• Studio del codice java
• Supporto del tool Understand
Estrazione Astrazione Validazione
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
6. Processo di ricostruzione della documentazione
architetturale
• Le viste più importanti che questo processo ha fatto emergere:
• una vista di tipo Layered Style “clusterizzando” le classi e package analizzati;
• una ModuleView, con vari stili in seguito descritti nel dettaglio, che riporta gli aspetti della
comunicazione client-server tra Datanode e Namenode
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
7. Cosa abbiamo analizzato?
• Un package considerato per il primo aspetto è server che contiene le classi che attraverso i
loro metodi gestiscono i nodi fisici DN e NN, implementando diverse funzionalità come la
gestione del file system tramite gli inodes per il NN, e funzionalità di gestione dei blocchi e
delle repliche per il DN.
• Successivamente è stato analizzato il package ipc in cui sono presenti classi per
implementare il meccanismo RPC, in particolare attraverso la classe RPC.java
• Il package java.net che contiene le classi ed i metodi che permettono di sfruttare il
protocollo di reteTCP/IP, come ad esempio InetSocketAddress che crea un socket address
da un indirizzo ip e un numero di porto.
• I metodi di comunicazione considerati sono tutti quelli presenti nell’interfaccia java
DatanodeProtocol presente nel package org.apache.hadoop.hdfs.server.protocol. In
particolare abbiamo analizzato il metodo sendHeartbeat che consente al DN (Datanode) di
inviare messaggi periodici al NN (Namenode) che segnalano che il DN è ancora “vivo”,
inoltre in questo messaggio sono allegate statistiche di funzionamento, report, ecc.
• Altri aspetti che ci hanno portato a soffermarci su quelli appena esposti
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
8. ModuleView
Nome della vista Stili architetturale adottati Tipi di elementi
rappresentati
Tipi di relazioni
rappresentate
HadoopOverwiev Decomposition Style Package Is-part-of
LayeredStyle Server-
Ipc-Java.Net
Layered Style Layer Allowed to use
UseStyle package RPC Layered,
Decomposition, Uses
Styles.
Layer
Package
Use
DataNode NameNode
Communication
Uses Style,
Decomposition,
Generalization
Package, Classi,
Interfacce
Use, Implements,
Generalizzation
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
9. ModuleView [HadoopOverwiev]
Questa vista ha lo scopo di far comprendere a chi legge questo lavoro di reverse engineering
quali sono stati i package di hadoop su cui ci siamo concentrati, ovvero hdfs e ipc, per far
emergere i due aspetti descritti in seguito.
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Contiene le
funzionalità
per la gestione
del file system
distribuito
Contiene le classi
per l’utilizzo del
meccanismo RPC
10. ModuleView [HadoopOverwiev]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
• L’euristica utilizzata è DOH
• Questa euristica punta a determinare la struttura dei package. Per applicare
questa euristica abbiamo usato la funzionalità di understand Entity Filter.
• Vedi documentazione
11. ModuleView [UseStyle package RPC]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Contiene i package clusterizzati
attraverso l’euristica LSIH, che
contengono classi che gestiscono i nodi
fisici di questa architettura come NN e
DN e si servono dei livelli inferiori per
realizzare la comunicazione tra
quest’ultimi.
Contiene i package clusterizzati attraverso l’euristica
LIJH, che contengono classi che implementano un
meccanismo di RPC, ridefinito da apache per motivi di
prestazioni, e forniscono servizi ai livelli più alti per
sfruttare questo meccanismo astraendone i dettagli
implementativi.
Contiene i package e le relative classi
messe a disposizione da Oracle, che
permettono di sfruttare il protocollo
di reteTCP/IP.
12. ModuleView [UseStyle package RPC]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
//DataNode.java
import org.apache.hadoop.ipc.ProtobufRpcEngine;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.RemoteException;
…
// For InterDataNodeProtocol
public RPC.Server ipcServer;
…
private void initIpcServer(Configuration conf) throws IOException {
InetSocketAddress ipcAddr = NetUtils.createSocketAddr(
conf.getTrimmed(DFS_DATANODE_IPC_ADDRESS_KEY));
// Add all the RPC protocols that the Datanode implements
RPC.setProtocolEngine(conf, ClientDatanodeProtocolPB.class,
ProtobufRpcEngine.class);
ClientDatanodeProtocolServerSideTranslatorPB
clientDatanodeProtocolXlator =
new ClientDatanodeProtocolServerSideTranslatorPB(this);
BlockingService service =ClientDatanodeProtocolService
.newReflectiveBlockingService(clientDatanodeProtocolXlator);
ipcServer = new RPC.Builder(conf)
.setProtocol(ClientDatanodeProtocolPB.class)
.setInstance(service)
.setBindAddress(ipcAddr.getHostName())
.setPort(ipcAddr.getPort())
.setNumHandlers(
conf.getInt(DFS_DATANODE_HANDLER_COUNT_KEY,
DFS_DATANODE_HANDLER_COUNT_DEFAULT)).setVerbose(false)
.setSecretManager(blockPoolTokenSecretManager).build();
…
13. ModuleView [UseStyle package RPC]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
//RPC.java
package org.apache.hadoop.ipc;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.NoRouteToHostException;
import java.net.SocketTimeoutException;
import java.io.*;
import java.io.Closeable;
…
/**
* Get a proxy connection to a remote server
*
* @param protocol protocol class
* @param clientVersion client version
* @param addr remote address
* @param conf configuration to use
* @return the proxy
* @throws IOException if the far end through a RemoteException
*/
public static <T>T waitForProxy(
Class<T> protocol,
long clientVersion,
InetSocketAddress addr,
Configuration conf
) throws IOException {
return waitForProtocolProxy(protocol, clientVersion, addr, conf).getProxy();
}
…
14. ModuleView [UseStyle package RPC]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Questo grafico di Understand mostra che le dipendenze vanno verso IPC
16. ModuleView [UseStyle package RPC]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
• Razionale:
• Si è deciso di fornire questa vista per cercare di rappresentare l’architettura
a layer dei protocolli che permettono la comunicazione tra DN e NN,
consentendo ad un altro architetto di comprendere come le classi nel livello
più alto usano i servizi dei livelli inferiori per realizzare la comunicazione.
Questa vista può essere usata per effettuare una manutenzione ad esempio
perfettiva per migliorare le performance della comunicazione, o da un
tester se ad esempio vengono cambiate le classi di un livello inferiore e
quindi fare un testing di integrazione.
18. ModuleView [LayeredStyle Server-Ipc-Java.Net]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
• Euristiche utilizzate:
Nome Acronimo Elemento/Relazione
Use Server Ipc USIH Use
Use Ipc JavaNet UIJNH Use
LayerServerIpc LSIH Layer
LayerIpcJavanet LIJH Layer
DecompositionOverwiev DO package
19. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Trade off: tra il livello di dettaglio e leggibilità
20. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Classe BPServiceActor
richiama periodicamente il
metodo sendHeartBeat
• Il DN invia heartbeat
periodicamente
• Con l’euristica CPCDN troviamo
BPServiceActor
21. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
//Chiamato nel thread BPServiceActor
HeartbeatResponse sendHeartBeat() throws IOException {
StorageReport[] reports =
dn.getFSDataset().getStorageReports(bpos.getBlockPoolId());
if (LOG.isDebugEnabled()) {
LOG.debug("Sending heartbeat with " + reports.length +
" storage reports from service actor: " + this);
}
VolumeFailureSummary volumeFailureSummary = dn.getFSDataset()
.getVolumeFailureSummary();
int numFailedVolumes = volumeFailureSummary != null ?
volumeFailureSummary.getFailedStorageLocations().length : 0;
/*Qui viene chiamato il sendHeartBeat dell'oggetto DatanodeProtocolClientSideTranslatorPB che implementa
l'interfaccia datanodeProtocol, nota questo metodo è implementato anche da NamenodeRpcServer, ma in questo
caso non viene chiamata la sua implementazione*/
return bpNamenode.sendHeartbeat(bpRegistration, //DatanodeProtocolClientSideTranslatorPB bpNamenode; (lc 97)
reports,
dn.getFSDataset().getCacheCapacity(),
dn.getFSDataset().getCacheUsed(),
dn.getXmitsInProgress(),
dn.getXceiverCount(),
numFailedVolumes,
volumeFailureSummary);
}
22. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Il metodo sendHeartbeat usa diversi oggetti come
parametri, le cui classi sono all’interno del package protocol
23. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Usa i metodi della classe
datanode per ricavare le
statistiche e i report da
inviare al namenode
24. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Recuperati i dati chiama
un metodo della classe
puntata dalla dispendenza
d’uso stereotipata con
callForSend
25. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
//DatanodeProtocolClientSideTraslatorPB
//Implementa l'interfaccia DatanodeProtocol.java, chiamata da BPServiceActor
@Override
public HeartbeatResponse sendHeartbeat(DatanodeRegistration registration,
StorageReport[] reports, long cacheCapacity, long cacheUsed,
int xmitsInProgress, int xceiverCount, int failedVolumes,
VolumeFailureSummary volumeFailureSummary) throws IOException {
HeartbeatRequestProto.Builder builder = HeartbeatRequestProto.newBuilder()
.setRegistration(PBHelper.convert(registration))
.setXmitsInProgress(xmitsInProgress).setXceiverCount(xceiverCount)
.setFailedVolumes(failedVolumes);
builder.addAllReports(PBHelper.convertStorageReports(reports));
if (cacheCapacity != 0) {
builder.setCacheCapacity(cacheCapacity);
}
if (cacheUsed != 0) {
builder.setCacheUsed(cacheUsed);
}
if (volumeFailureSummary != null) {
builder.setVolumeFailureSummary(PBHelper.convertVolumeFailureSummary(
volumeFailureSummary));
}
HeartbeatResponseProto resp;
try {
/*private final DatanodeProtocolPB rpcProxy;*/
resp = rpcProxy.sendHeartbeat(NULL_CONTROLLER, builder.build());
} catch (ServiceException se) {
throw ProtobufHelper.getRemoteException(se);
}
DatanodeCommand[] cmds = new DatanodeCommand[resp.getCmdsList().size()];
int index = 0;
for (DatanodeCommandProto p : resp.getCmdsList()) {
cmds[index] = PBHelper.convert(p);
index++;
}
RollingUpgradeStatus rollingUpdateStatus = null;
if (resp.hasRollingUpgradeStatus()) {
rollingUpdateStatus = PBHelper.convert(resp.getRollingUpgradeStatus());
}
return new HeartbeatResponse(cmds, PBHelper.convert(resp.getHaStatus()),
rollingUpdateStatus);
• }
26. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Attraverso diverse
chiamate e mediante l’uso
del protocol buffer
vengono serializzate le
informazioni da inviare al
NN.
27. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
//DatanodeProtocolServerSideTraslatorPB
/*Dovrebbe implementare questo metodo di DatanodeProtocolPB (all'interno non c'è niente)*/
@Override
public HeartbeatResponseProto sendHeartbeat(RpcController controller,
HeartbeatRequestProto request) throws ServiceException {
HeartbeatResponse response;
try {
final StorageReport[] report = PBHelper.convertStorageReports(
request.getReportsList());
VolumeFailureSummary volumeFailureSummary =
request.hasVolumeFailureSummary() ? PBHelper.convertVolumeFailureSummary(
request.getVolumeFailureSummary()) : null;
/*impl è di tipo DatanodeProtocol, che è un interfaccia i cui metodi sono implementati da NamenodeRpcServer*/
response = impl.sendHeartbeat(PBHelper.convert(request.getRegistration()),
report, request.getCacheCapacity(), request.getCacheUsed(),
request.getXmitsInProgress(),
request.getXceiverCount(), request.getFailedVolumes(),
volumeFailureSummary);
} catch (IOException e) {
throw new ServiceException(e);
}
HeartbeatResponseProto.Builder builder = HeartbeatResponseProto
.newBuilder();
DatanodeCommand[] cmds = response.getCommands();
if (cmds != null) {
for (int i = 0; i < cmds.length; i++) {
if (cmds[i] != null) {
builder.addCmds(PBHelper.convert(cmds[i]));
}
}
}
builder.setHaStatus(PBHelper.convert(response.getNameNodeHaState()));
RollingUpgradeStatus rollingUpdateStatus = response
.getRollingUpdateStatus();
if (rollingUpdateStatus != null) {
builder.setRollingUpgradeStatus(PBHelper
.convertRollingUpgradeStatus(rollingUpdateStatus));
}
return builder.build();
}
28. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
DatanodeProtocol è
l’interfaccia che espone i
metodi per permettere al
DN di comunicare con il
NN.
29. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
//DatanodeProtocol (Interfaccia)
/**
* sendHeartbeat() tells the NameNode that the DataNode is still
* alive and well. Includes some status info, too.
* It also gives the NameNode a chance to return
* an array of "DatanodeCommand" objects in HeartbeatResponse.
* A DatanodeCommand tells the DataNode to invalidate local block(s),
* or to copy them to other DataNodes, etc.
* @param registration datanode registration information
* @param reports utilization report per storage
* @param xmitsInProgress number of transfers from this datanode to others
* @param xceiverCount number of active transceiver threads
* @param failedVolumes number of failed volumes
* @param volumeFailureSummary info about volume failures
* @throws IOException on error
*/
@Idempotent
public HeartbeatResponse sendHeartbeat(DatanodeRegistration registration,
StorageReport[] reports,
long dnCacheCapacity,
long dnCacheUsed,
int xmitsInProgress,
int xceiverCount,
int failedVolumes,
VolumeFailureSummary volumeFailureSummary)
throws IOException;
30. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Chiamata basata su
tecnologia RPC verso il
namenode
31. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
@Override // DatanodeProtocol
public HeartbeatResponse sendHeartbeat(DatanodeRegistration nodeReg,
StorageReport[] report, long dnCacheCapacity, long dnCacheUsed, int
xmitsInProgress, int xceiverCount, int failedVolumes, VolumeFailureSummary
volumeFailureSummary) throws IOException {
checkNNStartup();
verifyRequest(nodeReg);
return namesystem.handleHeartbeat(nodeReg, report, dnCacheCapacity,
dnCacheUsed, xceiverCount, xmitsInProgress, failedVolumes,
volumeFailureSummary);
}
32. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
• Attraverso FSNamesystem
si costruisce la risposta da
inviare al DN.
• Vengono generati i
DatanodeCommand.
• Mentre in protocol abbiamo
gli oggetti passati per
parametro dalla funzione.
33. ModuleView [Comunicazione DataNode NameNode]
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
HeartbeatResponse handleHeartbeat(DatanodeRegistration nodeReg,
StorageReport[] reports, long cacheCapacity, long cacheUsed,
int xceiverCount, int xmitsInProgress, int failedVolumes,
VolumeFailureSummary volumeFailureSummary) throws IOException {
readLock();
try {
//get datanode commands
final int maxTransfer = blockManager.getMaxReplicationStreams()
- xmitsInProgress;
DatanodeCommand[] cmds = blockManager.getDatanodeManager().handleHeartbeat(
nodeReg, reports, blockPoolId, cacheCapacity, cacheUsed,
xceiverCount, maxTransfer, failedVolumes, volumeFailureSummary);
//create ha status
final NNHAStatusHeartbeat haState = new NNHAStatusHeartbeat(
haContext.getState().getServiceState(),
getFSImage().getLastAppliedOrWrittenTxId());
return new HeartbeatResponse(cmds, haState, rollingUpgradeInfo);
} finally {
readUnlock();
}
}
34. ModuleView [Comunicazione DataNode NameNode]
• Questa vista è diretta ad ogni stackholder che vuole comprendere la
comunicazione tra DN e NN da una prospettiva statica. Può essere utilizzata come
base per creare un astrazione di più alto livello, oppure come guida per andare ad
approfondire lo studio dell’implementazione delle diverse classi che partecipano a
tale comunicazione.
• Ad una fase di estrazione effettuata dal codice, in particolare rispetto al metodo
sendHeartbeat, si sono susseguite diverse viste di più basso livello, fino ad arrivare
a questa. Abbiamo scelto questa vista perché offre il giusto livello di dettaglio per
mostrare questo aspetto della comunicazione.
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
35. ModuleView [Comunicazione DataNode
NameNode]
• Euristiche utilizzate:
Gioacchino Lonardo - Alessandro Pagliaro (GreenCode)
Nome Acronimo Elemento/Relazione
ClassePerComunicazioneDN CPCDNH CommunicationDN
ClasseNamenodeRpcServer CNNRPCSH NnCommunication
UsoForResponse UFRH Use
UseToRecoverForSend UTRFSH Use
CallForSend CFSH Use
UseI UIH Use
CallImpMethod CIMH Use
UsePB UPBH Use
CallRPC CRPCH Use
CallForResponse CFRH Use