0% found this document useful (0 votes)
11 views18 pages

801 DCexp 3

The document outlines the implementation of group communication in distributed systems, focusing on absolute, consistent, and causal ordering mechanisms. It explains the importance of group communication for synchronization, data sharing, and reliability among multiple nodes. Additionally, it provides code examples for transaction systems and social media applications to illustrate these concepts in practice.

Uploaded by

Bhumika Nalawade
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views18 pages

801 DCexp 3

The document outlines the implementation of group communication in distributed systems, focusing on absolute, consistent, and causal ordering mechanisms. It explains the importance of group communication for synchronization, data sharing, and reliability among multiple nodes. Additionally, it provides code examples for transaction systems and social media applications to illustrate these concepts in practice.

Uploaded by

Bhumika Nalawade
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

ROLL NO.

B801
Experiment No: 3

Aim: Implementation of Group Communication(1-M, N-1, M-N) (Absolute ordering, Consistent


ordering and Causal ordering)
Theory:
Group Communication in Distributed Systems:
Group communication in distributed systems refers to the process where multiple nodes or entities
communicate with each other as a group.
●​ Instead of sending messages to individual recipients, group communication allows a sender to
transmit information to all members of a group simultaneously.
●​ This method is essential for coordinating actions, sharing data, and ensuring that all participants in
the system are informed and synchronized. It’s particularly useful in scenarios like collaborative
applications and real-time updates.

Importance of Group Communication in Distributed Systems


Group communication is critically important in distributed systems due to several key reasons:

●​ Multiple nodes must collaborate and synchronize their actions. Group communication helps them
exchange information and stay updated.
●​ Different nodes can create data that needs to be shared. Group communication helps quickly send
this information to everyone involved, reducing delays and keeping data consistent.
●​ Group communication protocols enhance reliability by allowing messages to be replicated or
acknowledged across multiple nodes. This ensures robust communication, even during failures or
network issues.
●​ As distributed systems expand, effective scaling is crucial. Group communication mechanisms can
manage more nodes and messages without sacrificing performance, keeping the system efficient
and responsive.
Types of Group Communication in a Distributed System
1. Unicast Communication
Unicast communication is the point-to-point transmission of data between two nodes in a network. In
the context of distributed systems:
●​ Unicast is when a sender sends a message to a specific recipient, using their unique network
address.
●​ Each message targets one recipient, creating a direct connection between the sender and the
receiver.
●​ You commonly see unicast in client-server setups, where a client makes requests and receives
responses, as well as in direct connections between peers.
●​ This method makes good use of network resources, is easy to implement, and keeps latency low
because messages go straight to the right person.
●​ Unicast isn’t efficient for sending messages to many recipients at once, as it requires separate
messages for each one, leading to more work.

2. Multicast Communication

Multicast communication involves sending a single message from one sender to multiple receivers
simultaneously within a network. It is particularly useful in distributed systems where broadcasting
information to a group of nodes is necessary:

●​ Multicast lets a sender share a message with a specific group of people who want it.
●​ This way, the sender can reach many people at once, which is more efficient than sending separate
messages.
●​ This approach is often used to send updates to subscribers or in collaborative applications where
real-time sharing of changes is needed.
●​ By sending data just once to a group, multicast saves bandwidth, simplifies communication, and
can easily handle a larger number of recipients.
●​ Managing group membership is necessary to ensure reliable message delivery, and multicast can
run into issues if there are network problems that affect everyone in the group.
3. Broadcast Communication
Broadcast communication involves sending a message from one sender to all nodes in the network,
ensuring that every node receives the message:

Broadcast is when a sender sends a message to every node in the network without targeting specific
recipients.
●​ Messages are delivered to all nodes at once using a special address designed for this purpose.
●​ It’s often used for network management tasks, like sending status updates, or for emergency alerts
that need to reach everyone quickly.
●​ Broadcast ensures that every node receives the message without needing to specify who the
recipients are, making it efficient for sharing information widely.
●​ It can cause network congestion in larger networks and raises security concerns since anyone on
the network can access the broadcast message, which might lead to unauthorized access.

Group Communication Models:

1-M (Unicast to Multicast): This is the most common scenario. A central server (or any single
process) distributes information to multiple clients or replicas. Examples include:
●​ Distributing stock market updates.
●​ Sending notifications to subscribers.
●​ Updating replicated databases.
N-1 (Multicast to Unicast): Less common as a primary communication model, but can be used in
specific patterns. For instance:
●​ Multiple sensors sending data to a single aggregator.
●​ Clients sending requests to a central server. While the response might be 1-M, the initial
request is N-1.
M-N (Multicast to Multicast): The most general and complex case. Every member of a group can
send messages to every other member. Examples:
●​ Collaborative applications (e.g., shared document editing).
●​ Distributed consensus protocols (e.g., Paxos, Raft).
●​ Peer-to-peer systems.
ordering guarantees in distributed systems

1. Absolute Ordering (Total Ordering)

