Performance optimization techniques for microservices

In today’s fast-paced digital landscape, microservices have become the go-to architecture for building scalable and resilient applications. However, as these systems grow in complexity and scale, ensuring optimal performance becomes paramount since users’ are accustomed not to wait long for any content to appear in the page. In this section, we will explore the importance of performance optimization for microservices and delve into strategies that can be employed to fine-tune their efficiency.

Performance optimization is crucial for microservices as it directly impacts user experience and overall system reliability. By carefully analyzing and fine-tuning various aspects of a microservice architecture, organizations can achieve faster response times, reduced latency, improved scalability, optimal cloud resource utilization thus reduce billing.

One key aspect of performance optimization is designing cloud agnostic microservices. This approach allows organizations to leverage the benefits of different cloud providers while avoiding vendor lock-in. By designing services that are independent of any specific cloud platform, businesses can easily migrate or distribute their workload across multiple clouds to ensure high availability and fault tolerance. Docker, Kubernetes, Terraform plays a crucial role to achieve the cloud independance.

Problem statement:

There are many factors which effect performance of any given microservice and create bottleneck while doing the performance tuning. Idenfying that bottleneck to the first key factor towards an optimial system. In general pure-microservices are independent from each other with almost no data dependencies bu these are very rare scenarios in real-world deployments.

Let’s take an simple example of an e-Commerce application, where we have the following microservices:

  • User management
  • Product management
  • Inventory management
  • Cart management
  • Order management
  • Fulfillment management

Here the servies are dependent on each other in terms of data consistency,

e.g. Inventory management service can’t operate standalone without having information about products from the Product management service. Similarly Cart management can’t operate with inventory info so on and so forth.

So the communication between the microservices become very critical and expensive opertions in some cases, which could become a major bottleneck. In my profrssional experience, I found this most of the time as the blocker for the performance optimization.

Possible solutions:

Here are a couple of approaches which can be combined to enable top-notch performance for any given microservice.

  • gRPC can comes at rescue to optimize the communication time between the microservices due to it’s underlying HTTP/2 based binary channel based protocol, which makes the intra-service communication faster by 6-7 times in real-world applications. But gRPC commucation establishment can only speedup the data transfer but the processing time still plays a crucial role for each of the services.
  • Next consideration is use of event-driven microservices, where the partial data can be pre-processed and kept to the desired services based on events. Event-driven architectures allow services to communicate asynchronously through events, enabling loose coupling between components. By carefully designing event flows and utilizing efficient message brokers or event streaming platforms, organizations can ensure seamless communication between services while minimizing latency and maximizing throughput. e.g. When we are showing product details, we need to have info form inventory whethere sufficient product exists in the inventory. So in the event-driven architecture, we have to de-normalize the product count to the Product management service only on the event of “New Order”, “Return Order”, “Cancel Order”. So that way the Product management service doesn’t need to query for available product count to Inventory management service, thus increasing the performance.
  • Object level caching also plays a crucial part into the performance tuning, In our example use-case we can cache entire product object, which will be required for the UI pages, so that once a API request comes in it won’t run multiple queries to form the object rather directly return from cache so the time complexity of the call will tend to O(1).In this approach important factor is to do the cache invalidation, otheriwise cache will keep on serving old data, so event-driven approach can be used in order to build & destroy the respective object cache.

Throughout this section, we have explored real-world use cases and best practices for performance optimization in microservices architectures. By embracing these strategies, organizations can unlock the full potential of their microservice-based applications while delivering exceptional user experiences.

Future of gRPC

In the ever-evolving world of technology, gRPC has emerged as a powerful and efficient framework for building distributed systems. With its numerous advantages and unique features, gRPC is poised to shape the future of network communication.

One of the key advantages of gRPC is its speed and performance. By utilizing the HTTP/2 protocol and binary serialization and de-serialization, gRPC enables faster data transmission and reduced latency compared to traditional REST APIs which is text-based transfers. This makes it an ideal choice for applications that require real-time data exchange or high throughput.

