Definition
- Peer – a node that acts as both a client and a server, capable of requesting work from others and serving work to others simultaneously.
- Peer Discovery – the mechanism by which a new node finds existing peers, often through a bootstrap list or a distributed directory.
- DHT (Distributed Hash Table) – a structured routing scheme like Kademlia that maps any key to a responsible peer, enabling lookups in about log(N) hops.
- Replication – storing each piece of data on multiple peers so that peers leaving does not lose data.
- Consensus – how peers agree on shared state without a central authority, using proof-of-work, proof-of-stake, or gossip protocols.
Normally National Bank of India has a central head office that every branch reports to and that is the single source of truth. In a peer-to-peer world there is no head office: each branch keeps its own copy of the shared ledger and talks directly to every other branch, and they agree on the truth by a majority voting protocol rather than by asking a boss. If one branch burns down, nothing is lost because every other branch has the full ledger.
Understanding the Concepts
What is Peer-to-Peer architecture?
In the common client-server model there is a clear asymmetry: clients ask, servers answer, and the server is the authority and often the bottleneck. Peer-to-Peer removes that asymmetry. Every peer runs the same software and plays both roles: it can serve data to others and request data from others. There is no central server that must be up for the system to function.
package com.bank.p2p;
/**
* A simplified peer that can both serve and request data.
* In a real P2P network, this communicates over sockets.
*/
public class BankPeer {
private final String peerId;
private final java.util.Map<String, String> localLedger = new java.util.HashMap<>();
public BankPeer(String peerId) {
this.peerId = peerId;
}
// Serve: respond to another peer's request
public String serve(String key) {
return localLedger.getOrDefault(key, "NOT_FOUND");
}
// Request: ask another peer for data
public String requestFrom(BankPeer other, String key) {
return other.serve(key);
}
public void store(String key, String value) {
localLedger.put(key, value);
}
}
Expected: each peer can both store/serve data and request data from others.
No central server required.
How does peer discovery work?
A new node needs to find existing peers to join the network. Common approaches include a bootstrap list of known seed nodes, a distributed directory, or multicast announcements on a local network.
package com.bank.p2p;
import java.util.ArrayList;
import java.util.List;
public class PeerDiscovery {
private final List<String> knownPeers = new ArrayList<>();
public PeerDiscovery(List<String> bootstrapNodes) {
knownPeers.addAll(bootstrapNodes);
}
public void discoverMore() {
// Ask each known peer for its neighbor list
System.out.println("Querying " + knownPeers.size() + " bootstrap nodes for more peers...");
// In production: connect to each, exchange peer lists
knownPeers.add("peer-4.nbi.internal");
knownPeers.add("peer-5.nbi.internal");
System.out.println("Known peers now: " + knownPeers.size());
}
public static void main(String[] args) {
PeerDiscovery discovery = new PeerDiscovery(
List.of("peer-1.nbi.internal", "peer-2.nbi.internal", "peer-3.nbi.internal")
);
discovery.discoverMore();
}
}
Querying 3 bootstrap nodes for more peers...
Known peers now: 5
How does DHT routing locate data?
A Distributed Hash Table like Kademlia maps both data keys and node IDs into the same hash space. Each key is served by the node whose ID is closest to the key hash, and lookups take about log(N) hops.
package com.bank.p2p;
import java.util.TreeMap;
public class SimpleDHT {
// Simulates a DHT ring with node positions
private final TreeMap<Integer, String> ring = new TreeMap<>();
public void addNode(String nodeId, int hashPosition) {
ring.put(hashPosition, nodeId);
}
public String findResponsible(String key) {
int keyHash = Math.abs(key.hashCode() % 1000);
var entry = ring.ceilingEntry(keyHash);
if (entry == null) entry = ring.firstEntry(); // wrap around
return entry.getValue();
}
public static void main(String[] args) {
SimpleDHT dht = new SimpleDHT();
dht.addNode("nbi-branch-mumbai", 100);
dht.addNode("nbi-branch-delhi", 400);
dht.addNode("nbi-branch-chennai", 700);
System.out.println("Account SAV2001 handled by: " + dht.findResponsible("SAV2001"));
System.out.println("Account CUR3005 handled by: " + dht.findResponsible("CUR3005"));
}
}
Account SAV2001 handled by: nbi-branch-delhi
Account CUR3005 handled by: nbi-branch-chennai
When is Peer-to-Peer the right fit?
The deciding factor is that decentralization is a hard requirement, not a nice-to-have. Blockchain exists precisely because no single party should control the ledger. BitTorrent uses P2P so popular files are served by thousands of peers rather than one overloaded server. Mesh networks use P2P because there may be no central infrastructure available at all.
| Use Case | Decentralization Hard Req? | P2P Fit? |
|---|---|---|
| Cryptocurrency / blockchain | Yes, no trusted central authority | Yes |
| BitTorrent file sharing | Yes, no single server to shut down | Yes |
| Disaster-relief mesh network | Yes, no infrastructure available | Yes |
| Normal banking web app | No, one bank owns the system | No |
| Internal microservices | No, one organization controls all | No |
How is P2P different from client-server?
| Aspect | Client-Server | Peer-to-Peer |
|---|---|---|
| Roles | Clear: clients ask, servers answer | Every node is both |
| Central authority | Yes (the server) | None |
| Single point of failure | Server is a SPOF | No SPOF |
| Consistency | Straightforward (server is truth) | Hard (consensus needed) |
| Scalability | Server is the bottleneck | Each peer adds capacity |
| Complexity | Low | High |
| Best for | Most business applications | Decentralization requirements |
package com.bank.p2p;
// Client-Server: one authority, simple
public class ClientServerModel {
// Server is the single source of truth
// Client sends request, server processes, returns response
// Simple, reliable, easy to reason about
}
// Peer-to-Peer: no authority, complex
public class PeerToPeerModel {
// Every node holds a copy, agrees by consensus
// No single point of failure, but consistency is hard
// Security is harder (Sybil attacks, malicious peers)
}
What are the trade-offs and limitations?
P2P is far harder to get right than client-server. Consistency is difficult because there is no single authority, so you rely on consensus or accept eventual consistency. Security is harder because peers may be malicious: the Sybil attack, where one actor spins up many fake peers, can gain disproportionate influence. Operations and debugging are harder because there is no central place to observe the system.
package com.bank.p2p;
// Sybil attack: one malicious actor creates many fake peers
public class SybilAttackDemo {
public static void main(String[] args) {
int legitimatePeers = 10;
int fakePeersFromOneActor = 50;
int totalPeers = legitimatePeers + fakePeersFromOneActor;
double attackerInfluence = (double) fakePeersFromOneActor / totalPeers * 100;
System.out.println("Attacker controls " + String.format("%.1f", attackerInfluence)
+ "% of the network with fake peers");
System.out.println("Mitigation: proof-of-work, proof-of-stake, or identity verification");
}
}
Attacker controls 83.3% of the network with fake peers
Mitigation: proof-of-work, proof-of-stake, or identity verification
What about a banking consortium settlement scenario?
In an inter-bank settlement network where independent banks do not trust a single central operator, P2P makes sense. Each bank runs a peer holding a full ledger copy, and entries commit by majority consensus.
package com.bank.p2p;
import java.math.BigDecimal;
import java.util.List;
public class ConsortiumSettlement {
record SettlementEntry(String fromBank, String toBank, BigDecimal amount) {}
static boolean majorityApproves(List<Boolean> votes) {
long approvals = votes.stream().filter(v -> v).count();
return approvals > votes.size() / 2;
}
public static void main(String[] args) {
SettlementEntry entry = new SettlementEntry(
"National Bank of India", "HDFC", new BigDecimal("5000000.00"));
List<Boolean> peerVotes = List.of(true, true, true, false, true);
boolean committed = majorityApproves(peerVotes);
System.out.println("Settlement: " + entry);
System.out.println("Majority approved: " + committed);
}
}
Settlement: SettlementEntry[fromBank=National Bank of India, toBank=HDFC, amount=5000000.00]
Majority approved: true
What should a senior engineer know?
The mature judgment is to never choose P2P for convenience. The overwhelming majority of business systems are better served by client-server with a load balancer. You reach for P2P only when the absence of a central authority is itself a core requirement. Ordering of events without a central clock is a genuine distributed-systems problem, and consensus protocols like proof-of-work are slow and energy-hungry.
What are common interview follow-up questions?
- How does a DHT handle node churn (peers joining and leaving frequently)?
- What is the difference between structured and unstructured P2P networks?
- How does gossip protocol achieve eventual consistency across peers?
- Why is P2P not appropriate for a banking web application?
- How does blockchain prevent double-spending without a central authority?
Visual Overview
Client-Server Model Peer-to-Peer Model
──────────────────── ────────────────────
┌────────┐ ┌────────┐ ┌────────┐
│Client A│ │Client B│ │ Peer A │◄────►┌────────┐
└───┬────┘ └───┬────┘ └───┬────┘ │ Peer B │
│ │ │ └───┬────┘
▼ ▼ │ │
┌──────────────────┐ ▼ ▼
│ Server │ ┌────────┐ ┌────────┐
│ (single authority│ │ Peer C │◄────►│ Peer D │
│ + bottleneck) │ └────────┘ └────────┘
└──────────────────┘
Every peer talks to every peer.
Server is SPOF. No single point of failure.
Server is bottleneck. Each peer adds capacity.
Key Takeaway
Peer-to-Peer architecture makes every node both a client and a server, communicating directly with peers and requiring no central coordinator. The mechanisms that make it work are peer discovery, DHT-based routing for finding data, replication for surviving node departures, and consensus protocols for agreeing on shared state without a boss.
The deciding factor for choosing P2P is that decentralization must be a hard requirement. Blockchain exists precisely because no single party should control the ledger. BitTorrent uses it so there is no single server to overload or shut down. Mesh networks use it because there may be no central infrastructure at all. For a banking web application owned and operated by one bank, client-server with a load balancer is overwhelmingly simpler and better.
The trade-offs are real: consistency without a central authority requires slow consensus protocols, security is harder because of threats like Sybil attacks, and there is no central place to observe or debug the system. These costs are only worth paying when the absence of a central authority is the core requirement, not a preference.
Remember one sentence: choose P2P only when decentralization is a hard requirement, because for everything else, client-server is simpler and better.
---