Concept: All processes in the system agree on a single, global order for all messages. It's like
having a single line where everyone waits their turn. If process A receives message m1
before m2, then all other processes that receive m1 and m2 must also receive them in that
same order.

Diagram:

Mechanisms:

●​ Centralized Sequencer: A single process assigns sequence numbers to all messages.


This is simple but creates a single point of failure and can be a bottleneck.
●​ Distributed Consensus: Protocols like Paxos, Raft, or Zab allow a group of processes
to agree on a total order without a central coordinator. More complex but more
fault-tolerant.

Challenges:

●​ Network delays: Messages might arrive out of order at different processes.


●​ Clock skew: Processes have slightly different clocks, making it hard to agree on a
global time.
●​ Fault tolerance: The sequencer or consensus mechanism must be robust to failures.
●​ Overhead: Achieving total order often involves significant communication and
coordination, adding latency.
Use Cases:

●​ Distributed transactions (e.g., banking systems).


●​ Replicated databases (ensuring consistent updates).
●​ Distributed locking (preventing race conditions).

2. Consistent Ordering (FIFO Ordering)

Concept: Messages from a single sender are delivered in the order they were sent. However,
there are no guarantees about the order of messages from different senders. Imagine
multiple lines at a ticket counter. Each line is served in order, but the order in which people
from different lines get tickets might be arbitrary.

Diagram:

Mechanisms: Each sender maintains a sequence number for its own messages. Receivers use these
sequence numbers to ensure FIFO order from each sender.
Advantages: Simpler to implement than total ordering.
Disadvantages: Doesn't provide a global view of message order, which can lead to inconsistencies in
some applications.
Use Cases:

●​ Client-server applications where each client's requests are processed in order.


●​ Message queues where messages from a single producer are delivered in order.
3. Causal Ordering

Concept: Preserves cause-and-effect relationships between messages. If message m2 was


caused by message m1 (e.g., m2 is a response to m1, or the content of m2 depends on m1),
then m2 must be delivered after m1 to all processes.

Mechanisms:

●​ Vector Clocks: Capture causal relationships. Each process has a vector of counters.
When a process sends a message, it increments its own counter and includes the
vector clock in the message. The receiver updates its own clock by taking the
maximum of each element.
●​ Matrix Clocks: An extension of vector clocks for more complex causal relationships.

Challenges: Determining causality can be complex, especially in large systems.​

Use Cases:

●​ Distributed simulations.
●​ Collaborative editing.
●​ Distributed databases where the order of operations matters.
## Implementation:

transaction_system.py - Absolute Ordering Implementation

from dataclasses import dataclass

import time

from typing import List, Dict

from queue import PriorityQueue

import threading

@dataclass

class Transaction:

transaction_id: int

sender: str

amount: float

timestamp: float

sequence_number: int

def __lt__(self, other):

return self.sequence_number < other.sequence_number

class TransactionNode:

def __init__(self, node_id: str):

self.node_id = node_id

self.sequence_number = 0

self.transaction_queue = PriorityQueue()

self.processed_transactions = []

self.lock = threading.Lock()

self.balance = 1000.0 # Initial balance


def create_transaction(self, amount: float) -> Transaction:

with self.lock:

self.sequence_number += 1