Another benefit of gRPC is its language-agnostic nature and deterministic data-contract between server and client using PROTO files. It supports multiple programming languages, including popular ones like Go, NodeJS, Python, C++, Java, and more. This flexibility allows developers to choose their preferred language while still leveraging the power of gRPC for seamless communication between different services.

Furthermore, gRPC offers built-in support for bi-directional streaming and flow control mechanisms. This means that both clients and servers can send multiple requests or responses asynchronously without blocking each other. As a result, applications built with gRPC can handle large-scale data transfers efficiently and effectively.

However, like any technology, gRPC also has its pros and cons. While it excels in performance and scalability, some developers may find the learning curve steep due to its complex configuration requirements. Additionally, since it relies heavily on protocol buffers for message serialization, there may be compatibility issues when integrating with existing systems that use different data formats.

In my personal experience, the gRPC stands very tall in real-life service-to-service communication. Just to give an example, in a microservice-based environment initially, we have been using REST for internal data exchange. Due to the performance issues, I have decided to migrate to gRPC-based communication. After these migrations, our communications got fast by around 4-5 times in most of the use cases.

In conclusion, the future of gRPC looks promising as more developers recognize its benefits in terms of speed, flexibility, and scalability. By harnessing its power in building distributed systems across various programming languages, we can expect to see increased adoption of this framework in industries ranging from microservices architectures to IoT devices.

Introduction to QUIC & HTTP/3

QUIC is a new multiplexed transport built on top of UDP. The overall goal is to reduce latency and eliminate head-of-line blocking compared to that of TCP.  

The QUIC transport protocol has several features that are desirable in a transport for HTTP

  • Reliable, multiplexed transport over UDP
  • Encrypted
  • Stream multiplexing
  • Per-stream flow
  • Reduced Latency
  • Runs in user-space
  • Open sourced in Chromium

The Internet Engineering Task Force (IETF) has announced that the third official version of HyperText Transfer Protocol (HTTP/3) will not use TCP, instead, it will run over the QUIC protocol.

HTTP/3 inheriting from HTTP/2 is aimed at taking advantage of QUIC’s features.

HTTP/3 and QUIC in the protocol stack

The QUIC project started as an alternative to TCP+TLS+HTTP/2, with the goal of improving user experience, particularly page load times.

QUIC uses the concept of streams. When each resource is assigned an individual conceptual flow, the transport layer may know that when a packet is lost, subsequent packets can still be used if they contain data from another resource that was not in the lost packet.

A connection in QUIC is a single chain between two QUIC endpoints. The connection establishment combines version negotiation with the cryptographic and transport handshakes to reduce connection establishment latency.

Integration of QUIC and TLS.

With this method, every exchange will be encrypted and that will be the default behaviour.

However there are a few drawbacks of this protocol. Performance can be affected by attacks of the like Server Config Replay Attack. There is an interesting study about this by Robert Lychev and others here.

The modern web browsers seem to be ready for this transition since Chrome and Opera already have it implemented.

Stay tuned for more on QUIC! Keep Learning!

Effect of gRPC communication into multi-player gaming frameworks

From the time our industry has discovered networking by interconnecting systems, the hunt for a most advanced remote communication has begun.  gRPC is a modern inter-process communication technology that allows us to build distributed applications.

When gRPC was launched, it was immediately used by CoreOS, Netflix, Square, and Cockroach Labs and many more within a year of launch. Etcd by CoreOS, a distributed key/value store, uses gRPC for peer communication. Telecom companies like Cisco, Juniper, and Arista are using gRPC for streaming the telemetry data and network configuration from their networking devices.

gRPC’s secret recipe lies in the way serialisation is handled. Internally gRPC uses binary messaging using protocol buffers which runs on top of HTTP/2. So gRPC is a strongly typed, polyglot communication protocol that allows us to build request – response , style synchronous communication, as well as we can use duplex streaming.

gRPC with protocol buffers is used for communication between app and the server. gRPC is already built on top of HTTP/2. In gRPC the streaming is easy, say we want to build other realtime opponents in the game , gRPC makes life easy. It also supports types and validations and is faster compared to JSON as we have strict type checking.

