Objective: In this session, we explore the bridge between high-level application code (like our Python Map-Reduce algorithms) and the underlying distributed infrastructure (OS, containers, and networks). This bridging layer is called Middleware.
In a distributed system, applications are spread across multiple machines, running potentially different operating systems, and written in different languages. Middleware is the software layer that logically resides above the operating systems and below the applications to provide a single-system image.
Instead of an application developer manually opening TCP sockets and worrying about endianness, lost packets, or finding the IP address of a target server, the middleware abstracts these infrastructure details away.
To integrate applications into infrastructure seamlessly, middleware employs several architectural tricks.
A wrapper (or adapter) is a piece of software that offers an interface to a component so that it looks exactly like another interface. This is crucial for integrating legacy applications into modern cloud-native systems without modifying the legacy source code.
Example: Imagine an old main-frame database that only accepts custom binary commands. You can build a REST-API Wrapper around it. Modern web applications send standard HTTP JSON requests to the Wrapper, which translates them into the binary format for the database.
Interceptors allow middleware to break the normal flow of execution (like an RPC call) and insert custom infrastructure logic (like logging, authentication, or load balancing), without the application knowing.
Example: When a Python microservice calls database.get_user(), an interceptor intercepts the call, checks a Redis cache first, and if found, returns the data immediately. The application logic is completely unaware of the caching infrastructure.
RPC is the oldest and most fundamental integration middleware. It makes a call to a function running on a remote server look exactly like a local function call. Under the hood, the middleware “stub” serializes the parameters, opens the socket, sends the network request, receives the response, and hands it back to the program.
Example: gRPC (built by Google) uses Protocol Buffers to serialize data efficiently and operates over HTTP/2, acting as a high-performance modern middleware.
Today, the “Infrastructure” heavily implies Container Orchestration (like Kubernetes). How does an application integrate into K8s?
localhost:8080, and the sidecar intercepts it, encrypts it, routes it to the correct remote server, and handles retries.These exercises build directly upon the Distributed Image Processor covered in Week 5 (Containerization) and the GitOps Pipeline in Week 6 (CI/CD).
Scenario: Users are currently accessing the Image Processor API directly across different microservice ports.
Task: Implement an API Gateway (using Nginx or a lightweight Python Flask app) acting as a Wrapper. The Gateway should listen on a single port (e.g., 80) and route /api/upload requests to the Upload Microservice and /api/status requests to the Status Microservice. Do this without modifying the Week 5 Python code.
Scenario: The Image Processor is public, and malicious bots are flooding the system with massive 4K images, exhausting our Kubernetes cluster resources. Task: Write an Interceptor middleware (in Python or injected via an Envoy sidecar proxy).
X-API-KEY.Scenario: Instead of relying on Kubernetes to load balance the internal worker pods, we want to construct a native RPC smart-client. Task: Modify the Week 5 image “Distributor” component to act as its own middleware.
Image-Worker containers.