return Transaction(

transaction_id=self.sequence_number,

sender=self.node_id,

amount=amount,

timestamp=time.time(),

sequence_number=self.sequence_number

def process_transaction(self, transaction: Transaction):

with self.lock:

self.transaction_queue.put(transaction)

self.balance -= transaction.amount

self.processed_transactions.append(

f"Processed: Transaction {transaction.transaction_id} "

f"from {transaction.sender} for ${transaction.amount:.2f} "

f"(Balance: ${self.balance:.2f})"

class TransactionSystem:

def __init__(self):

self.nodes: Dict[str, TransactionNode] = {}

self.global_sequence = 0
self.lock = threading.Lock()

def add_node(self, node_id: str):

self.nodes[node_id] = TransactionNode(node_id)

def submit_transaction(self, sender_id: str, amount: float):

with self.lock:

self.global_sequence += 1

transaction = self.nodes[sender_id].create_transaction(amount)

transaction.sequence_number = self.global_sequence

# Process transaction on all nodes in the same order

for node in self.nodes.values():

node.process_transaction(transaction)

def main():

# Create transaction system

system = TransactionSystem()

# Add nodes (representing different parts of the system)

system.add_node("user1")

system.add_node("user2")

system.add_node("user3")

print("Starting Transaction System Demo...")

print("-" * 50)

# Submit transactions

transactions = [

("user1", 100.0),

("user2", 150.0),
("user1", 200.0),

("user3", 300.0)

for sender, amount in transactions:

system.submit_transaction(sender, amount)

time.sleep(0.1) # Small delay for demonstration

# Print processed transactions for each node

for node_id, node in system.nodes.items():

print(f"\nNode {node_id} Transaction Log:")

for log in node.processed_transactions:

print(log)

if __name__ == "__main__":

main()
social_media_consistent.py - Consistent Ordering Implementation

from dataclasses import dataclass

import time

from typing import List, Dict

from queue import Queue

import threading

@dataclass

class Post:

post_id: int

user_id: str

content: str

timestamp: float

class SocialMediaUser:

def __init__(self, user_id: str):

self.user_id = user_id

self.post_queue = Queue()

self.feed = []

self.post_count = 0

self.lock = threading.Lock()

def create_post(self, content: str) -> Post:

with self.lock:

self.post_count += 1

return Post(

post_id=self.post_count,
user_id=self.user_id,

content=content,

timestamp=time.time()

def receive_post(self, post: Post):

self.post_queue.put(post)

self.feed.append(

f"[{time.strftime('%H:%M:%S', time.localtime(post.timestamp))}] "

f"{post.user_id}: {post.content}"

class ConsistentSocialNetwork:

def __init__(self):

self.users: Dict[str, SocialMediaUser] = {}

def add_user(self, user_id: str):

self.users[user_id] = SocialMediaUser(user_id)

def publish_post(self, user_id: str, content: str):

post = self.users[user_id].create_post(content)

# Deliver to all users in consistent order

for user in self.users.values():

user.receive_post(post)

def main():

# Create social network

network = ConsistentSocialNetwork()
# Add users

network.add_user("alice")

network.add_user("bob")

network.add_user("charlie")

print("Starting Social Media Demo (Consistent Ordering)...")

print("-" * 50)

# Simulate posts

posts = [

("alice", "Hello everyone!"),

("bob", "Hi Alice!"),

("charlie", "Hey folks!"),

("alice", "How's everyone doing?")

for user_id, content in posts:

network.publish_post(user_id, content)

time.sleep(0.1) # Small delay for demonstration

# Print feeds

for user_id, user in network.users.items():

print(f"\n{user_id}'s Feed:")

for post in user.feed:

print(post)

if __name__ == "__main__":

main()
social_media_causal_demo.py
from dataclasses import dataclass
import time
from typing import List, Dict, Optional
@dataclass
class SocialPost:
post_id: int
user_id: str
content: str
timestamp: float
parent_id: Optional[int] = None
post_type: str = 'post' # 'post', 'comment', or 'reaction'
class User:
def __init__(self, user_id: str):
self.user_id = user_id
self.feed = []
self.post_count = 0
def receive_post(self, post: SocialPost):
self.feed.append(post)
def display_feed(self):
# Sort posts by timestamp
sorted_posts = sorted(self.feed, key=lambda x: x.timestamp)
# Display posts with proper indentation
for post in sorted_posts:
timestamp = time.strftime('%H:%M:%S', time.localtime(post.timestamp))
if post.post_type == 'post':
print(f"[{timestamp}] {post.user_id}: {post.content}")
elif post.post_type == 'comment':
print(f" [{timestamp}] {post.user_id} replied: {post.content}")
else: # reaction
print(f" [{timestamp}] {post.user_id} reacted: {post.content}")
class SocialNetwork:
def __init__(self):
self.users: Dict[str, User] = {}
self.global_post_count = 0

def add_user(self, user_id: str):


self.users[user_id] = User(user_id)
def create_post(self, user_id: str, content: str, post_type='post', parent_id=None) -> SocialPost:
self.global_post_count += 1
post = SocialPost(
post_id=self.global_post_count,
user_id=user_id,
content=content,
timestamp=time.time(),
parent_id=parent_id,
post_type=post_type
)
# Deliver to all users
for user in self.users.values():
user.receive_post(post)
# Add small delay to ensure proper ordering
time.sleep(0.1)
return post.post_id
def run_demo():
# Create network and add users
network = SocialNetwork()
users = ["Alice", "Bob", "Charlie", "David"]
for user in users:
network.add_user(user)
print("Starting Social Media Demo (Causal Ordering with Dependencies)...")
print("-" * 60)
print("\nCreating social media interactions...")

😊
# Create a post
post_id = network.create_post("Alice", "Hello everyone! How's your day going? ")


# Create comments
network.create_post("Bob", "Great! Having coffee ", "comment", post_id)
network.create_post("Charlie", "Just finished a meeting!", "comment", post_id)

❤️
# Create reactions
network.create_post("David", " ", "reaction", post_id)
# Alice responds to comments
network.create_post("Alice", "Coffee sounds perfect right now!", "comment", post_id)
# Print each user's feed
print("\nDisplaying user feeds:")
print("-" * 60)
for user_id, user in network.users.items():
print(f"\n{user_id}'s Feed:")
user.display_feed()
print("-" * 30)
if __name__ == "__main__":
run_demo()
Conclusion:The implementation demonstrates how different ordering mechanisms (Absolute,
Consistent, and Causal) ensure proper message sequencing in distributed systems, with Absolute
ordering guaranteeing global sequence, Consistent ordering ensuring same view for all users, and
Causal ordering maintaining logical dependencies between related messages.

You might also like