LogCabin: Distributed System Built on Raft

Consensus State


\documentclass[border=2pt]{standalone}

%% Fonts
%\usepackage{fontspec}
%% Default Features
%\defaultfontfeatures{
%	Mapping=tex-text,
%	Ligatures=TeX,
%}
%% Serif Font
%\setmainfont[
%	UprightFont=EBGaramond-Regular,
%	ItalicFont=EBGaramond-Italic,
%	BoldFont=EBGaramond-Bold,
%	BoldItalicFont=EBGaramond-BoldItalic,
%]{EB Garamond}
%% Mono Font
%\setmonofont[
%	UprightFont=JetBrainsMonoNL-Regular,
%	ItalicFont=JetBrainsMonoNL-Italic,
%	BoldFont=JetBrainsMonoNL-Bold,
%	BoldItalicFont=JetBrainsMonoNL-BoldItalic,
%]
%{JetBrains Mono}

% Tikz
\usepackage{tikz}
\usetikzlibrary{calc, positioning, shapes}

% Colors
%\definecolor{myyellow}{RGB}{255, 255, 191}
%\definecolor{mygreen}{RGB}{171, 221, 164}
%\definecolor{myblue}{RGB}{216, 225, 246}
% Dimensions
\def\deltadim{0.1}
\def\cornerradius{0.2cm}
\def\innersep{6pt}
\def\outersep{2pt}
% Threads
\def\threaddrawcolor{yellow!60!black}
\def\threadfillcolor{yellow!20}
\def\shift{1cm}
%% Peer threads
\def\numpeerthreads{4}
%% Service Threads
\def\numservicethreads{3}
%% Timer Threads
\def\numtimerthreads{2}
% Consensus State
\def\consensusstatedrawcolor{green!70!black}
\def\consensusstatefillcolor{green!20}
\def\consensusstateheight{2.25cm}
\def\consensusstatewidth{4.5cm}
% Lock
\def\lockdrawcolor{orange!50!black}
\def\lockfillcolor{orange!50}
\def\lockhandlecolor{black}
\def\locksize{12pt}
% Data Store
\def\datastoredrawcolor{orange!80!black}
\def\datastorefillcolor{orange!60}
\def\datastoreheight{6pt}
\def\datastorewidth{12pt}

% Styles
\tikzset{
	% labels
	label/.style={
		font=\small\ttfamily,
		align=center,
	},
	% node labels
	node_label/.style={
		font=\small,
		align=center,
	},
	% general
	module/.style={
		draw,
		very thick,
		label,
		outer sep=\outersep,
		rounded corners=\cornerradius,
		shape=rectangle,
	},
	% threads
	thread/.style={
		module,
		draw=\threaddrawcolor,
		fill=\threadfillcolor,
		inner xsep=\innersep,
		inner ysep=\innersep,	
	},
	% consensus state
	consensus_state/.style={
		module,
		draw=\consensusstatedrawcolor,
		fill=\consensusstatefillcolor,
		minimum height=\consensusstateheight,
		minimum width=\consensusstatewidth,
	},
	% parts of consensus state
	consensus_state_parts/.style={
		module,
		draw=\consensusstatedrawcolor,
		fill=\consensusstatefillcolor,
		inner xsep=\innersep,
		inner ysep=\innersep,
	},
	% lock
	lock_body/.style={
		draw=\lockdrawcolor,
		fill=\lockfillcolor,
		very thick,
		shape=rectangle,
		minimum size=\locksize,
		inner sep=0,
		outer sep=0,
	},
	lock_handle/.style={
		draw=black,
		very thick, 
		looseness=2
	},
	% data store
	data_store/.style={
		draw=\datastoredrawcolor,
		fill=\datastorefillcolor,
		thick,
		ellipse,
		inner sep=0,
		minimum height=\datastoreheight,
		minimum width=\datastorewidth,
	},
	% connections
	connection/.style={
		thick,
		-stealth,
	},
	% traffic
	inbound_traffic/.style={
		very thick,
		latex-,
	},
	outbound_traffic/.style={
		very thick,
		-latex,
	}
}