Consider any Service, you generate a gRPC service from the service definition and you have clients talking to that service. It can be a mobile client or a desktop client talking to the service,  through the stubs and all the connection details are abstracted. Then, your one service could be talking to another service using a stub. In fact, it could happen that your second service talks to two other services, again through stubs.

gRPC communication

The beauty of this model is that communication between client and server, and between microservice’s, all happen through stubs that gRPC handles. 

Let’s quickly look at what are some of the advantages of gRPC :
1. Known for its functional design : Because gRPC used protoBufs as their messaging format , it favours a more functional approach to their APIs.

2. Slashes network latency to a great extent : gRPC builds on HTTP/2, which allows for faster and long-lived connections, reducing the time for setup/teardown common for individual HTTP/1.x requests.

3. Infra support : RPC often uses Kubernetes on Google Kubernetes Engine (GKE), which provides built-in proxy and load balancing support.

4. Bi-directional communication : gRPC takes advantage of HTTP/2’s bi-directional communication support, removing the need to separately support request/response.

5. Documentation: Since gRPC started within Google, documentation is extensive on the gRPC website. 

Why is gRPC a right fit for multiplayer gaming applications ? 

A multiplayer game project will require a modern real-time API. And the next bottleneck would be solving scalability issues. The main feature of bi-directional streaming in gRPC plays an important role in it being used to implement gaming applications. servers have a period of time where they accept requests, change game state, then broadcast all state changes at once to all clients.

In terms of gRPC integration, the client is similar to the server. It streams responses and converts them to the game engine can understand and also update the state of the game directly.

In a gaming application, the state of the game becomes very crucial at this point in time. The reduced latency that gRPC provides wins the battle to get away from the sticky states. Hence gaining advantage of a lower latency to enable quicker state management in the game.

Conclusion

REST has been around for 20+ years and gRPC is not a replacement for REST. gRPC APIs can offer huge performance improvements and reduced response time as compared to REST APIs, but which approach to choose comes down to what fits your particular use case.

How to implement bi-directional streaming using gRPC with Python (Client) – Part 2

Previously, we have demonstrated how to implement a bi-directional gRPC streaming server using python. Once the server implementation is ready we will implement the client.

In order to implement the client we will have to use the same proto file as the server as that acts as a data contract between server and client. Proto file as follows:

syntax = "proto3";
package SamplePackage;

message EntryCreateRequest {
    string title = 1;
    string code = 2;
    string description = 3;
}

message EntryResponse {
    string id = 1;
    string title = 2;
    string code = 3;
    string description = 4;
    int32 created_on = 6;
}

service SampleService {
    rpc createBulkEntries(stream EntryCreateRequest) returns (stream EntryResponse) {}
}

As proto files are not directly readable by python classes, we will convert them to python native class as follows:

python -m grpc_tools.protoc -I./proto --python_out=./proto/ --grpc_python_out=./proto/ ./proto/sample.proto

Let’s define the client to communicate to the gRPC streaming server. The code snippet is fully commented for the ease of understanding.

# import required libraries & proto defn.
import grpc
from proto import sample_pb2_grpc, sample_pb2

# initialize channel to gRPC server
channel = grpc.insecure_channel(target="localhost:50051")

# create service stub
stub = sample_pb2_grpc.SampleServiceStub(channel=channel)

# define request object generator which will yield 15 requests
def entry_request_iterator():
    for idx in range(1, 16):
        entry_request = sample_pb2.EntryCreateRequest(title=f"Test {idx}", code=f"T{idx}", description=f"Test {idx} description")
        yield entry_request

# iterate through response stream and print to console
for entry_response in stub.createBulkEntries(entry_request_iterator()):
    print(entry_response)

The above code snippet generates a series of request objects and stream it to the server and fetches the response stream from the server. Output as follows:

$ python client.py 
id: "fac2810d-133a-4285-ab62-a8f1cf47c4cb"
title: "Test 1"
code: "T1"
description: "Test 1 description"
created_on: 1628054962

