Time

Physical time: is measured by physical clocks which tick with a certain rate

Logical time: is measured by logical clocks which tick when events occur

Clock skew: the difference in timing between two or more clocks in a distributed system

Physical clocks #

Measure real world time

  • Perfect clock: $C(t)$
  • Correct clock $C_i(t)$: $C_i(t)= C(t)$
  • Accurate clock $C_i(t)$: $dC_i(t)/dt = 1$
  • Synchronized clocks $C_i(t)$ and $C_k(t)$ at time $t$: $C_i(t) = C_k(t)$

Measuring between local events: no synchronization required, however clock should be sufficiently accurate

Measuring between events on two different systems: clocks should be synchronized but don't need to be current, and sufficiently accurate

Clock synchronization: each system $i$ calculates its clock based on the distributed values by a function $f$. $$ c_i(t) = f(C_j, C_k) $$

  • Coordinated Universal Time (UTC): the primary time standard that regulates clocks and time worldwide.
  • Maximum clock skew $\delta$ (seconds): how much difference you allow to occur within the system.
  • Maximum drift rate $c$: crystal clocks are not perfect, determinates the maximum error from "real time".

Both determine the frequency of clock synchronization, resynchronization should happen at least every $\delta/2c$ if clocks should not be more than $\delta$ apart.

Cristian's Clock Synchronization algorithm #

There is a master server that has a UTC receiver. Slave servers query master server (at least every $\delta/2c$ seconds) and then updates it clock by estimating the masters current time ($C_M'$) after receiving response: $$ C_M'(T_1) = C_M + P\ $$ $$ P = (T_1 - T_0 - I) / 2 $$ where $C_M$ is the masters time, $T_0$ is the time of the request, $T_1$ the time of the response and $I$ the interrupt handling time.

More exact estimations can be done by performing multiple measurements and ignoring the measurements where $T_1 - T_0$ exceeds a certain threshold. The software clock can be slowed down without breaking by letting some interrupts pass.

Lamport's Clock Synchronization algorithm #

There is no "master" time, instead time servers periodically exchange information. If a process sends a message the timestamp is added, if a message is received the clock is set to max (received timestamp + minimum of propagation delay, own clock value). Modelled as a directed graph (with diameter $d$, the longest, shortest path between two vertices) A message is sent at least every $\tau$ seconds on one edge of the graph.

Under assumptions, $\delta \approx d(2c\tau + z)~~ \forall t \geq t_0 + \tau d$

Logical clocks #

Logical clocks provide a consistent ordering of events in distributed system without using actual time. They are used in a wide range of distributed algorithms like mutual exclusion, replication and deadlock detection.

Causal dependencies #

Causal / $a$ happens before $b$: strict partial order $a \rightarrow b$

  • $a$ is executed before $b$ in the same process: $a \rightarrow b$
  • $a$ sends a message to $b$: $a \rightarrow b$
  • let $a$, $b$ and $c$ be events in any process, if $a \rightarrow b$ and $b \rightarrow c$, then $a \rightarrow c$ (transitivity)

Concurrent / causally unrelated $a\ ||\ b$: $\neg (a \rightarrow b) \land \neg (b \rightarrow a)$

Scalar clocks #

Each process keeps a clock which starts at 0, on a event or send the clock value is increased by one

Scalar clock condition, a system of scalar clocks is correct when: $$ \forall a, b, : a \rightarrow b \Rightarrow C(a) < C(b) $$

Synchronization algorithm #

  • Initialization $C(p_i) := 0$
  • Local event / send: $C(p_i) := C(c_pi) + 1$
  • Receive: $C(p_i) := \max(C(c_pi),C(m')) + 1$

Lamports Distributed Mutual Exclusion Algorithm #

  • Every process has a request queue (RQ) that contains requests $Req(T_r: p_i)$ to lock the resource, $T_r$ is the time of the request.
  • A process can lock the resource if it has a $Req(T_r : P_i)$ in its RQ before all other requests AND received a message with timestamp $> T_r$ from all other processes.
  • When a resource is released $Releasse(T_j: P_i)$ is send to all other processes and the $Req$ is removed from all queues.

Vector clocks #

The system of vector clocks is correct, when $$ \forall a, b : a \rightarrow b \Leftrightarrow VC(a) < VC(b) $$

Vector timestamp: $n$-dimensional vector where $n$ is the number of processes in the system

Causal history of event $e$: $$ \downarrow(e) = { e' \mid e'\ _r\rightarrow e } $$ $_r\rightarrow$ is the reflexive closure of $\rightarrow$ the set of events up till and including the event

Mathematical functions: $$ VC_1 \leq VC_2 \Leftrightarrow \forall i : VC_1[i] \leq VC_2[i] $$ $$ VC_1 || VC_2 \Leftrightarrow \neg (VC_1 \leq VC_2) \land \neg (VC_2 \leq VC_1) $$ $$ VC_1 < VC_2 \Leftrightarrow VC_1 \leq VC_2 \land VC_1 \neq VC_2 $$

Supremum (component-wise max): $$ sup(VC_1, VC_2) = \forall i : max(VC_1[i], VC_2[i]) $$

Synchronization algorithm #

  • Local event: increases own component
  • Sending: increase and include value in message
  • Receiving: increase own component and calculate supremum