\begin{document}
	\begin{tikzpicture}
		% Consensus state
		\node [
			consensus_state,
		] (consensus state) {consensus state};
		%% Configuration
		\node [
			consensus_state_parts,
			anchor=south west,
			shift={(0,-\shift*2)},
		] (configuration) at (consensus state.south west) {configuration};
		%% Lock
		\coordinate (lock_body_x) at ($(configuration.mid)!0.5!(configuration.west)$);
		\node[
			lock_body,
			anchor=north,
			shift={(0,\outersep + \locksize/2)},
		] (lock_body) at (lock_body_x|-consensus state.south) {};
		\draw[
			lock_handle
		] (lock_body.125) to[out=90, in=90] (lock_body.55);
		%% Log
		\node [
			consensus_state_parts,
			anchor=south east,
			shift={(0,-\shift*2)},
		] (log) at (consensus state.south east) {log};
		%% Data store
		\foreach \i in {0,...,2} {
			\node[
				data_store,
				shift={(\datastorewidth/10,\i * \datastoreheight/2)},
			] at (log.south east) {};
		}	
	
		% Peer threads
		\coordinate (peer_thread) at ($(consensus state.south west) + (-\shift,0)$);
		
		\foreach \i in {1,...,\numpeerthreads} {
			\pgfmathsetmacro{\displacement}{\i * \deltadim}
			\node[
				thread,
				anchor=east
			] (peer_thread\i) at ($(peer_thread) + (-\displacement,\displacement)$) {peer\\thread};
		}

		% Service threads
		\coordinate (service_thread) at ($(consensus state.north west) + (-\shift,0)$);
		
		\foreach \i in {1,...,\numservicethreads} {
			\pgfmathsetmacro{\displacement}{\i * \deltadim}
			\node[
				thread,
				anchor=east
			] (service_thread\i) at ($(service_thread) + (-\displacement,\displacement)$) {service\\thread};
		}
		
		% State Machine
		\node[
			thread,
			anchor=south
		] (state_machine_thread) at ($(consensus state.north) + (0,\shift)$) {state machine\\thread};
		
		% Timer threads
		\coordinate (timer_thread) at ($(consensus state.north east) + (\shift,0)$);
		
		\foreach \i in {1,...,\numtimerthreads} {
			\pgfmathsetmacro{\displacement}{\i * \deltadim}
			\node[
				thread,
				anchor=west
			] (timer_thread\i) at ($(timer_thread) + (-\displacement,\displacement)$) {timer\\thread};
		}
		
		% Log synch thread
		\node[
			thread,
			anchor=west
		] (log_synch_thread) at ($(consensus state.south east) + (\shift,0)$) {log synch\\thread};
		
		% Part of
		\draw[thick] (consensus state.south-|configuration) -- (configuration);
		\draw[thick] (consensus state.south-|log) -- (log);
		
		% Traffic
		\draw[
			inbound_traffic,
			node_label
		] (service_thread\numservicethreads) 
						-- +(-\shift*3,0) 
						node[pos=0.5, above, align=center] {inbound\\RPCs};
		\draw[
			outbound_traffic,
			node_label
		] (peer_thread\numpeerthreads) 
						-- +(-\shift*3,0) 
						node[pos=0.5, above, align=center] {outbound\\RPCs};
		
		% Connections
		\draw[connection] (log_synch_thread) -- (log);
		\draw[connection] (log_synch_thread) -- (consensus state);
		\draw[connection] (timer_thread\numtimerthreads) -- (consensus state);
		\draw[connection] (state_machine_thread) -- (consensus state);		
		\draw[connection] (service_thread1) -- (consensus state);
		\draw[connection] (peer_thread1) -- (consensus state);
	\end{tikzpicture}
\end{document}

Replicated State Machine


\documentclass[border=2pt]{standalone}

%% Fonts
%\usepackage{fontspec}
%% Default Features
%\defaultfontfeatures{
%	Mapping=tex-text,
%	Ligatures=TeX,
%}
%% Serif Font
%\setmainfont[
%	UprightFont=EBGaramond-Regular,
%	ItalicFont=EBGaramond-Italic,
%	BoldFont=EBGaramond-Bold,
%	BoldItalicFont=EBGaramond-BoldItalic,
%]{EB Garamond}
%% Mono Font
%\setmonofont[
%	UprightFont=JetBrainsMonoNL-Regular,
%	ItalicFont=JetBrainsMonoNL-Italic,
%	BoldFont=JetBrainsMonoNL-Bold,
%	BoldItalicFont=JetBrainsMonoNL-BoldItalic,
%]
%{JetBrains Mono}