...14 more

Hope the article series will help you to understand bi-directional gRPC streaming with python in step by step approach. We would love to help you to solve any of your issue related to gRPC, you may contact us on LinkedIn: https://www.linkedin.com/in/skallpaul/

How to implement bi-directional streaming using gRPC with Python (Server) – Part 1

In our previous tutorials, we have demonstrated how to implement bi-directional streaming using NodeJS. Since gRPC is just a protocol definition so it can be implemented in any possible language. So today we will demonstrate how to setup a bi-directional server using python & gRPC.

The codebase has been shared on GitHub for your convenience as follows: https://github.com/techunits/bidirectional-streaming-grpc-sample-python

In order to execute the gRPC streaming, we will need the following pip libraries as pre-requisites:

grpcio==1.39.0
grpcio-tools==1.39.0
protobuf==3.17.3
six==1.16.0
uuid==1.30

The very first step to setup any gRPC communication is to create a data contract in the form of a protocol buffer file. In our demonstration, we will use a simple contract that should be able to create some resource entries to the server in the stream and expect a response in the form of a stream.

Our proto file as follows:

syntax = "proto3";
package SamplePackage;

message EntryCreateRequest {
    string title = 1;
    string code = 2;
    string description = 3;
}

message EntryResponse {
    string id = 1;
    string title = 2;
    string code = 3;
    string description = 4;
    int32 created_on = 6;
}

service SampleService {
    rpc createBulkEntries(stream EntryCreateRequest) returns (stream EntryResponse) {}
}

Unlike NodeJS, python classes will not able to read the proto files directly, so we have to convert the proto into native python classes. The following command will generate 2 python class files sample_pb2_grpc.py & sample_pb2.py.

python -m grpc_tools.protoc -I./proto --python_out=./proto/ --grpc_python_out=./proto/ ./proto/sample.proto

gRPC Streaming Server:

Now we will define our server process which will read the above classes and servicer as follows:

# import required libraries & proto defn.
import grpc
from concurrent import futures
from proto import sample_pb2_grpc

# import servicer
from servicers import SampleServiceServicer

def serve():
    # initialize server with 4 workers
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))

    # attach servicer method to the server
    sample_pb2_grpc.add_SampleServiceServicer_to_server(SampleServiceServicer(), server)

    # start the server on the port 50051
    server.add_insecure_port("0.0.0.0:50051")
    server.start()
    print("Started gRPC server: 0.0.0.0:50051")

    # server loop to keep the process running
    server.wait_for_termination()


# invoke the server method
if __name__ == "__main__":
    serve()

The server process is having a dependency on the servicer method SampleServiceServicer defined as follows:

# import required libraries & proto defn.
from proto import sample_pb2_grpc, sample_pb2
import uuid
from datetime import datetime

class SampleServiceServicer(sample_pb2_grpc.SampleServiceServicer):
    ''' this servicer method will read the request from the iterator supplied
        by incoming stream and send back the response in a stream
    '''
    def createBulkEntries(self, request_iterator, context):
        entry_info = dict()
        for request in request_iterator:
            print(request)

            ##### save to database #####

            # simulate the response after saving to database
            entry_info = {
                "id": str(uuid.uuid4()),
                "title": request.title,
                "code": request.code,
                "description": request.description,
                "created_on": round(datetime.now().timestamp())
            }

            # stream the response back
            yield sample_pb2.EntryResponse(**entry_info)

Once we are done with the above steps, we should be able to start the server with the following command:

$ python serve.py
Started gRPC server: 0.0.0.0:50051

While building the server script we have using sConnector to test and debug our script visually even before creating any client. This helps a lot for a faster development cycle. Screenshot as follows:

gRPC Streaming Client:

In our next tutorial, we will explain how to implement a client to connect to the streaming server and send/receive the data as follows:

How to implement bi-directional streaming using gRPC with Python (Client) – Part 2

How to implement bi-directional streaming using gRPC with NodeJS (Client) – Part 2

