\documentclass[a4,titlepage]{seminar} %\usepackage[cp850]{inputenc} %wirkt nicht? \usepackage{fancybox} \usepackage{german} \usepackage{color} \usepackage{semcolor} \usepackage{pstricks} \usepackage{pst-node} \slideframe{none} \rotateheaderstrue \renewcommand{\theslide}{ \arabic{slide} } \centerslidesfalse \pagestyle{myheadings} \markright{\rm Robuste verteilte Programmierung in Haskell} \newcommand{\stitle}[1]{\centerline{\shadowbox{\Large{\blue #1}}}} \newcommand{\Haskell}{\textsc{Haskell}} \newcommand{\CH}{\textsc{Concurrent Haskell}} \newcommand{\Erlang}{\textsc{Erlang}} \newcommand{\DHS}{\textsc{Distributed Haskell}} \newcommand{\QBox}[1]{\psframebox{\parbox{2cm}{\Large\bf\tt #1}}} \begin{document} \setlength{\slidewidth}{24cm} %\renewcommand{\sliderightmargin}{10cm} %------------------------------ \begin{slide} \pagestyle{empty} \title{\stitle{Robuste verteilte Programmierung in Haskell} \vfill} \author{Volker Stolz \\ Lehrstuhl f"ur Informatik II \\ RWTH Aachen \\ Betreuer: Frank Huch } \date{23. Oktober 2000} \maketitle \vfill \end{slide} %------------------------------ \begin{slide} \stitle{"Uberblick} \vfill \begin{itemize} \item Verteilte Systeme, Kommunikation \& \DHS \item \CH \item Implementierung der Mailbox in \DHS \item Zust"ande in der funktionalen Programmierung \item Bestandteile von \DHS \begin{itemize} \item Kommunikation zwischen Prozessen \item Registrierte Dienste \item Verbindungscache \item \textit{Linking} von Prozessen \end{itemize} \item Ein real existierendes \DHS-Programm \end{itemize} \vfill \end{slide} %------------------------------ \begin{slide} \stitle{Warum verteilte Systeme} \begin{itemize} \item Client-Server Anwendungen \begin{itemize} \item Bankautomaten, Telephonie \item offene System (\textit{instant messaging}) \end{itemize} \item eingebettete Systeme \item wissenschaftliches Rechnen\\(meist auf Clustern mit fester Knotenzahl) \end{itemize} Demn"achst auch: \begin{itemize} \item \textit{Roaming}\\ Auffinden/Benutzen von Serverdiensten in Netzen\\ (Beispiel \textbf{Jini}) \end{itemize} \end{slide} %------------------------------ \begin{slide} \stitle{Kommunikationsmodelle} \vfill \begin{center} \begin{itemize} \item verbindungslos $\leftrightarrow$ verbindungsorientiert? \item verl"a"slich $\leftrightarrow$ unverl"a"slich? \item Datenstrom oder einfacher Zugang zu h"oheren Datenstrukturen? \end{itemize} \end{center} Au"serdem: \begin{center} \begin{itemize} \item ben"otigt die Anbindung spezielle Bibliotheken? \item ben"otigt auch der Client eine Laufzeitumgebung? \end{itemize} \end{center} \vfill \end{slide} %------------------------------ \begin{slide} \stitle{Kommunikationsmechanismen} \vfill \begin{itemize} \item Bibliotheken \begin{itemize} \item MPI,PVM \item []{\begin{tabbing} Nachteil: \=Bibliothek muss auch auf Client-Seite installiert sein\\ \>Nur in geschlossenem System einsetzbar\\ Vorteil: \>Optimiert f"ur wissenschaftliche Anwendungen durch\\ \>Ausnutzung evtl.~vorhandener spezieller Hardware \end{tabbing}} \end{itemize} \item TCP/IP \item []{\begin{tabbing} Nachteil: \=Daten lediglich als Bytestrom\\ Vorteil: \>"Uberall verf"ugbar\\ \>Somit auch offene Systeme m"oglich \end{tabbing}} \end{itemize} \vfill \end{slide} %------------------------------ \begin{slide} \stitle{Kommunikation in \Erlang/\DHS} \vfill Sprachkonstrukte: \vfill \begin{tabular}{llll} $\bullet$ & \ttfamily\textit{Pid} \textit{data} &$\bullet$ & \ttfamily\textit{Pid} $\Leftarrow$ spawn \textit{func}\\ $\bullet$ & \ttfamily remoteSend \textit{uri data} &$\bullet$ & \ttfamily link \textit{Pid}\\ $\bullet$ & \ttfamily receive & $\bullet$ & \ttfamily\textit{Pid} $\Leftarrow$ spawnLink \textit{func}\\ \end{tabular} \vfill \begin{itemize} \item[$\rightarrow$] \textit{\texttt{Pids}} $\cong$ global eindeutige Referenz auf Proze"s \item[$\rightarrow$] \texttt{receive} greift "uber \textsl{Pattern Matching} je einen Eintrag aus Mailbox heraus \end{itemize} \vfill {\ttfamily \begin{tabular}{|l|l|l|l|} \hline Inc & Get \rnode{ref1}{\textsl{$p_1$}} & Get \rnode{ref2}{\textsl{$p_n$}} & ...\\ \hline \end{tabular} \hspace{2cm} \begin{tabular}{l} \Rnode{box1}{\begin{tabular}{|l|l|l|} \hline Inc & Dec & ...\\ \hline \end{tabular}}\\[2ex] \Rnode{box2}{\begin{tabular}{|l|l|l|} \hline Dec & Dec & ...\\ \hline \end{tabular}} \end{tabular} \ncarc[arcangleA=90,nodesep=3pt]{->}{ref1}{box1} \ncarc[arcangleA=270,arcangleB=-10,nodesep=2pt]{->}{ref2}{box2} } \end{slide} %------------------------------ \begin{slide} \stitle{Ein einfaches \DHS-Programm (1)} \vfill \def\arraystretch{0.9} \ttfamily\small \begin{tabular}[t]{@{}|l|@{}} \hline import Distributed\\ \\ Msg = Inc | Dec | Get Pid |\\ ~~~~~~~~Value Int\\ \\ counter n = do\\ ~~receive\\ ~~~~Inc -> counter (n+1)\\ ~~~~Dec -> counter (n-1)\\ ~~~~Get pid -> do\\ ~~~~~~pid (Value n)\\ ~~~~~~counter n\\ \hline \end{tabular}\hfill \begin{tabular}[t]{@{}|l|@{}} \hline import Distributed\\ \\ Msg = Get Pid | Value Int\\ \\ main = do\\ ~~pid <- spawn (Counter.counter 0)\\ ~~me <- self\\ ~~pid (Get me)\\ ~~receive\\ ~~~~Value v -> do\\ ~~~~~~print v\\ \hline \end{tabular} \end{slide} %------------------------------ \begin{slide} \extraslideheight{10in} \stitle{Ein einfaches \DHS-Programm (2)} \vfill \def\arraystretch{0.9} \ttfamily\small \begin{tabular}[t]{@{}|l|@{}} \hline import Distributed\\ Msg = Inc | Dec | Get Pid |\\ ~~~~~~~~Value Int\\ \\ start = do\\ ~~register \char34 Counter\char34\\ ~~counter 0\\ \\ counter n = do\\ ~~receive\\ ~~~~Inc -> counter (n+1)\\ ~~~~Dec -> counter (n-1)\\ ~~~~Get pid -> do\\ ~~~~~~pid (Value n)\\ ~~~~~~counter n\\ \hline \end{tabular}\hfill \begin{tabular}[t]{@{}|l|@{}} \hline import Distributed\\ Msg = Get Pid | Value Int\\ \\ main = do\\ ~~let uri =\\ ~~~~\char34 dhs://node@host/Counter\char34\\ ~~pid <- remoteLookup uri\\ ~~me <- self\\ ~~pid (Get me)\\ ~~receive\\ ~~~~Value v -> do\\ ~~~~~~print v\\ \hline \end{tabular} \end{slide} %------------------------------ \begin{slide} \stitle{Kommunikationsmechanismen in \CH} \vfill \begin{center} \begin{itemize} \item \textbf{MVars} (\textit{synchronising variables}) {\ttfamily \begin{tabbing} newEmptyMVar \=:: IO (MVar a)\\ takeMVar \>:: MVar a -> IO a\\ putMVar \>:: MVar a -> a -> IO () \end{tabbing}} \item \textbf{Channels} {\ttfamily \begin{tabbing} newChan \=:: IO (Chan a)\\ writeChan \>:: Chan a -> a -> IO ()\\ readChan \>:: Chan a -> IO a \end{tabbing}} \item \textbf{Threads}\\ {\ttfamily forkIO :: IO () -> IO ThreadId } \end{itemize} \end{center} \vfill \end{slide} %------------------------------ \begin{slide} \stitle{Ein kurzes \CH-Programm} \vfill % \small \ttfamily \def\arraystretch{0.9} \centerline{\begin{tabular}{l} main :: IO ()\\ main = do\\ ~~ch <- newChan\\ ~~\char95~~<- forkIO ( loopCh ch )\\ ~~loopKbd ch \end{tabular}} \vfill \begin{tabular}[t]{@{}l@{}} loopCh :: Chan String -> IO ()\\ loopCh ch = do\\ ~~msg <- readChan ch\\ ~~putStrLn (\char34Text: \char34~+ msg)\\ ~~loopCh ch \end{tabular}\hfill \begin{tabular}[t]{l@{}} loopKbd :: Chan String -> IO ()\\ loopKbd ch = do\\ ~~putStr \char34 Eingabe> \char34\\ ~~i <- getLine\\ ~~writeChan ch i\\ ~~loopKbd ch\\ \end{tabular} \end{slide} %------------------------------ \begin{slide} \stitle{Implementierung der Mailbox} Zwei Bestandteile: \begin{itemize} \item \texttt{Channel String} als Verbindung zur Au"senwelt "uber den \textit{Dicitionary}-Proze"s \item \texttt{[Msg]} als interne Darstellung der Mailbox \end{itemize} \renewcommand{\labelitemi}{$\rightarrow$} Funktionsweise: \begin{itemize} \item Andere Prozesse schreiben die Nachricht als String in den Channel\\ Beachte: Zeitliche Reihenfolge bleibt erhalten! \item Beim Aufruf von \texttt{receive} werden die Strings in den algebraischen Datentyp \texttt{Msg} umgewandelt und -- wiederum unter Erhalt der zeitlichen Reihenfolge -- in einer Liste gespeichert. \end{itemize} \end{slide} %------------------------------ \begin{slide} \stitle{\textit{(De-) Serializing} in \Haskell} \vfill \begin{itemize} \item Klassen \texttt{Read \& Show} wandeln algebraischen Datentypen\\ in Strings und umgekehrt:\\ \texttt{show :: (Show a) => a -> String}\\ \texttt{read :: (Read a) => String -> a}\\ \texttt{data Msg = A | B | \ldots\ deriving (Show,Read)} \item \texttt{receive} ben"otigt somit den Zieltyp:\\ {\ttfamily % \def\arraystretch{0.9} % \begin{tabular}[t]{@{}l@{~}l} receive :: (Read a, Show a) => (a -> (DIO a b)) -> DIO a b % \end{tabular} } \item Bei komplexeren Daten kann der Benutzer \texttt{read} und \texttt{show} "uberladen \end{itemize} \vfill \end{slide} %------------------------------ \begin{slide} \stitle{Nachteile der Mailbox-Implementierung} \vfill \begin{itemize} \item nur Daten mit String-Repr"asentation m"oglich \item \textit{Serializing/Deserializing} sehr aufwendig \item Nachrichtenkonstruktoren m"ussen \glqq handverlesen\grqq\ sein \end{itemize} \small Beispiel:\\ \texttt{ A.Msg = Ping \char124\ Pong \char124\ Text String\\ B.Msg = Inc \char124\ Dec \char124\ Text Int} Client (Versuch 1):\\ \texttt{ data Msg = A.Ping \char124\ A.Pong \char124\ B.Inc \char124\ B.Text Int} Client (Versuch 2):\\ \texttt{ data Msg = Ping \char124\ Pong \char124\ Inc \char124\ Text Int} Allerdings unm"oglich:\\ \texttt{ data Msg = Ping \char124\ Pong \char124\ Text (String \char124\ Int)} \end{slide} %------------------------------ \begin{slide} \stitle{Zust"ande in der funktionalen Programmierung} \vfill \DHS\ ben"otigt Zust"ande bzw.~ globale Variablen f"ur das Laufzeitsystem (Proze"sverwaltung, Ein-/Ausgabe-Kan"ale, ...) Dazu kommen weitere Proze"s-interne Zust"ande: \begin{itemize} \item eigene Pid \item Mailbox \end{itemize} \textbf{H"aufiges Problem:} (Globale) Zust"ande erschweren Programmierung.\\ \textbf{Au"serdem:} I/O-Operationen in \Haskell\ erforden spezielle Handhabung \vfill \end{slide} %------------------------------ \begin{slide} \stitle{Zust"ande: M"ogliche L"osungen} \vfill \begin{itemize} \item \glqq Durchschleifen\grqq\ des Zustands als Parameter\\ Nachteil: un"ubersichtlich, l"astig \item Monaden (basierend auf \textit{continuations})\\ Nachteil: Verschachtelung von Monaden schwierig \end{itemize} Monaden "ubernehmen das \glqq Durchschleifen ihrer Welt\grqq\ durch Konkatenation bei sequentieller Ausf"uhrung. {\bf Beispiel IO-Monade:} \begin{itemize} \item \texttt{type IO a = World -> (a,World)} \end{itemize} {\bf DIO-Monade:} \begin{itemize} \item Erweiterung der IO-Monade um die ben"otigten Zust"ande \end{itemize} \vfill \end{slide} %------------------------------ \begin{slide} \stitle{Das \DHS\ Laufzeitsystem: Proze"ssicht} \vfill \psset{nodesep=3pt} \begin{tabular}{llll} & \multicolumn{2}{c}{DHS-Laufzeitsystem} & \\[3ex] \Rnode{lokal}{\psframebox{DHS-Proze"s}} & \multicolumn{2}{c}{\Rnode{dict1}{Dictionary}} & \Rnode{remote}{\psframebox{DHS-Proze"s}}\\[5ex] & \Rnode{spalte1}{ \begin{tabular}{cc} \Rnode{n1}{I/O-Proze"s} & \Rnode{m1}{Dictionary}\\[2ex] \Rnode{n2}{Verbindungscache} & \Rnode{m2}{PortListener}\\[2ex] \Rnode{n3}{Netzwerk} & \Rnode{m3}{Netzwerk} \end{tabular}} & \end{tabular} \ncarc{->}{lokal}{dict1} \aput{:U}{Intern?} \ncarc{->}{dict1}{remote} \ncarc[arcangleB=15]{->}{lokal}{spalte1} \aput{:U}{Extern?} \ncline{->}{n1}{n2} \ncline{->}{n2}{n3} \ncarc[arcangleA=-35,arcangleB=-35]{->}{n3}{m3} \ncline{->}{m3}{m2} \ncline{->}{m2}{m1} \ncarc{->}{spalte1}{remote} \vfill \begin{center} \texttt{data Pid = Pid (\textsl{host,port}) Integer} \end{center} %\vfill %\textbf{"ahnlicher Verlauf} bei Nachrichten mittels \texttt{\textsl{remoteSend \& remoteLookup}} \vfill \end{slide} %------------------------------ \begin{slide} \stitle{\DHS: Registrierte Dienste} \vfill \begin{itemize} \item Knoten k"onnen Prozesse anbieten und unter einem Namen registrieren \begin{itemize} \item Registrierung des Knotennamens beim Start \item Prozesse benutzen \textsl{register} \end{itemize} \item Mit diesen Prozessen k"onnen andere Prozesse kommunizieren: \begin{itemize} \item entweder durch \textsl{remoteSend} \item oder durch \textsl{remoteLookup} (Abbildung von Namen auf Pids) \end{itemize} \end{itemize} Dazu n"otig: \begin{itemize} \item D\char26 mon auf dem Rechner, welcher registrierte Dienste anbieten will \item hier: \texttt{dhd} auf TCP-Port 10008 \end{itemize} \vfill \end{slide} %------------------------------ \begin{slide} \stitle{Das \DHS\ Laufzeitsystem: Netzwerksicht} \vfill Server: \texttt{triton}\hfill Client: \texttt{agamemnon}\\ \vspace{2ex} \fbox{\parbox{0.4\textwidth}{ \begin{center} \vspace*{0.2cm} \psframebox{DHD} \vspace*{0.5cm} \begin{tabular}{|c|} \hline Knoten{\it 1}\\ \textit{\char34 DBServer\char34}\\\hline RTS\\\hline Proze"s{\it 1}\\ ...\\ Proze"s{\it n}\\ \hline \end{tabular} \begin{tabular}{|c|} \hline Knoten{\it 2}\\ \textit{\char34 Counter\char34}\\\hline RTS\\\hline \\ ...\\ \\ \hline \end{tabular} \end{center}}}\hfill \fbox{\parbox{0.4\textwidth}{ \begin{center} \begin{tabular}{|c|} \hline Knoten\\\hline RTS\\\hline Proze"s \\ ...\\ \hline \end{tabular} \end{center}}} \end{slide} %------------------------------ \begin{slide} \stitle{\DHS: Verbindungscache} \vfill Kommunikation zwischen Knoten in bisheriger Implementierung mit TCP\\ $\rightarrow$ mehrere DHS-Prozesse benutzen dieselbe Verbindung \begin{itemize} \item Minimierung der Latenz durch weniger Verbindungsaufbauten \item Zeitweiser Verbindungsabbau bei Inaktivit"at \item Vgl. persistente Verbindungen in \texttt{HTTP/1.1} \end{itemize} \vfill \Rnode{I1}{\psframebox{Proze"s 1}}~\Rnode{I2}{\psframebox{Proze"s 2}}\hfill\Rnode{O1}{\psframebox{Proze"s 3}}~\Rnode{O2}{\psframebox{Proze"s 4}} \begin{center} \rnode{Box}{ \begin{tabular}[t]{|c||c|c||c|c||c|c||c|} \hline ... & 0 & Inc & 5 & Dec & 0 & Inc & ...\\\hline \end{tabular} } \end{center} \ncangle[nodesep=1pt,angleA=-90,angleB=180,offsetB=-5pt]{->}{I1}{Box} \ncangle[nodesep=1pt,angleA=-90,angleB=180,offsetA=-16pt,offsetB=5pt]{->}{I2}{Box} \ncangle[nodesep=1pt,angleB=270,offsetB=-16pt,offsetA=5pt]{->}{Box}{O1} \ncangle[nodesep=1pt,angleB=270,offsetA=-5pt]{->}{Box}{O2} \end{slide} %------------------------------ \begin{slide} \stitle{\DHS: \textit{Linking}} Implementierung: \begin{itemize} \item {\bf Entfernter Knoten} mu"s best.~Datenpakete best"atigen \item {\bf Lokaler Proze"s} erh"alt im Fehlerfall die Nachricht\\ \hspace*{1cm}\texttt{Down \textsl{pid}} \item kann durch \texttt{receive} aufgefangen werden kann \end{itemize} \vfill Wichtig: \begin{itemize} \item Implementierung (fast) nur auf Seite des Linkenden \item \glqq gelinkter\grqq~Proze"s bemerkt nur \texttt{Ping}-Anforderungen \item Linking nicht beschr"ankt auf Richtung Client $\rightarrow$ Server!\\ % H"aufig ist es wichtig, da"s auch der Server von der Terminierung des Clients erf"ahrt! \end{itemize} \end{slide} %------------------------------ \begin{slide} \stitle{Was wir geschafft haben} \begin{itemize} \item Eine komfortable Programmierumgebung f"ur die robuste verteilte Programmierung offener Systeme in \Haskell \item Versenden von Daten welche sich als Strings kodieren lassen\\ \end{itemize} \stitle{Noch Durchzuf"uhren} \begin{itemize} \item Vergleich mit Port-basiertem \Haskell: \begin{itemize} \item Anderes Kommunikationsmodell:\\ "Ubertragung der \texttt{Channel} auf Netzwerkebene % \item[$\rightarrow$] \textit{multiple writer / single reader} \end{itemize} \item Implementierung eines umfangreicheren Beispiels \item Leistungsbewertung \end{itemize} \vfill \end{slide} %------------------------------ \extraslideheight{10in} \begin{slide} % \stitle{\DHS-Demo} \ttfamily\footnotesize \def\arraystretch{0.8} \begin{tabular}[t]{@{}l@{}} main = Distributed.start\\ ~~(do register \char34 dataBase\char34\\ ~~~~~~dataBase []) \char34 DB-Server\char34\\ \\ dataBase :: [(String,String)]\\ ~~~~~~~~~~~~~~-> DIO Msg ()\\ dataBase l = receive (\char92 v -> case v of\\ ~~Shutdown -> halt\\ ~~Connect pid -> do\\ %~~~~me <- self\\ ~~~~pid (Connect me)\\ ~~~~dataBase l\\ ~~Lookup key pid -> do\\ %~~~~proc \$ putStrLn (\char34 Lookup : \char34++key)\\ ~~~~pid (IsValue (lookup key l))\\ ~~~~dataBase l\\ ~~Alloc key pid ->\\ ~~~~case lookup key l of\\ ~~~~~~Nothing -> do\\ ~~~~~~~~pid Free\\ ~~~~~~~~receive (\char92 v' -> case v' of\\ ~~~~~~~~~~Value v pid' | pid'==pid -> do\\ %~~~~~~~~~~~~proc \$ putStrLn (\char34 New entry : \char34++key)\\ ~~~~~~~~~~~~dataBase ((key,v):l))\\ ~~~~~~Just \_ -> do\\ ~~~~~~~~pid Allocated\\ ~~~~~~~~dataBase l)\\ \end{tabular} \hfill \footnotesize \def\arraystretch{0.8} \begin{tabular}[t]{@{}||l@{}} client :: Pid -> DIO Msg ()\\ client pid = do\\ ~~me <- self\\ ~~case str of\\ ~~~~\char34 i\char34 -> do\\ ~~~~~~key <- proc \$ getLine\\ ~~~~~~pid (Alloc key me)\\ ~~~~~~receive (\char92 v -> case v of\\ ~~~~~~~~Free -> do\\ ~~~~~~~~~~v <- proc \$ getLine\\ ~~~~~~~~~~pid (Value v me)\\ ~~~~~~~~~~client pid\\ ~~~~~~~~Allocated -> client pid\\ ~~~~~~~~Down \char92 -> halt)\\ ~~~~\char34 l\char34 -> do \\ ~~~~~~key <- proc \$ getLine\\ ~~~~~~pid (Lookup key me)\\ ~~~~~~receive (\char92 v -> case v of\\ ~~~~~~~~IsValue mStr -> do\\ ~~~~~~~~~~proc \$ print mStr\\ ~~~~~~~~~~client pid\\ ~~~~~~~~Down \_ -> halt)\\ ~~~~\char34 Q\char34 -> do\\ ~~~~~~pid Shutdown; halt\\ %~~~~~~halt \end{tabular} \end{slide} %------------------------------ \end{document}