% Tikz
\usepackage{tikz}
\usetikzlibrary{calc, positioning, shapes}

% Colors
%\definecolor{myyellow}{RGB}{255, 255, 191}
%\definecolor{mygreen}{RGB}{171, 221, 164}
%\definecolor{myblue}{RGB}{216, 225, 246}
% Dimensions
\def\deltadimclient{0.1}
\def\deltadimserver{0.2}
\def\padding{0.4cm}
\def\cornerradius{0.2cm}
\def\logentrieslinewidth{0.7pt}
\def\innersep{6pt}
\def\outersep{2pt}
% Client
\def\numclients{3}
\def\clientdrawcolor{gray!60!black}
\def\clientfillcolor{gray!25}
% Server
\def\numservers{4}
\def\serverdrawcolor{\clientdrawcolor}
\def\serverfillcolor{\clientfillcolor}
\def\serverheight{5.7cm}
\def\serverwidth{6.5cm}
% Replicated
\def\replicateddrawcolor{green!70!black}
\def\replicatedfillcolor{green!20}
% Entries
\def\logentriesdrawcolor{cyan!100}
\def\logentriesfillcolor{cyan!20}
\def\entriesheight{15pt}
\def\entrieswidth{34pt}
\def\textspace{2mm}
% Data Store
\def\datastoredrawcolor{orange!80!black}
\def\datastorefillcolor{orange!60}
\def\datastoreheight{9pt}
\def\datastorewidth{18pt}
% Connections
\def\connectionshift{0.35}
\def\labelinnersep{1.5pt}

% Styles
\tikzset{
	% labels
	label/.style={
		font=\footnotesize\ttfamily,
		align=center,
	},
	% node labels
	node_label/.style={
		draw,
		thick,
		inner sep=\labelinnersep,
		shape=circle,
		align=center,
	},
	% general
	module/.style={
		draw,
		very thick,
		label,
		outer sep=\outersep,
		rounded corners=\cornerradius,
		shape=rectangle,
	},
	% client
	client/.style={
		module,
		draw=\clientdrawcolor,
		fill=\clientfillcolor,
		inner xsep=\innersep,
		inner ysep=\innersep,	
	},
	% server
	server/.style={
		module,
		draw=\serverdrawcolor,
		fill=\serverfillcolor,
		minimum height=\serverheight,
		minimum width=\serverwidth,
	},
	% replicated 
	replicated/.style={
		module,
		draw=\replicateddrawcolor,
		fill=\replicatedfillcolor,
		inner sep = \innersep,
	},
	% log and state machine entries
	entries/.style={
		shape=rectangle,
		draw=\logentriesdrawcolor,
		line width=\logentrieslinewidth,
		fill=\logentriesfillcolor,
		rounded corners=0cm,
		minimum height=\entriesheight,
		minimum width=\entrieswidth,
		inner ysep=0pt,
		inner xsep=\innersep/2,
		outer sep=0pt,
	},
	% data store
	data_store/.style={
		draw=\datastoredrawcolor,
		fill=\datastorefillcolor,
		thick,
		ellipse,
		inner sep=0,
		minimum height=\datastoreheight,
		minimum width=\datastorewidth,
	},
	% connections
	connection/.style={
		thick,
		-stealth,
	}
}