In our previous tutorial, we have built a server to handle the bi-directional streams. Here we will build a bi-directional streaming client for the same with NodeJS.

The codebase has been shared on GitHub for your convenience as follows: https://github.com/techunits/bidirectional_grpc_sample_node

Prerequisite:

In order to implement the following tutorial, we need to have NodeJS 14+ installed on your system and the bi-directional gRPC streaming server is running successfully on the system.

Build the client:

As the server is running as a part of the prerequisite so we will assume that all the required dependencies have been installed on the system.

Load required packages:
const logger = require("elogger");
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const faker = require("faker");
const slugify = require("slugify");
Load “article.proto” to load the gRPC data contract:
const packageDefinition = protoLoader.loadSync("./article.proto", {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true
});
const articleManagerProto = grpc.loadPackageDefinition(packageDefinition).ArticleManagerPackage;
Initialize client & create stub based on the given proto:
const endpoint = "localhost:9111";
const serviceStub = new articleManagerProto.ArticleService(endpoint, grpc.credentials.createInsecure());
Create the service call:

The following call will initialize the RPC method which will be required to initialize the streaming as well as handle the response from the server.

const serviceCall = serviceStub.createBulkEntries();
Register events to fetch data:

This event handler will ensure that as soon as the server sends some data as a part of the successful processing of the stream, it will capture and proceed to the action accordingly. In our example, it will simply print the response back to the standard out console.

serviceCall.on("data", function(response) {
    logger.log(response);
});
Register event to handle error:

It might happen that the server is not able to process the data due to some validation failure or any other reason, so it will raise an exception. The following code snippet will handle the same and proceed accordingly. It will print to the standard error console in the given example.

serviceCall.on("error", function(error) {
    logger.error(error.code, " -> ", error.details);
});
Register event to handle call end:

We might need to process some additional business logic in a real-world scenario once the streaming is completed, so the following event handler will help to achieve the same.

serviceCall.on('end', function() {
    logger.debug(`Closed`);
});
Write to the stream:

The above code snippets will be used to handle different use cases once the server is sending back the response in terms of success or failure message. But in order to get to that stage we have to first write something to the stream as follows:

(async () => {
    const idxList = [1,2,3,4,5];
    for await (let i of idxList) {
        logger.debug(`Creating stream #${i}`);
        serviceCall.write({
            title: faker.lorem.sentence(),
            code: slugify(faker.lorem.words(2)),
            description: faker.lorem.paragraph()
        });
    }
})();

Here we are iterating the loop 5 times to send some set of data 5 times to the server via stream and the responses will be handler by the registered events.

New to gRPC?

If you just want to try out gRPC streaming capabilities, you may try our hosted gRPC mock interfaces at https://grpc.techunits.com/

How to implement bi-directional streaming using gRPC with NodeJS (Server) – Part 1

gRPC, introduced in August 2016 by Google, gradually booming in the market due to its unique capabilities like Binary data transfer over HTTP/2 protocol, uni-directional & bi-directional streaming. Many microservice architects are nowadays preferring gRPC on top of REST-based communication for better performance for service-2-service data transfer.

gRPC also provides a unique capability for bi-directional streaming which could be used for any use cases starting from Chat server, persistent service-to-service connection, and lots more.

Today we will learn how to implement bi-directional streaming using gRPC with NodeJS. The codebase has been shared on GitHub for your convenience as follows: https://github.com/techunits/bidirectional_grpc_sample_node

Prerequisite:

In order to implement the following tutorial, we need to have NodeJS 14+ installed on your system.

Use case:

We will build a bi-directional streaming server and client to create an article management application that will allow us to create articles in bulk using streaming.

Build Proto:

The first step to implement any gRPC service is to build the data contract in the form of a protocol buffer or proto file. Here is our proto file which will enable us to set up streaming using the “stream” keyword.

The RPC method “createBulkEntries” will allow developers to communicate with the gRPC service using bi-directional streaming as both request and response parameters are wrapped with the “stream” keyword.

Let’s also assume the filename is article.proto, which we will refer into our implementation

syntax = "proto3";
package ArticleManagerPackage;

message ArticleCreateRequest {
    string title = 1;
    string description = 2;
}

message ArticleResponse {
    string id = 1;
    string title = 2;
    string description = 3;
    string created_on = 4;
}

service ArticleService {
    rpc createBulkEntries(stream ArticleCreateRequest) returns (stream ArticleResponse) {}
}

Install required packages:

We will need the following packages as a part of the implementation which should be installed via npm command:

$ npm install @grpc/grpc-js        # core grpc library
$ npm install @grpc/proto-loader   # core grpc proto manager
$ npm install faker                # to generate fake data for testing
$ npm install elogger              # advanced logging library
$ npm install uuid                 # UUID generation library
$ npm install slugify              # convert some string to slug

Build the server:

After installation of all the above packages, we can start with our server script as follows:

Load required packages:

In the below code snippet, we are loading a custom node package named “handler.js” that will be required to manipulate the data.

// load required packages
const logger = require("elogger");
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const handlerObj = require("./handler");
Load “article.proto” to load the gRPC data contract:
const packageDefinition = protoLoader.loadSync("./article.proto", {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true
});
const articleManagerProto = grpc.loadPackageDefinition(packageDefinition).ArticleManagerPackage;
Initialize server and register handlers for the respective RPC methods:
const server = new grpc.Server();        
server.addService(articleManagerProto.ArticleService.service, {
    createBulkEntries: handlerObj.createBulkEntries
});
Bind & start the server process to port 9111:
const bindEndpoint = `0.0.0.0:9111`;
server.bindAsync(bindEndpoint, grpc.ServerCredentials.createInsecure(), (err, response) => {
    if(err) {
        logger.error(err);
    }
    else {
        server.start();
        logger.info(`Article manager gRPC service started on grpc://${bindEndpoint}`);
        
    }
});
Deep dive into “handler.js” file:

“handler.js” is responsible for handler the gRPC streaming calls and saving the data to the respective medium. In our example, we have mocked the save and returned the id and created_on timestamp to the response stream.

const logger = require("elogger");
const uuid = require("uuid");

exports.createBulkEntries = (call) => {
    logger.debug(`gRPC ${call.call.handler.path}`);

    // handle the data stream
    call.on("data", async (payload) => {
        console.log(payload);
        payload.id = uuid.v4();
        payload.created_on = new Date().getTime();
        call.write(payload);
    });

    // if server encouters event request to end the stream
    call.on("end", async (payload) => {
        call.end();
    });
};

The above snippet will start our gRPC server on port 9111. The output should be as follows:

$ node server.js
INFO: 	Mon Feb 01 2021 17:54:15 GMT+0530 (India Standard Time)	Article manager gRPC service started on grpc://0.0.0.0:9111

Pros & Cons of MongoDB 4.x vs DocumentDB 4.x

mongoDb or documentDB ? Which one ? Are you confused ? Let me sort that confusion for you.

Lets see what amazon has to say ?
Amazon claims that migrating from MongoDB to DocumentDB is “as easy as changing the database endpoint to the new Amazon DocumentDB cluster”

Ok, 

Now lets see what Mongo has to say ? 

One of the reviews I came across for MongoDB Atlas – “It is the fully-managed, global cloud database service for modern applications. Best-in-class automation and proven practices guarantee availability, scalability, and compliance with the most demanding data security and privacy standards. You can run Atlas on AWS, Google Cloud, and Azure or you could choose to run on all three at once. With multi-cloud clusters in Atlas, you can take advantage of unique tools and services native to all three major cloud providers without any added complexity to the data management experience.”

mongoDb

MongoDB is a document database with the scalability and flexibility that you want with the querying and indexing that you need. MongoDB’s document model is simple for developers to learn and use, while still providing all the capabilities needed to meet the most complex requirements at any scale. They provide drivers for 10+ languages, and the community has built dozens more.

The following platforms are available from mongoDB :

Amazon documentDb