\begin{document}
	\begin{tikzpicture}
		% Server
		\foreach \i in {1,...,\numservers} {
			\pgfmathsetmacro{\displacement}{\i * \deltadimserver}
			\node[
				server,
				anchor = west,
			] (server\i) at (-\displacement, \displacement) {};
		}
		%% Label
		\node[
			label,
			anchor=north west,
			shift={(\padding,-\padding)},
		] at (server\numservers.north west){server};
		
		% Log
		\node[
			replicated,
			anchor = south west,
			shift={(\padding,\padding)},
		] (log) at (server\numservers.south west) {%
			log
			%
			\\[\textspace]
			%
			\begin{tikzpicture}
				\node[
					entries
				] (log1) {$x \leftarrow 3$};
				%
				\node[
					entries,
					anchor=west,
					xshift=-\logentrieslinewidth
				] (log2) at (log1.east) {$y \leftarrow 7$};
				%
				\node[
					entries,
					anchor=west,
					xshift=-\logentrieslinewidth
				] (log3) at (log2.east) {$y \leftarrow 9$};
				%
				\node[
					entries,
					anchor=west,
					xshift=-\logentrieslinewidth
				] (log4) at (log3.east) {$\cdots$};
			\end{tikzpicture}%
		};
		%% Data store
		\foreach \i in {0,...,2} {
			\node[
				data_store,
				shift={(\datastorewidth/6,\i * \datastoreheight/2)},
			] at (log.south east) {};
		}	
		
		% State Machine
		\node[
			replicated,
			anchor = north east,
			shift={(-\padding,-\padding)},
		] (state machine) at (server\numservers.north east) {%
			state machine
			%
			\\[\textspace]
			%
			\begin{tikzpicture}
				\node[
					entries
				] (sm1) {$x : 3$};
				%
				\node[
					entries,
					anchor=north,
					yshift=\logentrieslinewidth
				] (sm2) at (sm1.south) {$y : 9$};
				%
				\node[
					entries,
					anchor=north,
					yshift=\logentrieslinewidth
				] (sm3) at (sm2.south) {$z : 0$};
				%
			\end{tikzpicture}
		};
		
		% Consensus Module
		\node[
			replicated,
			anchor = west,
			shift={(\padding,0)},
		] (consensus module) at (server\numservers.west|-state machine.west) {consensus\\module};	

		% Client
		\coordinate (client) at (-3,0|-consensus module);
		
		\foreach \i in {1,...,\numclients} {
			\pgfmathsetmacro{\displacement}{\i * \deltadimclient}
			\node[
				client,
			] (client\i) at ($(client) + (-\displacement,\displacement)$) {client};
		}
		
		% Arrows
		%% client -> consensus module
		\draw[connection] (client\numclients)
									 to[out=50, in=150] 
									 node[node_label, shift={(0,-\connectionshift)}] {1}
						  (consensus module);
		%% consensus module -> log
		\draw[connection] (consensus module) 
									to[out=270, in=140] 
									node[node_label, shift={(-\connectionshift,0)}] {2} 
						  (log);
		%% log -> state machine
		\draw[connection] (log) 
									to[out=0, in=300] 
									node[node_label, pos=0.7, shift={(\connectionshift,0)}] {3} 
						  (state machine);
		%% state machine -> client
		\draw[connection] (state machine) 
									to[out=140, in=70] 
									node[node_label, shift={(0,\connectionshift)}] {4} 
						  (client\numclients);
		%% consensus module -> server
		\foreach \i in {1,...,\numservers} {
			\ifnum\i=\numservers\else 
			\draw[connection] (consensus module) 
										to[out=190, in=195, looseness=1.5] 
										node[shift={(-\connectionshift,0)}] (server_node\i) {} 
							  (server\i.south west);
			\fi
		}
		%%% Label
		\node[
			node_label
		] at (server_node1) {2};
	\end{tikzpicture}
\end{document}

Unoptimized Raft Pipeline


\documentclass[border=2pt]{standalone}

%% Fonts
%\usepackage{fontspec}
%% Default Features
%\defaultfontfeatures{
%	Mapping=tex-text,
%	Ligatures=TeX,
%}
%% Serif Font
%\setmainfont[
%	UprightFont=EBGaramond-Regular,
%	ItalicFont=EBGaramond-Italic,
%	BoldFont=EBGaramond-Bold,
%	BoldItalicFont=EBGaramond-BoldItalic,
%]{EB Garamond}
%% Mono Font
%\setmonofont[
%	UprightFont=JetBrainsMonoNL-Regular,
%	ItalicFont=JetBrainsMonoNL-Italic,
%	BoldFont=JetBrainsMonoNL-Bold,
%	BoldItalicFont=JetBrainsMonoNL-BoldItalic,
%]
%{JetBrains Mono}

% Tikz
\usepackage{tikz}
\usetikzlibrary{calc, positioning, shapes}

% Colors
%\definecolor{myyellow}{RGB}{255, 255, 191}
%\definecolor{mygreen}{RGB}{171, 221, 164}
%\definecolor{myblue}{RGB}{216, 225, 246}
% Dimensions
\def\deltadim{0.2pt}
\def\innersep{3pt}
\def\servershift{1.5cm}
\def\shortenlen{2pt}
% Pipeline stages
\def\stageslinewidth{1.5pt}
\def\stagesdrawcolor{magenta!100}
\def\stagesfillcolor{magenta!20}
\def\stagesheight{30pt}
\def\stageswidth{66pt}
%% Followers
\def\followersnum{4}
% Connections
\def\connectionshift{0.35}
\def\labelinnersep{1.5pt}

% Styles
\tikzset{
	% labels
	label/.style={
		font=\large\ttfamily,
		align=center,
	},
	% Pipeline stages
	stages/.style={
		shape=rectangle,
		draw=\stagesdrawcolor,
		line width=\stageslinewidth,
		fill=\stagesfillcolor,
		rounded corners=0cm,
		minimum height=\stagesheight,
		minimum width=\stageswidth,
		label,
		inner ysep=0pt,
		inner xsep=\innersep,
		outer sep=0pt,
	},
	% connections
	connection/.style={
		very thick,
		-stealth,
		shorten <=\shortenlen , shorten >=\shortenlen
	}
}

\begin{document}
	\begin{tikzpicture}
		% Leader replicates log
		\node[
			stages
		] (leader_receive) {receive};
		%
		\node[
			stages,
			anchor=west,
		] (leader_append) at (leader_receive.east) {append};
		%
		\node[
			stages,
			anchor=west,
		] (leader_sync) at (leader_append.east) {sync};
		
		% Followers receive AppendEntries
		\foreach \i in {\followersnum,...,1} {
			\pgfmathsetmacro{\displacement}{(\i-1) * \deltadim}
			\node[
				stages,
				anchor=west,
				shift={(\servershift,0)},
			] (follower_request\i) at 
			  ($(leader_sync.east) + (\displacement,-\displacement)$) 
			  {request};
			%
			\node[
				stages,
				anchor=west,
			] (follower_append\i) at (follower_request\i.east) {append};
			%
			\node[
				stages,
				anchor=west,
			] (follower_sync\i) at (follower_append\i.east) {sync};		
			%
			\node[
				stages,
				anchor=west,
			] (follower_response\i) at (follower_sync\i.east) {response};		
		}
		
		% Leader applies committed entries
		\node[
			stages,
			anchor=west,
			shift={(\servershift,0)},
		] (leader_commit) at 
		  (follower_response1.east-|follower_response\followersnum.east) 
		  {commit};
		%
		\node[
			stages,
			anchor=west,
		] (leader_apply) at (leader_commit.east) {apply};
		%
		\node[
			stages,
			anchor=west,
		] (leader_reply) at (leader_apply.east) {reply};
		
		% Connections
		%% Leader -> Followers
		\foreach \i in {\followersnum,...,1} {
			\draw [
				connection
			] (leader_sync.east) to[out=0, in=210] (follower_request\i.south west);
		}
		%% Followers -> Leader
		\foreach \i in {\followersnum,...,1} {
			\draw [
				connection
			] (follower_response\i.north east) to[out=30, in=180] (leader_commit.west);
		}
		
		% Labels
		\pgfmathsetmacro{\consensus}{int(\followersnum/2)}
		\node [
			align=center,
			shift={(0,1.5)}
		]
			at ($(follower_response1)!0.5!(leader_commit)$) 
			{\Large wait for \\\Large\consensus\ out of \followersnum};
	\end{tikzpicture}
\end{document}

Optimized Raft Pipeline


\documentclass[border=2pt]{standalone}

%% Fonts
%\usepackage{fontspec}
%% Default Features
%\defaultfontfeatures{
%	Mapping=tex-text,
%	Ligatures=TeX,
%}
%% Serif Font
%\setmainfont[
%	UprightFont=EBGaramond-Regular,
%	ItalicFont=EBGaramond-Italic,
%	BoldFont=EBGaramond-Bold,
%	BoldItalicFont=EBGaramond-BoldItalic,
%]{EB Garamond}
%% Mono Font
%\setmonofont[
%	UprightFont=JetBrainsMonoNL-Regular,
%	ItalicFont=JetBrainsMonoNL-Italic,
%	BoldFont=JetBrainsMonoNL-Bold,
%	BoldItalicFont=JetBrainsMonoNL-BoldItalic,
%]
%{JetBrains Mono}