The company describes documentDb as “fast, scalable, highly available and fully managed“. With Amazon’s documentDb 4.x launch, you can now use atomic, consistent, isolated, and durable (ACID) transactions, open a change stream cursor for a database or cluster, and much more.

Points of comparison : 

Amazon’s documentDb claims its fully managed, meaning offer database as a service, but mongoDb also has a platform mongoDb Atlas which is also providing database as a service . Ok, both are competent enough. Let’s get a little more in depth to first understand what are some unique features we will need to use for our project and let’s also see how each one scores on this.

Pricing :

MongoDB Atlas offers a free tier for developers to get the database setup up and running without having to enter credit card details. This is definitely encouraging for developers since price is a factor which one might not want to invest in trying out and experimenting to check if this product fits the use case better.

pricing

Let’s now see what is amazon document DB’s pricing, 

The cheapest DocumentDB instance starts at a relatively sharp price before adding I/O costs.

IO costs

Cloud compatibility: 

We are living in the era of cloud adoption , where businesses are using a multi-cloud approach. MongoDB atlas‘s data distribution and mobility across AWS, Azure, and Google Cloud is noteworthy.

cloud compatibility


Whereas with Amazon’s DocumentDB, we might need to end up with a single cloud provider may be a disadvantage if you are looking for a multi-cloud approach in your company’s setup. If you are sure you will stick to one cloud itself, then this might not be an intensive point of consideration for you to choose in terms of portability – choice of cloud.

cloud compatibility

Features : 

AWS claims DocumentDb as having “MongoDB compatibility” , but there are some of the features that it doesn’t have when compared to MongoDB . DocumentDB is not based on the MongoDB server. Rather it emulates the MongoDB API, and runs on top of Amazon’s Aurora backend platform. This creates significant architectural constraints, functionality limitations, and broken compatibility.

compatibility


DocumentDB claims to support the MongoDB 4.0 API, which implies that it is at parity with MongoDB v4.0, released back in June 2018. In actual fact the DocumentDB 4.0 feature set most closely resembles early MongoDB 3.0 and 3.2, released in 2015, and compatibility testing reveals it fails 63% of the MongoDB API correctness tests. Applications written for MongoDB will need to be re-written to work with Amazon DocumentDB.

Replication : 

Amazon document DB provides Single primary constrained to a single region, with up to 15 replicas, whereas MongoDB – Global clusters, with up to 50 replicas per shard across multiple regions

Sharding : 

Amazon document DB has No sharding, single primary only. Largest instance supports 30,000 concurrent connections. The MongoDB Atlas instance supports 128,000 concurrent connections. Full sharding support.

Let’s understand some more Functional Differences Between Amazon DocumentDB 4.0 and MongoDB 4.0.

“For example, Amazon DocumentDB 4.0 does not currently support the type conversion operators or the string operators that were introduced in MongoDB 4.0 “

Below are functional differences between Amazon DocumentDB 4.0 and MongoDB 4.0.

  • Lookup with empty key in path: When a collection contains a document with empty key inside the array (e.g. {“x” : [ { “” : 10 }, { “b” : 20 } ]}), and when the key used in the query ends in an empty string (e.g. x.), then Amazon DocumentDB will return that document since it traverses all the documents in the array whereas MongoDB will not return that document.
  • $setOnInsert along with $ in the path: The field operator $setOnInsert will not work in combination with $ in the path in Amazon DocumentDB, which is also consistent with MongoDB 4.0.

Conclusion 

If you consider to go with documentDB , you will need to ensure your project doesn’t end up using some of the features of MongoDB which amazon doesn’t support as mentioned above. And in case your organisation is working on a single cloud approach , then you can consider the document DB , but do remember that documentDB is not a complete replacement of mongoDB but it’s just a partial replacement.

Introduction to HTTP/2

Http/2 is a major revision of HTTP, which improves the performance of the web. It uses primary protocol and multiplexing. 

What are the primary goals of Http/2 ?

  1. Reduce latency.
  2. Minimise protocol overhead. 
  3. Adds support for request prioritisation and server push.

Let me throw a quick insight on how the HTTP1.1 works, before we jump into the working of HTTP/2.  

HTTP1.1 is built on HTTP protocol which is a simple request / response system. Here the client and server establish a TCP connection, which is a stateful communication. It allows us to send one request at a time and that channel is busy fetching the response. This socket is purely under-utilised. Once the request is made, you cannot send any other request until you get back the response. Because of this underutilisation , it is obviously slow.

HTTP/1.1

OK HTTP/1.1 had performance limitations , ok ! What came next ? it’s SPDY, let’s see how exactly it was SPDY?

This single TCP connection allowing only one request/response at a time is very expensive. There are resource descriptors held on the server and there is also a lot of memory wastage. We can do so much with a single TCP connection, this is when google realised it and developed SPDY, as an experimental protocol. It was announced in the mid-2009, whose primary goal was to reduce latency and address the performance limitations of HTTP/1.1.

What do you think HTTP Working group (HTTP-WG) did next ?

After observing the SPDY trend, they dissected SPDY. On the basis of their learning from SPDY, they improved and built out an official standard – HTTP/2.

Interesting history isn’t it. Com’on , let’s move on to the working of HTTP/2 ?

HTTP/2 works very similarly from the client perspective. We can still make GET requests, POST requests etc, and also we are still using a single TCP connection. But here we ended up using this single TCP connection, very efficiently. The client in this scenario , shoves as many requests at the same time into this pipe .This is called multiplexing. 

HTTP/2

Alright!, you may ask next how does the server know , which request is for what? And also how does the client know when it gets a response, that this response was gotten for which request ?

Let me dive into this, how is this confusion resolved ? This is where the stream ID tag is used , this is very internal that we do not see as clients of HTTP2. Every time a request is made with HTTP/2, every request is tagged with a stream ID. When the server returns back the response, every response gets tagged back with its respective stream ID. This is how the client will understand which response belongs to which request. This is multiplexing. Here since every request has an internal ID, here we can compress headers and the data.

Whoa!, That clears the confusion. 

What else has the HTTP/2 to offer ?

HTTP/2 allows the server to push multiple responses for a single request. But we must ensure our Client is configured for this setup using HTTP2. This at times can be an advantage or disadvantage, solely depending on what’s the use case.

Pros of HTTP2 

Yes , if you have read so far, you must obviously know , Its Multiplexing over a single TCP connection. You can make huge set of requests can be GET, POST, PUT list goes on.

Next, is compressing, This also we have understood why!, Let me re-iterate it , here we can compress the headers and data , because each request has an internal stream ID tag attached to it.

Moving on to the next amazing feature which is server push, This is where your client makes one request , but gets multiple responses (This can be disadvantageous as well , i discuss about this in the later section of this article).

It is always Secure, now the consensus of the HTTP2 is always secure, we cannot do a HTTP2 on a port 80, it has to be 443. Hence, it’s secure all the time. It’s a design decision, and it does have a benefit , so by design itself it is secure.

Protocol negotiation during TLS , Well How will your client know? That Server supports HTTP/2 ? During TLS, the server negotiates with the client in the same handshake and says I support this, do you also support it? While they are doing their encryption.

Cons of HTTP2 

When configured incorrectly, server push can be abused. Basically, here the server will end up pushing multiple resources to the client, irrespective of whether the client needs it or not. This will obviously cause an extra unnecessary bandwidth to be consumed. If this is done again and again, this will saturate the network.

Another one would be slower in the mixed mode . (Hey! What’s mixed mode ? – backend is HTTP/1.1 but the load balancer is HTTP/2 or vice versa). 

HTTP/2 – The trump card of gRPC

gRPC uses HTTP/2 as its transfer protocol. It inherits some great features of HTTP/2. Such as, 

  1. Binary framing 
  2. HTTP/2 compresses the headers using HPACK, which will reduce overhead cost and also improves performance.
  3. Multiplexing – as discussed already, the client and server can send multiple requests in parallel over a single TCP connection.
  4. Server Push.