% Tikz
\usepackage{tikz}
\usetikzlibrary{calc, positioning, shapes}

% Colors
%\definecolor{myyellow}{RGB}{255, 255, 191}
%\definecolor{mygreen}{RGB}{171, 221, 164}
%\definecolor{myblue}{RGB}{216, 225, 246}
% Dimensions
\def\deltadim{0.2pt}
\def\innersep{3pt}
\def\servershift{1.5cm}
\def\shortenlen{2pt}
% Pipeline stages
\def\stageslinewidth{1.5pt}
\def\stagesdrawcolor{magenta!100}
\def\stagesfillcolor{magenta!20}
\def\stagesheight{30pt}
\def\stageswidth{66pt}
%% Followers
\def\followersnum{4}
% Connections
\def\connectionshift{0.35}
\def\labelinnersep{1.5pt}

% Styles
\tikzset{
	% labels
	label/.style={
		font=\large\ttfamily,
		align=center,
	},
	% Pipeline stages
	stages/.style={
		shape=rectangle,
		draw=\stagesdrawcolor,
		line width=\stageslinewidth,
		fill=\stagesfillcolor,
		rounded corners=0cm,
		minimum height=\stagesheight,
		minimum width=\stageswidth,
		label,
		inner ysep=0pt,
		inner xsep=\innersep,
		outer sep=0pt,
	},
	% connections
	connection/.style={
		very thick,
		-stealth,
		shorten <=\shortenlen , shorten >=\shortenlen
	}
}

\begin{document}
	\begin{tikzpicture}
		% Leader replicates log
		\node[
			stages
		] (leader_receive) {receive};
		%
		\node[
			stages,
			anchor=west,
		] (leader_append) at (leader_receive.east) {append};
		%
		\node[
			stages,
			anchor=west,
		] (leader_sync) at (leader_append.east) {sync};
		
		% Followers receive AppendEntries
		\foreach \i in {\followersnum,...,1} {
			\pgfmathsetmacro{\displacement}{(\i-1) * \deltadim}
			\node[
				stages,
				anchor=west,
				shift={(\servershift,0)},
			] (follower_request\i) at 
			  ($(leader_sync.east) + (\displacement,-\displacement)$) 
			  {request};
			%
			\node[
				stages,
				anchor=west,
			] (follower_append\i) at (follower_request\i.east) {append};
			%
			\node[
				stages,
				anchor=west,
			] (follower_sync\i) at (follower_append\i.east) {sync};		
			%
			\node[
				stages,
				anchor=west,
			] (follower_response\i) at (follower_sync\i.east) {response};		
		}
		
		% Leader applies committed entries
		\node[
			stages,
			anchor=west,
			shift={(\servershift,0)},
		] (leader_commit) at 
		  (follower_response1.east-|follower_response\followersnum.east) 
		  {commit};
		%
		\node[
			stages,
			anchor=west,
		] (leader_apply) at (leader_commit.east) {apply};
		%
		\node[
			stages,
			anchor=west,
		] (leader_reply) at (leader_apply.east) {reply};
		
		% Connections
		%% Leader -> Followers
		\foreach \i in {\followersnum,...,1} {
			\draw [
				connection
			] (leader_sync.east) to[out=0, in=210] (follower_request\i.south west);
		}
		%% Followers -> Leader
		\foreach \i in {\followersnum,...,1} {
			\draw [
				connection
			] (follower_response\i.north east) to[out=30, in=180] (leader_commit.west);
		}
		
		% Labels
		\pgfmathsetmacro{\consensus}{int(\followersnum/2)}
		\node [
			align=center,
			shift={(0,1.5)}
		]
			at ($(follower_response1)!0.5!(leader_commit)$) 
			{\Large wait for \\\Large\consensus\ out of \followersnum};
	\end{tikzpicture}
\end{document}

Leave a Reply

Your email address will not be published.